My linux from scratch.

本博客介绍了作者使用空闲时间开始的Linux From Scratch (LFS) 项目经历。通过这个过程,作者不仅深入了解了Linux的工作原理,还尝试创建了一个小型的个人Linux操作系统。这是一次既兴奋又有趣的体验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

I started my project about lfs(linux from scratch) three days ago. 

Why did I want to play it using my spare time? The reason was that it would be very helpful for me to understand how linux works and make a new small linux os of myself. That was very exciting and interesting. And you can do it too.

(continue...)

/home/ty/code_data/g99/system/vendor/alps/kernel-5.10/drivers/misc/mediatek/flashlight/globalmem.c:173:8: error: incompatible function pointer types initializing 'ssize_t (*)(struct device *, struct device_attribute *, char *)' (aka 'long (*)(struct device *, struct device_attribute *, char *)') with an expression of type 'ssize_t (struct device *, struct device_attribute *, char *, size_t)' (aka 'long (struct device *, struct device_attribute *, char *, unsigned long)') [-Werror,-Wincompatible-function-pointer-types] static DEVICE_ATTR_RW(debugger); ^~~~~~~~~~~~~~~~~~~~~~~~ /home/ty/code_data/g99/system/vendor/alps/kernel-5.10/include/linux/device.h:132:45: note: expanded from macro 'DEVICE_ATTR_RW' struct device_attribute dev_attr_##_name = __ATTR_RW(_name) ^~~~~~~~~~~~~~~~ /home/ty/code_data/g99/system/vendor/alps/kernel-5.10/include/linux/sysfs.h:138:46: note: expanded from macro '__ATTR_RW' #define __ATTR_RW(_name) __ATTR(_name, 0644, _name##_show, _name##_store) ^~~~~~~~~~~~ <scratch space>:15:1: note: expanded from here debugger_show ^~~~~~~~~~~~~ /home/ty/code_data/g99/system/vendor/alps/kernel-5.10/include/linux/sysfs.h:104:10: note: expanded from macro '__ATTR' .show = _show, \ ^~~~~ /home/ty/code_data/g99/system/vendor/alps/kernel-5.10/drivers/misc/mediatek/flashlight/globalmem.c:173:8: error: incompatible function pointer types initializing 'ssize_t (*)(struct device *, struct device_attribute *, const char *, size_t)' (aka 'long (*)(struct device *, struct device_attribute *, const char *, unsigned long)') with an expression of type 'ssize_t (struct device *, struct device_attribute *, char *, size_t)' (aka 'long (struct device *, struct device_attribute *, char *, unsigned long)') [-Werror,-Wincompatible-function-pointer-types] static DEVICE_ATTR_RW(debugger); ^~
最新发布
08-07
<think>我们正在解决Linux内核模块编译错误:函数指针类型不兼容,具体是关于DEVICE_ATTR_RW宏的使用。 错误信息通常类似于:赋值时类型不兼容,可能是由于函数签名不匹配。 在Linux内核中,`DEVICE_ATTR_RW`宏用于定义一个设备属性(sysfs接口),该属性可读可写。它需要两个函数:`show`函数(用于读取)和`store`函数(用于写入)。在较新的内核版本中,这些函数的原型有严格的要求。 在Linux 5.10内核中,`show`和`store`函数的原型应该是: - `show`函数:`ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf);` - `store`函数:`ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);` 但是,在旧版本内核中,`store`函数可能没有`const`修饰符,或者参数顺序不同。另外,注意函数返回类型为`ssize_t`(有符号整数)。 常见的错误原因: 1. 函数签名不匹配:例如,`store`函数的第一个参数不是`struct device *`,而是`struct device_attribute *`,或者缺少`const`修饰符等。 2. 函数返回类型错误:例如,返回`int`而不是`ssize_t`。 3. 函数参数数量或顺序错误。 因此,我们需要检查使用`DEVICE_ATTR_RW`定义的属性对应的`show`和`store`函数的声明是否与内核要求的完全一致。 示例代码: 假设我们有一个设备属性`myattr`,我们定义了两个函数:`myattr_show`和`myattr_store`。 正确写法: ```c static ssize_t myattr_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t myattr_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); DEVICE_ATTR_RW(myattr); ``` 如果函数签名不匹配,编译器会报错,因为`DEVICE_ATTR_RW`宏内部会生成一个`struct device_attribute`结构体,该结构体期望的函数指针类型与提供的函数类型不一致。 解决方案: 1. 检查并修正函数签名,确保与内核要求一致。 2. 如果之前的内核版本允许不同的函数签名(例如,使用`struct kobject *`代替`struct device *`),那么需要根据内核版本调整。 注意:在Linux内核5.10中,`struct device_attribute`的定义如下(在`include/linux/device.h`中): ```c struct device_attribute { struct attribute attr; ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf); ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); }; ``` 因此,函数指针必须匹配上述类型。 如果我们在驱动中定义的函数使用了不同的签名(例如,使用了`struct device_driver *`或`struct kobject *`),则需要进行类型转换或者修改函数签名。但是,通常建议修改函数签名以匹配标准。 如果函数中确实需要访问其他结构(比如在`show`函数中需要访问驱动私有数据),可以通过`dev_get_drvdata(dev)`获取设备私有数据,这样就不需要改变函数签名。 示例修正: 错误示例: ```c static ssize_t myattr_store(struct device_driver *drv, const char *buf, size_t count) { // ... 错误:参数不匹配 } ``` 修正为: ```c static ssize_t myattr_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { // 使用dev来获取驱动私有数据等 struct my_driver_data *data = dev_get_drvdata(dev); // ... 处理buf return count; } ``` 另外,注意`show`函数必须返回实际写入缓冲区的字节数(或错误码),`store`函数返回实际处理的字节数(或错误码)。 如果问题仍然存在,请检查是否在定义属性时使用了正确的宏,以及宏的参数是否正确(属性名称是否一致)。 最后,重新编译模块。 如果还有问题,请提供具体的错误信息,以便进一步分析。 注意:内核版本升级可能导致API变化,因此建议查阅对应版本的内核文档或头文件。 参考:[^1] Linux内核源码(5.10)中`include/linux/device.h`关于`struct device_attribute`的定义。 §§相关问题§§ 1. 如何在内核模块中正确使用`DEVICE_ATTR`宏创建sysfs属性文件? 2.Linux内核驱动中,如何通过sysfs与用户空间进行数据交互? 3. 当内核API发生变化时,如何保持驱动代码的兼容性?</think>### Linux内核模块编译错误:DEVICE_ATTR_RW函数指针类型不兼容 在Linux 5.10内核中编译驱动时遇到`DEVICE_ATTR_RW`相关的函数指针类型不兼容错误,通常是由于函数签名与内核API要求不匹配导致的。以下是逐步解决方案: #### 1. **检查函数签名** Linux 5.10要求`show()`和`store()`函数的签名必须严格匹配: ```c // 正确签名 ssize_t show(struct device *dev, struct device_attribute *attr, char *buf); ssize_t store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); ``` **常见错误**: - 参数类型错误(如用`struct kobject*`替代`struct device*`) - 缺少`const`修饰符 - 参数顺序错误 #### 2. **修复函数实现** 修改函数定义以完全匹配内核要求: ```c static ssize_t myattr_show(struct device *dev, struct device_attribute *attr, char *buf) // 必须返回ssize_t { return sprintf(buf, "%d\n", value); } static ssize_t myattr_store(struct device *dev, struct device_attribute *attr, const char *buf, // 必须有const size_t count) // 必须有size_t { kstrtoint(buf, 10, &value); return count; } ``` #### 3. **正确使用宏** `DEVICE_ATTR_RW`会自动生成属性结构体,只需传递属性名: ```c static DEVICE_ATTR_RW(myattr); // 正确用法 ``` **错误用法**: ```c static DEVICE_ATTR_RW(myattr_show, myattr_store); // 错误!宏只需属性名 ``` #### 4. **类型强转问题** 如果必须保留非标准签名,使用强制转换(不推荐): ```c static ssize_t custom_store(struct kobject *kobj, ...) { ... } // 强制转换(可能引发安全隐患) static struct device_attribute dev_attr = __ATTR_RW(myattr, (ssize_t (*)(struct device *, ...))custom_store); ``` #### 5. **内核版本兼容处理** 若需支持多版本内核,使用`#ifdef`检查版本: ```c #include <linux/version.h> #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) // 5.10+标准签名 #else // 旧版内核签名 #endif ``` #### 6. **编译选项验证** 确保开启严格类型检查: ```makefile # Makefile中必须包含 ccflags-y := -Werror -Wimplicit-function-declaration ``` #### 错误示例分析 原始错误信息通常类似: ```bash error: incompatible function pointer types: expected ssize_t (*)(struct device *, struct device_attribute *, char *) got int (*)(struct kobject *, struct kobj_attribute *, char *) ``` 这表明: 1. 返回类型应为`ssize_t`而非`int` 2. 第一个参数应为`struct device*`而非`struct kobject*` > **根本原因**:从内核5.0开始,`struct device_attribute`的函数签名要求更严格,旧版宽松的类型检查已被移除[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值