新手,刚开始学linux下的驱动开发。前期看了本robert love《linux kernel development》,很多问题都没有深究。

在学习ldd3时,遇到的第一个问题是编译自己的内核,这个花费了一些工夫后终于搞定。

遇到的第二个问题就是这本书的第二章《构造和运行模块》中的Makefile的问题。

现在初步有了自己的理解,记录下来,供以后温故知新,也方便有我相同疑问的朋友参考。

如有错误之处,请大家指出,共同进步,谢谢。

 

我的开发环境是fedora 13OS,自己下了2.6.35的Kernel源代码树,从新编译,安装了系统。

具体GNU工具的版本就不说了,都是fedora 13自带的。看懂本文,可能需要有一点点makefile基础,我也不是很精通:)

 

首先,将Makefile粘帖出来:

 

 

首先解释下makefile中的几点:

$(MAKE)--是指make。在内核树的主makefile中,可以找到这个变量。

$(KERNELRELEASE)--KERNELRELEASE也是一个变量,可以在内核树的主makefile中找到。

$(MAKE) -C $(KERNELDIR)  --KERNELDIR在前面定义了,是指内核树的根目录。-C选项的作用是将当前的工作目录转移到你所指定的目录,我们这里指定为内核树的根目录,/lib/modules/$(shell uname -r)/build指向的就是内核树的根目录,build是个软链接。 uname -r是shell命令,显示当前的内核版本号,我的是2.6.35.

M=$(PWD)--M=选项让该makefile在构造modules目标之前,返回到当前目录。一般这个makefile和驱动模块的代码在一起,就是返回到驱动模块代码所在的目录。“M=” 选项的作用是,当用户需要以某个内核为基础编译一个外部模块的话,需要在make modules 命令中加入“M=dir” ,程序会自动到你所指定的dir 目录中查找模块源码,将其编译,生成KO 文件。

modules--目标指向obj-m变量中设定的模块。如果有多个源文件,obj-m := hello.o需要改一下,改如下:

 

 

 

接下来重点描述下我对makefile流程的理解,其实这个才是我最花工夫的地方。

 

首先要搞明白一点,我的驱动代码和这个makefile并不一定在内核树根目录下,实际上,我是在/home/xxx/src/下的。在shell里,也是在这个目录下执行的make命令。

 

执行make

首先检查KERNERRELEASE变量,发现没有定义,所以,走else,接下来定义了两个变量KERNELDIR和PWD。

然后会走进default.

 

注意: 此时会因为 -C $(KERNELDIR)进入内核树根目录,执行内核树根目录下的主makefile,这个makefile中有我们前面提到的两个变量的声明,KERNELRELEASE和MAKE。内核树里的主makefile会根据M=选项,执行M=选项指向的目录处的驱动代码的makefile。其实这是第二次读这个makefile了。

然后根据M=选项指向的模块目录,再执行驱动代码位置的makefile,也就是前面粘帖下来的makefile。你可能会有疑问,那这个makefile不是被读了两遍了吗?是的。就是读了两遍,但是两遍结果并不相同。因为第二遍的时候,KERNELRELEASE 和MAKE变量有了定义。于是走了ifndef分支,obj-m有了定义,此时才真正的编译内核模块。编译完模块,会离开内核树的目录,回到M=选项指向的目录。

 

一个标准的模块编译过程,makefile是要被读两次的。

 

采用这种makefile的好处是,既可以将驱动模块放在内核树里面编译(/usr/src/linux/driver/),也可以将驱动模块放在内核树外面,都可以编译通过.

 

使用命令: make -n可以查看详细的执行过程.

 

参考:

1.LDD3

2.http://www.embedu.org/Column/Column310.htm

 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐