linux源码中的uapi的来源include recursion
2017-06-14 00:13
176 查看
转自http://tinylab.org/linux-kernel-uapi/
问题描述
从3.5开始,Linux Kernel 里多了一个 uapi 文件夹,里面放了很多 Linux Kernel 各个模块的头文件。如果是第一次碰到,可能会对这个不是很了解。
问题分析
Linux Kernel 中新增的这些 uapi 头文件,其实都是来自于各个模块原先的头文件,最先是由 David Howells 提出来的。uapi 只是把内核用到的头文件和用户态用到的头文件分开。
解决方案
在 3.5 之前,Linux Kernel 的头文件一般是这样的:
/* Header comments (copyright, etc.) */
#ifndef _XXXXXX_H
#define _XXXXXX_H
[User-space definitions]
#ifdef __KERNEL__
[Kernel-space definitions]
#endif /* __KERNEL__ */
[User-space definitions]
#endif
而在 3.5 之后,这样一个头文件就会被分为两个:
.filename.h
/* Header comments (copyright, etc.) */
#ifndef XXXX_H
#define XXXX_H
#include <include/uapi/path/to/header.h>
[Kernel-space definitions]
#endif
./uapi/filename.h
/* Header comments (copyright, etc.) */
#ifndef _UAPI_XXXX_H
#define _UAPI_XXXX_H
[User-space definitions]
#endif
这样做有什么好处呢?一个是解决 Linux Kernel 里的交叉引用,另外一个就是方便用户态的开发者,可以简单的查看 uapi 里的代码变化来确定 Linux Kernel 是否改变了系统 API。
我把问题脱离于项目简单描述一下:我写了一个函数
head1.h
head2.h
那么,现在另有两个源文件
source1.cpp
source2.cpp
整个项目会分别编译这两个源文件,编译完之后会报错,大致意思是 ClassA 和 VAR_MACRO 没有定义,那么问题就比较奇怪了,每个头文件都分别引用了另一个头文件,为什么会出现未定义呢?
我们都知道 C/C++ 中头文件开始习惯使用
回到问题本身,我在微博上贴出了这个问题,有人说在
对于
那么也展开它,这时
看到没,这地方 func 函数之前有 ClassA 类型的定义,根本没必要像有些人说的那样加上
我们再展开
这时问题就很清楚了,func 函数声明之前并没有发现 ClassA 类型定义,该定义在函数声明的后面,这时候如果能在
再回到
问题描述
从3.5开始,Linux Kernel 里多了一个 uapi 文件夹,里面放了很多 Linux Kernel 各个模块的头文件。如果是第一次碰到,可能会对这个不是很了解。
问题分析
Linux Kernel 中新增的这些 uapi 头文件,其实都是来自于各个模块原先的头文件,最先是由 David Howells 提出来的。uapi 只是把内核用到的头文件和用户态用到的头文件分开。
解决方案
在 3.5 之前,Linux Kernel 的头文件一般是这样的:
/* Header comments (copyright, etc.) */
#ifndef _XXXXXX_H
#define _XXXXXX_H
[User-space definitions]
#ifdef __KERNEL__
[Kernel-space definitions]
#endif /* __KERNEL__ */
[User-space definitions]
#endif
而在 3.5 之后,这样一个头文件就会被分为两个:
.filename.h
/* Header comments (copyright, etc.) */
#ifndef XXXX_H
#define XXXX_H
#include <include/uapi/path/to/header.h>
[Kernel-space definitions]
#endif
./uapi/filename.h
/* Header comments (copyright, etc.) */
#ifndef _UAPI_XXXX_H
#define _UAPI_XXXX_H
[User-space definitions]
#endif
这样做有什么好处呢?一个是解决 Linux Kernel 里的交叉引用,另外一个就是方便用户态的开发者,可以简单的查看 uapi 里的代码变化来确定 Linux Kernel 是否改变了系统 API。
我把问题脱离于项目简单描述一下:我写了一个函数
bool func(ClassA* CA)需要加到项目中,我就把这个函数的声明放到
head1.h中,函数参数类型 ClassA 定义在另一个头文件
head2.h中,因此我需要在
head1.h中包含
head2.h;而
head2.h中之前又包含了
head1.h,这样就构成了一种头文件相互包含的场景。再加上一些其它的声明与定义,就构成了这样的一个文件结构:
head1.h
#ifndef __HEAD_1_H__ #define __HEAD_1_H__ #include "head2.h" #define VAR_MACRO 1 //define a macro, which used in head2.h bool func(ClassA* CA); //ClassA is defined in head2.h #endif
head2.h
#ifndef __HEAD_2_H__ #define __HEAD_2_H__ #include "head1.h" class ClassA{ int mVar; void setMem(){ mVar = VAR_MACRO }; //macro VAR_MACRO is defined in head1.h ... //other members and functions }; #endif
那么,现在另有两个源文件
source1.cpp
#include "head1.h" //... some source code
source2.cpp
#include "head2.h" //... some source code
整个项目会分别编译这两个源文件,编译完之后会报错,大致意思是 ClassA 和 VAR_MACRO 没有定义,那么问题就比较奇怪了,每个头文件都分别引用了另一个头文件,为什么会出现未定义呢?
问题分析
我们都知道 C/C++ 中头文件开始习惯使用 #ifndef ... #define ... #endif这样的一组预处理标识符来防止重复包含,例如上面的问题中我也使用了,如果不使用的话,两个头文件相互包含,就出现递归包含。这个很好理解就不多叙。
回到问题本身,我在微博上贴出了这个问题,有人说在
head1.h的函数前加上
ClassA A;的前置声明,至于为什么要加,估计很多人都没理解...
对于
source1.cpp,它包含了头文件
head1.h,那么在编译之前,在
source1.cpp中展开
head1.h,而
head1.h又包含了
head2.h,
那么也展开它,这时
source1.cpp就变成类似下面这样:
class ClassA{ int mVar; void setMem(){ mVar = VAR_MACRO }; //macro VAR_MACRO is defined in head1.h ... //other members and functions }; #define VAR_MACRO 1 //define a macro, which used in head2.h bool func(ClassA* CA); //ClassA is defined in head2.h //... source1.cpp source code
看到没,这地方 func 函数之前有 ClassA 类型的定义,根本没必要像有些人说的那样加上
ClassA CA;这样的前置声明。
我们再展开
source2.cpp看看:
#define VAR_MACRO 1 //define a macro, which used in head2.h bool func(ClassA* CA); //ClassA is defined in head2.h class ClassA{ int mVar; void setMem(){ mVar = VAR_MACRO }; //macro VAR_MACRO is defined in head1.h ... //other members and functions }; //... source2.cpp source code
这时问题就很清楚了,func 函数声明之前并没有发现 ClassA 类型定义,该定义在函数声明的后面,这时候如果能在
head1.h的函数声明之前加上
ClassA CA;的前置声明,就不会在编译的时候报找不到 ClassA 的定义的错误了。
再回到
source1.cpp展开的源码看看,是不是一下子明白了为什么报找不到 VAR_MACRO 的定义的错误了?修改方法也简单,把宏定义拉到
#include "head2.h"语句之前就 OK 了。
相关文章推荐
- OpenGL教程Nehe版(中文版+VC++源码)来源:Linux社区 作者:Linux
- Linux最新稳定内核2.4.x的网络接口源码的结构(一)
- Linux TCP/IP 协议栈源码分析(一)
- linux 内核源码结构
- LINUX 串口通讯源码
- Linux下阅读源码的好工具Kscope
- Linux内核2.6.14源码分析-双向循环链表代码分析(巨详细)
- Linux下字符型驱动程序完整源码入门示例
- Linux操作系统下如何编译安装源码包软件
- Linux应用程序的源码
- Linux内核2.4.x的网络接口源码的结构
- 如何阅读Linux源码
- linux 核心源码下载
- Linux下Libpcap源码分析和包过滤机制
- 收藏的一个linux下proxy实现的源码
- linux内核源码目录结构
- 家电业与开放源码阵营 对 Linux 开发分歧严重
- Linux网络接口的源码结构
- 源码的来源
- Linux 学习数据专题【管理、编程、源码分析】——Linux相关图书选购指南