makefile学习(一)
2012-09-16 12:53
141 查看
为了使得rtems的源代码在自己的编译器上能够编译通过,不得不写makefile,否则对每个C文件的改动都要手动去编译,没有makefile只会感到越来越麻烦。
一。刚开始,没想那么多,就用sed提取出所有的C文件的文件名,然后借助sed的强大之处,一条sed命令生成冗长的一个makefile,比如有一个xxx.c文件,我就用sed命令把他处理成:
这样一来,有多少个c文件就有多少个以上操作,想想吧,一个makefile有几十k。
二。这样虽然看起来也简单,但是当我去静下心来看下makefile的相关文章之后,发现了自己的愚蠢之处,一条语句就可以解决的,这就是所谓的静态模式,例如,我们有a.c,b.c这两个源文件,我就可以这样写:
上面的规则等价于以下规则:
这样一来,我们的makefile就一条规则就搞定了,只有1k的大小。解释一下上面的代码:上面的例子中,指明了我们的目标从$objects中获取,“%.o”表明要所有以“.o”结尾的目标,也就是“a.o b.o”,也就是变量$object集合的模式,而依赖模式“%.c”则取模式“%.o”的“%”,也就是“a b”,并为其加下“.c”的后缀,于是,我们的依赖目标是“a.c
b.c”。而命令中的“$<”和“$@”则是自动化变量,“$<”表示所有的依赖目标集(也就是“a.c b.c”),“$@”表示目标集(也就是“a.o b.o“)。
三。以上所述部分,我没有提及头文件。我们现在要修改a.c,make一下,makefile会很智能的去执行命令
而不会去管其他没有被修改的文件。但是,在我们写的程序中,特别是一个操作系统中,头文件肯定是少不了的,如果a.c中包含a.h,b.c中包含b.h,现在修改a.h或者b.h试试看,make一下,结果会发现makefile啥都没做,但是我明明修改了文件啊,为什么make它没反应呢??对!!可以,让a.o和b.o分别依赖各自的头文件啊:
确实,再试试,修改一个头文件,make一下,makefile会去做我们想要它做的工作了。
然而,这样些会有很多的麻烦。
首先,这样写岂不是又回到了,我第一条说的,又把一个makefile没必要的写成了冗长冗长的样子。有人可能会说,可以用隐含规则去减少行数,比如将以上代码修改如下:
这样真的很简洁明了,代码量又少了。
那么,第二个麻烦,恐怕你就没办法解决了。如果有成千上百个c文件,每个c文件里都会包含不同的头文件,你要一个c文件一个c文件的去找头文件吗?这个不靠谱。。。
有问题就有解决之道:
比如,有如下的依赖关系存在
GNU make的官方手册建议这样写:(这个解决之道来自”linux c编程一站式学习“,至于现在的官方手册是不是还是这样写,我就不清楚了)
用如上的代码,我在ubuntu下试了下,确实是可以行的,能够解决头文件的依赖关系,也就是说,我修改一个头文件,那些依赖这个头文件的c文件都要重新编译。
上述语句中的“$(sources:.c=.d)”中的“.c=.d”的意思是做一个替换,把变量$(sources)所有[.c]的字串都替换成[.d]。当然,你得注意次序,因为include
是按次来载入文件,最先载入的[.d]文件中的目标会成为默认目标。
解释:(也是来自linux c编程一站式学习)
这个命令写了四行,但其实是一条命令,make只创建一个Shell进程执行这条命令,这条命令分为5个子命令,用分号隔开,并且为了美观,用续行符\拆成四行来写。执行步骤为:
1. set -e命令设置当前Shell进程为这样的状态:如果它执行的任何一条命令的退出状态非零则立刻终止,不再执行后续命令。
2. 把原来的maze.d删掉。
3. 重新生成maze.c的依赖关系,保存成文件maze.d.1234(假设当前Shell进程的id是1234)。注意,在Makefile中$有特殊含义,如果要表示它的字面意思则需要写两个$,所以Makefile中的四个$传给Shell变成两个$,两个$在Shell中表示当前进程的id,一般用它给临时文件起名,以保证文件名唯一。
4. 这个sed命令比较复杂,就不细讲了,主要作用是查找替换。maze.d.1234的内容应该是maze.o: maze.c maze.h main.h,经过sed处理之后存为maze.d,其内容是maze.o maze.d: maze.c maze.h main.h。
5. 最后
ad7a
把临时文件maze.d.1234删掉。
不管是Makefile本身还是被它包含的文件,只要有一个文件在make过程中被更新了,make就会重新读取整个Makefile以及被它包含的所有文件,现在main.d、stack.d和maze.d都生成了,就可以正常包含进来了(假如这时还没有生成,make就要报错而不是报警告了),相当于在Makefile中添了三条规则:
如果我在main.c中加了一行#include "foo.h",那么:
1. main.c的修改日期变了,根据第一条规则要重新生成main.o和main.d。
2. 现在main.d的内容更新为main.o main.d: main.c main.h stack.h maze.h foo.h。
3. 由于main.d被Makefile包含,main.d被更新又导致make重新读取整个Makefile,把新的main.d包含进来,于是新的依赖关系生效了。
这个所谓的官方提供的方案中的sed命令跟我平时用的语法有点不同,看起来很不爽,我就把它修改了我自己习惯的sed语句了:
四。悲催的是,我们自己的编译器是跑在windows下的,虽然支持makefile,但是不支持sed。
一。刚开始,没想那么多,就用sed提取出所有的C文件的文件名,然后借助sed的强大之处,一条sed命令生成冗长的一个makefile,比如有一个xxx.c文件,我就用sed命令把他处理成:
xxx.o: xxx.c cc -c xxx.c
这样一来,有多少个c文件就有多少个以上操作,想想吧,一个makefile有几十k。
二。这样虽然看起来也简单,但是当我去静下心来看下makefile的相关文章之后,发现了自己的愚蠢之处,一条语句就可以解决的,这就是所谓的静态模式,例如,我们有a.c,b.c这两个源文件,我就可以这样写:
objects = a.o b.o all: $(objects) $(objects): %.o: %.c $(CC) -c $< -o $@
上面的规则等价于以下规则:
a.o : a.c $(CC) -c a.c -o a.o b.o : b.c $(CC) -c b.c -o b.o
这样一来,我们的makefile就一条规则就搞定了,只有1k的大小。解释一下上面的代码:上面的例子中,指明了我们的目标从$objects中获取,“%.o”表明要所有以“.o”结尾的目标,也就是“a.o b.o”,也就是变量$object集合的模式,而依赖模式“%.c”则取模式“%.o”的“%”,也就是“a b”,并为其加下“.c”的后缀,于是,我们的依赖目标是“a.c
b.c”。而命令中的“$<”和“$@”则是自动化变量,“$<”表示所有的依赖目标集(也就是“a.c b.c”),“$@”表示目标集(也就是“a.o b.o“)。
三。以上所述部分,我没有提及头文件。我们现在要修改a.c,make一下,makefile会很智能的去执行命令
$(CC) -c a.c -o a.o
而不会去管其他没有被修改的文件。但是,在我们写的程序中,特别是一个操作系统中,头文件肯定是少不了的,如果a.c中包含a.h,b.c中包含b.h,现在修改a.h或者b.h试试看,make一下,结果会发现makefile啥都没做,但是我明明修改了文件啊,为什么make它没反应呢??对!!可以,让a.o和b.o分别依赖各自的头文件啊:
a.o : a.c a.h $(CC) -c a.c -o a.o b.o : b.c b.h $(CC) -c b.c -o b.o
确实,再试试,修改一个头文件,make一下,makefile会去做我们想要它做的工作了。
然而,这样些会有很多的麻烦。
首先,这样写岂不是又回到了,我第一条说的,又把一个makefile没必要的写成了冗长冗长的样子。有人可能会说,可以用隐含规则去减少行数,比如将以上代码修改如下:
a.o : a.c a.h b.o : b.c b.h
这样真的很简洁明了,代码量又少了。
那么,第二个麻烦,恐怕你就没办法解决了。如果有成千上百个c文件,每个c文件里都会包含不同的头文件,你要一个c文件一个c文件的去找头文件吗?这个不靠谱。。。
有问题就有解决之道:
比如,有如下的依赖关系存在
main.o: main.c main.h stack.h maze.h maze.o: maze.c maze.h main.h stack.o: stack.c stack.h main.h
GNU make的官方手册建议这样写:(这个解决之道来自”linux c编程一站式学习“,至于现在的官方手册是不是还是这样写,我就不清楚了)
all: main main: main.o stack.o maze.o gcc $^ -o $@ clean: -rm main *.o .PHONY: clean sources = main.c stack.c maze.c include $(sources:.c=.d) %.d: %.c set -e; rm -f $@; \ $(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$
用如上的代码,我在ubuntu下试了下,确实是可以行的,能够解决头文件的依赖关系,也就是说,我修改一个头文件,那些依赖这个头文件的c文件都要重新编译。
上述语句中的“$(sources:.c=.d)”中的“.c=.d”的意思是做一个替换,把变量$(sources)所有[.c]的字串都替换成[.d]。当然,你得注意次序,因为include
是按次来载入文件,最先载入的[.d]文件中的目标会成为默认目标。
解释:(也是来自linux c编程一站式学习)
这个命令写了四行,但其实是一条命令,make只创建一个Shell进程执行这条命令,这条命令分为5个子命令,用分号隔开,并且为了美观,用续行符\拆成四行来写。执行步骤为:
1. set -e命令设置当前Shell进程为这样的状态:如果它执行的任何一条命令的退出状态非零则立刻终止,不再执行后续命令。
2. 把原来的maze.d删掉。
3. 重新生成maze.c的依赖关系,保存成文件maze.d.1234(假设当前Shell进程的id是1234)。注意,在Makefile中$有特殊含义,如果要表示它的字面意思则需要写两个$,所以Makefile中的四个$传给Shell变成两个$,两个$在Shell中表示当前进程的id,一般用它给临时文件起名,以保证文件名唯一。
4. 这个sed命令比较复杂,就不细讲了,主要作用是查找替换。maze.d.1234的内容应该是maze.o: maze.c maze.h main.h,经过sed处理之后存为maze.d,其内容是maze.o maze.d: maze.c maze.h main.h。
5. 最后
ad7a
把临时文件maze.d.1234删掉。
不管是Makefile本身还是被它包含的文件,只要有一个文件在make过程中被更新了,make就会重新读取整个Makefile以及被它包含的所有文件,现在main.d、stack.d和maze.d都生成了,就可以正常包含进来了(假如这时还没有生成,make就要报错而不是报警告了),相当于在Makefile中添了三条规则:
main.o main.d: main.c main.h stack.h maze.h maze.o maze.d: maze.c maze.h main.h stack.o stack.d: stack.c stack.h main.h
如果我在main.c中加了一行#include "foo.h",那么:
1. main.c的修改日期变了,根据第一条规则要重新生成main.o和main.d。
2. 现在main.d的内容更新为main.o main.d: main.c main.h stack.h maze.h foo.h。
3. 由于main.d被Makefile包含,main.d被更新又导致make重新读取整个Makefile,把新的main.d包含进来,于是新的依赖关系生效了。
这个所谓的官方提供的方案中的sed命令跟我平时用的语法有点不同,看起来很不爽,我就把它修改了我自己习惯的sed语句了:
四。悲催的是,我们自己的编译器是跑在windows下的,虽然支持makefile,但是不支持sed。
相关文章推荐
- makefile常用函数学习(wildcard foreach filter word if ) PRODUCT_COPY_FILES
- 深入学习Make命令和Makefile
- 学习makefile(记录遇到的问题)
- 转载:运用Autoconf和Automake生成Makefile的学习之路
- Linux Make(Makefile)由浅入深的学习与示例剖析
- Makefile基础学习
- Makefile学习教程: 跟我一起写 Makefile
- GNU Makefile学习专题(三) | 第三个实例
- makefile的学习
- 对 makefile 中 call 函数学习的小例子
- makefile学习总结
- 【转藏】Makefile学习
- makefile的学习资料——跟我一起写 Makefile(全)
- Makefile学习(1):Makefile 中:= ?= += =的区别
- (二)我的Makefile学习冲动&&编译过程概述
- makefile学习
- Makefile学习笔记1
- makefile学习
- uboot学习之makefile编译一
- Makefile学习笔记---------自动化变量