- makefile的学习:(根本是根据文件创建的依赖关系实现各个命令来达到最终目的)
- 文件编写规则:显式规则、隐晦规则、变量定义、文件指示和注释
targets : prerequisites
Command
targets : prerequisites ; command
Command
targets 是文件名,以空格分开,可以使用通配符。一般来说,我们的目标基本上是一个
文件,但也有可能是多个文件。
command 是命令行,如果其不与“target rerequisites”在一行,那么,必须以[Tab 键]
开头,如果和 prerequisites 在一行,那么可以用分号做为分隔。(见上)
prerequisites 也就是目标所依赖的文件(或依赖目标)。如果其中的某个文件要比目标
文件要新,那么,目标就被认为是“过时的”,被认为是需要重生成的。这个在前面已
经讲过了。
Eg:main.o : main.c defs.h /*这里的main.o就是最终要生成的目标文件,其是依据main.c以及defs.h,这里的defs.h是用户自己的库文件*/
cc -c main.c /*这里cc是Makefile文件中自带的gcc变量,此语句用来生成main.o文件*/
-static 禁止使用动态库
编译出来的东西,一般都很大,也不需要什么动态连接库,就可以运行。
- 其他使用功能:通配符;“*”“?”“[...]”
- 文件搜寻:特殊变量(VPATH),VPATH=src:../headers :两个目录 src和 ../headers,冒号分割
使用方法有三种:
1、vpath <pattern> <directories>
为符合模式<pattern>的文件指定搜索目录<directories>。
2、vpath <pattern>
清除符合模式<pattern>的文件的搜索目录。
3、vpath
清除所有已被设置好了的文件搜索目录。
3.伪目标:.PHONY 定义伪目标
eg:
.PHONY: clean
clean:
rm *.o temp
使用 make clean 命令行输出: rm *.o temp
PHONY: cleanall cleanobj cleandiff
cleanall : cleanobj cleandiff
rm program
cleanobj :
rm *.o
cleandiff :
rm *.diff
“make clean”将清除所有要被清除的文件。“cleanobj”和“cleandiff”这两个伪目标有点
像“子程序”的意思。我们可以输入“make cleanall”和“make cleanobj”和“make
cleandiff”命令来达到清除不同种类文件的目的。
5.命令显示:在要执行的命令行之前加@,此命令行执行时屏幕上不会显示此命令。
6.命令执行:如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令。
Eg:
exec:
cd /home/hchen; pwd
当我们执行“make exec”时,第一个例子中的 cd 没有作用,pwd 会打印出当前的
Makefile 目录,而第二个例子中,cd 就起作用了,pwd 会打印出“/home/hchen”。
7.命令出错:命令正常返回0后继续执行后面指令,错误则返回非0,,则终止当前运行。
为了做到这一点,忽略命令的出错,我们可以在 Makefile 的命令行前加一个减号“-”
(在 Tab 键之后),标记为不管命令出不出错都认为是成功的。如:
clean:
-rm -f *.o
8.嵌套执行make:我们有一个子目录叫 subdir,这个目录下有个 Makefile 文件,来指明了这个目录下文件的编译规则。那么我们总控的 Makefile 可以这样书写:
subsystem:
cd subdir && $(MAKE) 总控makefile的变量可以传递给下一级makefile,需用export声明
Eg:expor<variable>
9.静态模式:
<targets ...>;: <target-pattern>;: <prereq-patterns ...>;
<commands>;
targets定义了一系列的目标文件,可以有通配符。是目标的一个集合。
target-parrtern是指明了targets的模式,也就是的目标集模式。
prereq-parrterns是目标的依赖模式,它对target-parrtern形成的模式再进行一次依赖目标的定义。
Eg:
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”)。
flietrs函数的应用:过滤
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 $<
$(filter %.o,$(files))表示调用Makefile的filter函数,过滤“$filter”集,只要其中模式为“%.o”的内容。其的它内容,我就不用多说了吧。这个例子展示了Makefile中更大的弹性。
10.自动生成依赖性:GNU组织建议把编译器为每一个.c源文件的自动生成的依赖关系放到一个文件.d中。
编译时加-M:自动找寻头文件
cc -M main.c
其输出是:
main.o : main.c defs.h
这里,我们给出了一个模式规则来产生[.d]文件:
%.d: %.c
@set -e; rm -f $@; \
$(CC) -M $(CPPFLAGS) $< >; $@.$$$$; \ //-M是编译生成.d文件
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ >; $@; \
rm -f $@.$$$$
其中$@表示目标文件,$<表示所有依赖文件。
这个规则的意思是,所有的[.d]文件依赖于[.c]文件,“rm -f $@”的意思是删除所有的目标,也就是[.d]文件,第二行的意思是,为每个依赖文件“$<”,也就是[.c]文件生成依赖文件,“$@”表示模式 “%.d”文件,如果有一个C文件是name.c,那么“%”就是“name”,“$$$$”意为一个随机编号,第二行生成的文件有可能是 “name.d.12345”,第三行使用sed命令做了一个替换,关于sed命令的用法请参看相关的使用文档。第四行就是删除临时文件。
高级变量方法:
foo := a.o b.o c.o
bar := $(foo:.o=.c)
这个示例中,我们先定义了一个“$(foo)”变量,而第二行的意思是把“$(foo)”中所有
以“.o”字串“结尾”全部替换成“.c”,所以我们的“$(bar)”的值就是“a.c b.c c.c”。
11.定义命令包:c语言定义函数一样
define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef
这里,“run-yacc”是这个命令包的名字,其不要和Makefile中的变量重名。在“define”和“endef”中的两行就是命令序列。这个 命令包中的第一个命令是运行Yacc程序,因为Yacc程序总是生成“y.tab.c”的文件,所以第二行的命令就是把这个文件改改名字。还是把这个命令 包放到一个示例中来看看吧。
foo.c : foo.y
$(run-yacc)
我们可以看见,要使用这个命令包,我们就好像使用变量一样。在这个命令包的使用中,命令包“run-yacc”中的“$^”就是“foo.y”,“$@” 就是“foo.c”(有关这种以“$”开头的特殊变量,我们会在后面介绍),make在执行命令包时,命令包中的每个命令会被依次独立执行。
我们可以使用“+=”操作符给变量追加值,如:
objects = main.o foo.o bar.o utils.o
objects += another.o
于是,我们的$(objects)值变成:“main.o foo.o bar.o utils.o another.o”(another.o 被追加
进去了)
?= :的用法
FOO ?= bar
其含义是,如果 FOO 没有被定义过,那么变量 FOO 的值就是“bar”,如果 FOO 先前
被定义过,那么这条语将什么也不做。
目标变量:prog
prog : CFLAGS = -g
prog : prog.o foo.o bar.o
$(CC) $(CFLAGS) prog.o foo.o bar.o
在这个示例中,不管全局的$(CFLAGS)的值是什么,在 prog 目标,以及其所引发的所
有规则中(prog.o foo.o bar.o 的规则),$(CFLAGS)的值都是“-g”
12.函数调用:函数调用,很像变量的使用,也是以“$”来标识的,其语法如下:
$(<function> <arguments> )
或是
${<function> <arguments>}
<function>就是函数名,make 支持的函数不多。<arguments>是函数的参数,参数
间以逗号“,”分隔,而函数名和参数之间以“空格”分隔。
Eg:$(subst a,b,$(x)):将$(x)中的a换成b subst是字符串处理函数
Eg: $(patsubst %.c,%.o,x.c.c bar.c)
把字串“x.c.c bar.c”符合模式[%.c]的单词替换成[%.o],返回结果是“x.c.o bar.o”
$(strip <string> ) :去空格函数,去掉开头结尾的空格的函数
$(findstring a,a b c)
$(findstring a,b c)
第一个函数返回“a”字符串,第二个返回“”字符串(空字符串)
13.文件名操作函数:
$(dir <names...> )
名称:取目录函数——dir。
功能:从文件名序列<names>中取出目录部分。目录部分是指最后一个反斜杠(“/”)
$(suffix <names...> )
名称:取后缀函数——suffix。
功能:从文件名序列<names>中取出各个文件名的后缀。
示例:$(suffix src/foo.c src-1.0/bar.c hacks)返回值是“.c .c”。
187

被折叠的 条评论
为什么被折叠?



