首先看书上第29页的Makefile文件:
当使用指令make -C ~/linux-2.6.10 M=`pwd` modules编译时过程如下图:
我们解释下这个指令中各个参数的含义:
1. -C ~/linux-2.6.10,这个参数在“man make”中有解释,就是Change Directory的意思,make命令看到这个参数,就会先转到指定的目录,然后再去这个指定的目录中找Makefile文件开始执行,这里就是linux源码根目录中的Makefile文件了。
2. M=`pwd`,这个参数不是make命令的Option,在“man make”中是找不到的,这个参数会直接传进Makefile文件中,我们可以在linux源码根目录的Makefile文件中找到相关说明,意思是这个参数指定了要编译的外部模块的目录,有了这个参数,linux编译系统就不会编译linux源码中的代码了,而是直接编译外部模块的代码。
3. modules,这个参数也是直接传给linux根目录中的Makefile文件,意思是编译模块。不加M参数的话,就是编译linux源码中的模块,加M参数的话,就是编译外部模块。这个参数的含义在linux源码的根目录中执行“make help”可以看到说明。
当直接用指令make不加参数编译时过程如下图:
可以看到编译过程增加了一句指令,这句指令就是上边我们用make加参数编译时的那句指令。我们现在来分析make不加参数编译时我们的Makefile文件执行的顺序。
1. 首先make不加参数会直接找到当前目录中的Makefile文件,按顺序执行第2行,看有没有$(KERNELRELEASE)这个变量,这时我们还没有这个变量。
2. 执行第6行、第7行定义两个变量,分别作为-C和M的参数值。
3. 执行第10行,就是我们make加参数编译时的那句指令,这句指令首先改变目录到linux源码根目录中,然后找到linux源码根目录中的Makefile文件,并执行这个Makefile文件。Makefile文件会定义$(KERNELRELEASE)变量,然后看到modules就知道了是要编译模块,根据M参数找到外部模块中的Makefile文件,并执行这个Makefile文件。
4. 再次执行到我们Makefile文件的第2行,看有没有$(KERNELRELEASE)这个变量,这个时候有了。
5. 执行到第3行,根据这一行找到hello.c去编译出hello.o。
6. 然后返回到linux源码中的Makefile文件,执行一些其它的操作,比如把hello.o变成hello.ko。
书上也说我们的Makefile文件是执行了两次的,第一次是直接make指令找当前目录中的Makefile文件,第二次是linux源码根目录中的Makefile文件根据M参数找外部模块的Makefile文件。
另外注意,其实/lib/modules/$(shell uname -r)/build是一个软链接,指向了真正的linux源码的根目录。