简单实例,makefile自动依赖(二)

参考自:http://blog.chinaunix.net/uid-20316928-id-3395996.html

《跟我一起学makedfile》 《GUN makefile……》


上一篇中发现修改了头文件,但是执行make后不会自动重新编译,

研究发现是因为没有头文件的依赖,最傻的加依赖方法就是在编译的时候头文件一块加进去。

那样子的话总不能每增加一个头文件都要去改一次makefile,上网一搜发现可以自动生成依赖文件,所以有了这篇文章。


有错的地方欢迎指出。互相交流,共同进步。



首先上编译前的源码树:



顶层makefile:


主要讲一下makefile中使用的几个函数:

第7行:wildcard

返回的值是include目录下面的所有的.h文件

第11行:join

$(join aaa bbb , 111 222 333)返回值是“aaa111 bbb222 333”

第12行:patsubst:

$(patsubst %.c,%.o,x.c.c bar.c)
把字串“x.c.c bar.c”符合模式[%.c]的单词替换成[%.o],返回结果是“x.c.o bar.o”

第22行:foreach,

names := a b c d
files := $(foreach n,$(names),$(n).o)
上面的例子中,$(name)中的单词会被挨个取出,并存到变量“n”中,“$(n).o”每次
根据“$(n)”计算出一个值,这些值以空格分隔,最后作为 foreach 函数的返回,所以,
$(files)的值是“a.o b.o c.o d.o”。

shell,

它的参数应该就是操作系统 Shell 的命令,它和反引号“`”是相同的功能。

注意,这个函数会新生成一个 Shell 程序来执行命令,所以你要注意其运行性能,如果你的
Makefile 中有一些比较复杂的规则,并大量使用了这个函数,那么对于你的系统性能是有
害的。特别是 Makefile 的隐晦的规则可能会让你的 shell 函数执行的次数比你想像的多得
多。


各个子目录中的makefile:(关于自动依赖的关键点


截取《跟我一起学习makefile》自动生成依赖部分内容:

====================================================================================================

在 Makefile 中, 我们的依赖关系可能会需要包含一系列的头文件,比如, 如果我们的 main.c中有一句“#include "defs.h"”,那么我们的依赖关系应该是:

main.o : main.c defs.h


大多数的C/C++编译器都支持一个“-M”的选项,即自动找寻源文件中包含的头文件,并生成一个依赖关系。

例如,如果我们执行下面的命令:
cc -M main.c
其输出是:
main.o : main.c defs.h

于是由编译器自动生成的依赖关系,这样一来,你就不必再手动书写若干文件的依赖关系,而由编译器自动生成了。

需要提醒一句的是,如果你使用 GNU 的 C/C++编译器,你得用“-MM”参数,不然,“-M”参数会把一些标准库

的头文件也包含进来

gcc -M main.c 的输出是:

main.o: main.c defs.h /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \
/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/pthreadtypes.h \
/usr/include/bits/sched.h /usr/include/libio.h \
/usr/include/_G_config.h /usr/include/wchar.h \
/usr/include/bits/wchar.h /usr/include/gconv.h \
/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stdarg.h \
/usr/include/bits/stdio_lim.h

gcc -MM main.c 的输出则是:
main.o: main.c defs.h

我们用的是gcc编译器所以用参数-MM。

======================================================================================================

取 http://blog.chinaunix.net/uid-20316928-id-3395996.html 部分内容:

======================================================================================================

Makefile如果由其它文件重建(这里我的Makefile sinclude了所有.d文件,.d也可以看成是一个Makefile),Makefile在读入所有其他makefile文件(.d)之后,首先将所读取的每个makefile(.d)作为一个目标,寻找更新它们的规则.

======================================================================================================

main目录:



例如:sources = led.c main.c

执行完$(sources:.c=.c)

第7行展开为:

sinclude led.d main.d

第四行: 由于sources第一个值为led.c,所以%.o 会自动展开为led.o,

所以在编译的时候只会加入led.c所依赖的头文件。

  将%.o改成main.o,在编译时候就只会加入main.c中所依赖的头文件。

将%.o改成led.o main.o ,编译时候只会加入第一个目标所依赖的头文件。

 

这就导致了如果有多个源文件,且这些源文件包含不同的头文件,那么在修改了某些头文件,也不会生成新的目标文件。



src目录:


第5行:sinclude,包含source变量中的所有.c文件对应的.d文件.

例如:

test.c则去包含test.d(.d文件也是一个makefile文件,找到.d文件会自动编译)

当前目录下找不到.d文件所以在当前makefile中查询.d文件生成依赖进入7~10行。

第7~10行:(这一段粘贴就好

第8行:将生成的输出保存在test.d.$$文件中

第9行:生成test.d文件,该文件的内容为:

src/eat目录:


第3~4行的内容:如果只是单个文件可以不加,如上图src目录下面的makefile,没有加编译也可以通过。

插入编译过程中的截图:

可以看出每个子目录都进去了两次,编译两个makefile

第一次执行:当前的makefile

第二次执行:sinclude中的.d文件



最后贴上编译后的源码树:



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章