工作中涉及到一些代码集成部分的工作,之前用过cmake,makefile,现在再系统学习一下,做一些笔记方便以后查阅
edit : main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o
main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h buffer.h
cc -c display.c
insert.o : insert.c defs.h buffer.h
cc -c insert.c
search.o : search.c defs.h buffer.h
cc -c search.c
files.o : files.c defs.h buffer.h command.h
cc -c files.c
utils.o : utils.c defs.h
cc -c utils.c
clean :
rm edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o
--------------------------------------------------------------
objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
main.o : defs.h kbd.o : defs.h command.h command.o : defs.h command.h display.o : defs.h buffer.h insert.o : defs.h buffer.h search.o : defs.h buffer.h files.o : defs.h buffer.h command.h utils.o : defs.h
.PHONY : clean
clean :
rm edit $(objects)
targets : prerequisites
command ...
或是这样:
targets : prerequisites ;
command
command ...
--------------------------------------------------------------
#make 自动推导
#make 看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中
#cc -c whatever.c 也会被推导出来
objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
display.o : defs.h buffer.h
insert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h
.PHONY : clean
clean :
rm edit $(objects)
--------------------------------------------------------------
#清空目标文件的规则
clean:
rm edit $(objects)
.PHONY : clean
clean :
-rm edit $(objects)
--------------------------------------------------------------
Makefile 里有什么
显示规则 : 如何生成一个或多的的目标文件。
隐晦规则 : 由于我们的 make 有自动推导的功能
变量的定义 : 在Makefile中我们要定义一系列的变量,变量一般都是字符串
文件指示 :
1 在一个Makefile中引用另一个Makefile,就像C语言中的include一样;
2 根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样;
3 定义一个多行的命令。有关这一部分的内容,我会 在后续的部分中讲述。
注释 : Makefile 中只有行注释,和 UNIX 的 Shell 脚本一样,其注释是用“#”字符
注释。Makefile 中只有行注释,和 UNIX 的 Shell 脚本一样,其注释是用“#”字符
--------------------------------------------------------------
Makefile 的文件名 : makefile 、 Makefile
引用其它的 Makefile
include foo.make *.mk $(bar)
变量$(bar),其包含了 e.mk 和 f.mk 等价于:
include foo.make a.mk b.mk c.mk e.mk f.mk
make 执行时,有“-I”或“--include-dir” 指定的目录下去寻找
目录<prefix>/include(一般是:/usr/local/bin 或/usr/include) 存在的话,make 也会去找。
环境变量 MAKEFILES 建议不要使用这个环境变量
--------------------------------------------------------------
make 的工作方式
1、读入所有的Makefile。 2、读入被include的其它Makefile。 3、初始化文件中的变量。 4、推导隐晦规则,并分析所有规则。 5、为所有的目标文件创建依赖关系链。
定义的变量被使用了,那么,make会把其展开在使用的位置。但make并不会完全马上展开,make使用的是拖延战术,如果变量出现在依赖关系的规则中,那么仅当这条依赖被决定要使用了,变量才会在其内部展开。
6、根据依赖关系,决定哪些目标要重新生成。 7、执行生成命令。
--------------------------------------------------------------
书写规则
一个是依赖关系,一个是生成目标的方法。
--------------------------------------------------------------
clean:
rm -f *.o
#目标 print 依赖于所有的[.c]文 件。其中的“$?”是一个自动化变量
print: *.c
lpr -p $?
touch print
objects = *.o
#如果你要让通配符在变量 中展开,也就是让 objects 的值是所有[.o]的文件名的集合
objects := $(wildcard *.o)
--------------------------------------------------------------
文件搜寻
#目录由“冒号”分隔,Makefile 文件中的特殊变量“VPATH”
VPATH = src:../headers
#另一个设置文件搜索路径的方法是使用 make 的“vpath”关键字(注意,它是全小写的)这是一个make的关键字,这和上面提到的那个VPATH变量很类似,但是它更灵活。可以指定不同的文件在不同的搜索目录中
#为符合模式<pattern>的文件指定搜索目录<directories>
1、vpath <pattern> <directories>
#清除符合模式<pattern>的文件的搜索目录
2、vpath <pattern>
#清除所有已被设置好了的文件搜索目录
3、vpath
#<pattern>需要包含“%”字符。“%”的意思是匹配零或若干字符,例 如,“%.h”表示所有以“.h”结尾的文件。 <pattern>指定了要搜索的文件集, 而 <directories>则指定了<pattern>的文件集的搜索的目录。
vpath %.h ../headers
#“.c”结尾的文件,先在“foo”目录,然后是“blish”,最后是“bar”目录。
vpath %.c foo
vpath % blish
vpath %.c bar
#“.c”结尾的文件,先在“foo”目录,然后是“blish”,最后是“bar”目录。
vpath %.c foo:bar
vpath % blish
--------------------------------------------------------------
伪目标
#“伪目标”并不是一个文件,只是一个标签
clean:
rm *.o temp
#“.PHONY”来显示 地指明一个目标是“伪目标”
.PHONY: clean
clean:
rm *.o temp
#伪目标一般没有依赖的文件。但是,我们也可以为伪目标指定所依赖的文件。伪目标同样可以作为“默认目标”,只要将其放在第一个。一个示例就是,如果你的Makefile需要一口气生成若干个可执行文件,但你只想简单地敲一个make完事
#伪目标的特性是,总是被执行的,所以其依赖的那三个 目标就总是不如“all”这个目标新。所以,其它三个目标的规则总是会被决议。也就达到 了我们一口气生成多个目标的目的。
all : prog1 prog2 prog3
.PHONY : all
prog1 : prog1.o utils.o
cc -o prog1 prog1.o utils.o
prog2 : prog2.o
cc -o prog2 prog2.o
prog3 : prog3.o sort.o utils.o
cc -o prog3 prog3.o sort.o utils.o
#“make clean”将清除所有要被清除的文件。“cleanobj”和“cleandiff”这两个伪 目标有点像“子程序”的意思。我们可以输入“make cleanall”和“make cleanobj” 和“make cleandiff”命令来达到清除不同种类文件的目的。
.PHONY: cleanall cleanobj cleandiff
cleanall : cleanobj cleandiff
rm program
cleanobj :
rm *.o
cleandiff :
rm *.diff
--------------------------------------------------------------
多目标
#Makefile 的规则中的目标可以不止一个,其支持多目标,我们的可以使用一个自动化变量“$@”
#函数名为subst,后面的为参数。
bigoutput littleoutput : text.g
generate text.g -$(subst output,,$@) > $@
等价于:
bigoutput : text.g
generate text.g -big > bigoutput
littleoutput : text.g
generate text.g -little > littleoutput
--------------------------------------------------------------
静态模式 更加容易地定义多目标的规则
#targets 定义了一系列的目标文件,可以有通配符。是目标的一个集合。
#target-parrtern 是指明了targets的模式,也就是的目标集模式。
#prereq-parrterns 是目标的依赖模式,对target-parrtern形成的模式再进行一次依赖目标的定义。
<targets ...>: <target-pattern>: <prereq-patterns ...>
<commands>
...
如果我们的<target-parrtern>定义成“%.o”
意思是我们的<target>集合中都是以“.o”结尾的
如果我们的<prereq-parrterns>定义成“%.c”
意思是对<target-parrtern> 所形成的目标集进行二次定义
其计算方法是,取<target-parrtern>模式中的“%”(也就是去掉了[.o]这个结尾),并为其加上[.c]这个结尾,形成的新集合。
所以,我们的“目标模式”或是“依赖模式”中都应该有“%”这个字符,如果你的文件名中有“%”那么你可以使用反斜杠“\”进行转义,来标明真实的“%”字符。
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
上面的例子中,指明了我们的目标从$object中获取,“%.o”表明要所有以“.o”结尾的目标,也就是“foo.o bar.o”,也就是变量$object集合的模式,而依赖模式“%.c”则取模式“%.o”的“%”,也就是“foo bar”,并为其加下“.c”的后缀,于是,我们的依赖目标就是“foo.c bar.c”。
命令中的“$<”和“$@”则是自动化变量,“$<”表示所有的依赖目标集(也就是“foo.c bar.c”),“$@”表示目标集(也就是“foo.o bar.o”)。 于是,上面的规则展开后等价于下面的规则:
foo.o : foo.c
$(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o : bar.c
$(CC) -c $(CFLAGS) bar.c -o bar.o
files = foo.elc bar.o lose.o
$(filter %.o,$(files)): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
$(filter %.elc,$(files)): %.elc: %.el
emacs -f batch-byte-compile $<
--------------------------------------------------------------
自动生成依赖性 自动找寻源文件中包含的头文件,并生成一个依赖关系。
main.o : main.c defs.h
#大多数的 C/C++ 编译器都支持一个“-M”的选项,即自动找寻源文件中包含的头文件
cc -M main.c
其输出是:
main.o : main.c defs.h
#如果你使用GNU的C/C++编译器,你得用“参数,不然,“-M”参数会把一些标准库的头文件也包含进来。
%.d: %.c
@set -e; rm -f $@; \
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
#所有的[.d]文件依赖于[.c]文件,“rm -f $@”的意思是删除所有的目标,[.d]文件
#第二行的意思是,为每个依赖文件“$<”,也就是[.c]文件生成 依赖文件,“$@”表示模式“%.d”文件,如果有一个 C 文件是 name.c,那么“%”就是“name”, “$$$$”意为一个随机编号,第二行生成的文件有可能是“name.d.12345”
#第三行使用sed命令做了一个替换,关于 sed 命令的用法请参看相关的使用文档。
#第四行就是删除临时文件。
总而言之,这个模式要做的事就是在编译器生成的依赖关系中加入[.d]文件的依赖,即把依 赖关系:
--------------------------------------------------------------
书写命令
每条命令的开头必须以[Tab]键开头,除非命令是紧跟在依赖规则后面的分号后的。在命令行之间中的空格或是空行会被忽略,但是如果该空格或空行是以Tab键开头的,那make会认为其是一个空命令。
显示命令
当我们用“@”字符在命令 行前,那么,这个命令将不被make显示出来,最具代表性的例子是,我们用这个功能来像 屏幕显示一些信息。
------------------------------------