跟着耗子哥学习,基本都是抄他的笔记,侵删 跟我一起写 Makefile(一)_陈皓专栏 【空谷幽兰,心如皓月】-CSDN博客_makefile
编译: 把.c文件变成.o文件
链接: 把.o文件变成可执行文件,比如a.out
make file 规则
target ... : prerequisites ...
command
...
...
target 是目标文件,可以是.o, 也可以是执行文件,
prerequisite 是前置条件,要生产target,必须满足前置条件
command 是make要执行的shell命令,在Makefile中的命令,必须要以[Tab]键开始。
典型的make file如下
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
clean : 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
可以看到edit和clean的是一样的,如果我们要修改,那么就得改两处,为了不这样:
可以定义变量:
objects = 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
而clean改成
clean: rm edit $(objects)
约定俗成
make的第一个可执行命令,为默认的执行命令
clean一般在make最末尾
自动推导
main.o 会自动找寻main.c依赖,所以无需在Makefile显示声明
引用其它的Makefile
用法为include <filename>
include foo.make *.mk $(bar)
等价于:
include foo.make a.mk b.mk c.mk e.mk f.mk
make中有一步,为所有的目标文件创建依赖关系链,我觉得这就是所谓的链接?
跟我一起写 Makefile(四)_陈皓专栏 【空谷幽兰,心如皓月】-CSDN博客
看到vpath,其他没咋看
伪目标
比如clean,其实就是不生成文件,但是确实会执行的指令,这个指令可能是其他指令的集合
“伪目标”,向make说明,不管是否有这个文件,这个目标就是“伪目标”。
.PHONY : clean
只要有这个声明,不管是否有“clean”文件,要运行“clean”这个目标,只有“make clean”这样。于是整个过程可以这样写:
.PHONY: clean
clean:
rm *.o temp
(五)多目标及自动依赖性
总而言之,这个模式要做的事就是在编译器生成的依赖关系中加入[.d]文件的依赖,即把依赖关系:
main.o : main.c defs.h
转成:
main.o main.d : main.c defs.h
(六)命令执行
@echo 显示命令
执行命令:需要注意的是,如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令。
exec:
cd /home/hchen; pwd
忽略命令出错
前面加个"-"号
clean:
-rm -f *.o
嵌套执行make
subsystem:
cd subdir && $(MAKE)
其等价于:
subsystem:
$(MAKE) -C subdir
这两个例子的意思都是先进入“subdir”目录,然后执行make命令。
如果你要传递变量到下级Makefile中,那么你可以使用这样的声明:
variable = value
export variable
(七)变量
$(object)是求object的值
最好使用这种定义: x := foo
dir := /foo/bar # directory to put the frobs in
后面采用“#”注释符来表示变量定义的终止,/foo/bar后面还跟了4个空格,如果我们这样使用这样变量来指定别的目录——“$(dir)/file”那么就完蛋了。
两种变量的高级使用方法
第一种是变量值的替换。
我们可以替换变量中的共有的部分,其格式是“$(var:a=b)”或是“${var:a=b}”,其意思是,把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串。这里的“结尾”意思是“空格”或是“结束符”
foo := a.o b.o c.o
bar := $(foo:.o=.c)
“$(bar)”的值就是“a.c b.c c.c”。
第二种高级用法是——“把变量的值再当成变量”。
先看一个例子:
x = y
y = z
a := $($(x))
在这个例子中,$(x)的值是“y”,所以$($(x))就是$(y),于是$(a)的值就是“z”。
override
用来覆盖命令行参数的值
语法是:
override <variable> = <value>
override <variable> := <value>
(八)变量二
(九)函数
调用语法:
$(<function> <arguments>)
示例:
comma:= ,
empty:=
space:= $(empty) $(empty)
foo:= a b c
bar:= $(subst $(space),$(comma),$(foo))
字符函数
$(subst <from>,<to>,<text>)
名称:字符串替换函数——subst。
功能:把字串<text>中的<from>字符串替换成<to>。
$(strip <string>)
名称:去空格函数——strip。
功能:去掉<string>字串中开头和结尾的空字符。
$(filter <pattern...>,<text>)
名称:过滤函数——filter。
sources := foo.c bar.c baz.s ugh.h
foo: $(sources)
cc $(filter %.c %.s,$(sources)) -o foo
$(filter %.c %.s,$(sources))返回的值是“foo.c bar.c baz.s”。
$(word <n>,<text>)
名称:取单词函数——word。
功能:取字符串<text>中第<n>个单词。(从一开始)
示例:$(word 2, foo bar baz)返回值是“bar”。
$(words <text>)
名称:单词个数统计函数——words。
功能:统计<text>中字符串中的单词个数。
返回:返回<text>中的单词数。
示例:$(words, foo bar baz)返回值是“3”。
文件名操作函数
$(dir <names...>)
名称:取目录函数——dir。
示例: $(dir src/foo.c hacks)返回值是“src/ ./”。
$(notdir <names...>)
名称:取文件函数——notdir。
$(notdir src/foo.c hacks)返回值是“foo.c hacks”。
$(basename <names...>)
名称:取前缀函数——basename。
示例:$(basename src/foo.c src-1.0/bar.c hacks)返回值是“src/foo src-1.0/bar hacks”。
(十)函数二
foreach if
call 修改参数顺序调用,并返回的函数
reverse = $(2) $(1)
foo = $(call reverse,a,b)
$(origin <variable>) 变量来源于哪里。比如envirment,环境变量
shell函数 看不下去了
控制函数 error和warning,error会导致退出,warning只是打印
(十一)make的运行
make的退出码
0 成功 1失败
当前目录下依次找三个文件——“GNUmakefile”、“makefile”和“Makefile”。其按顺序找这三个文件,一旦找到,就开始读取这个文件并执行。
指定makefile
我们也可以给make命令指定一个特殊名字的Makefile,例如,我们有个makefile的名字是“hchen.mk”,那么,我们可以这样来让make来执行这个文件:
make –f hchen.mk
指定目标
有一个make的环境变量叫“MAKECMDGOALS”,
sources = foo.c bar.c
ifneq ( $(MAKECMDGOALS),clean)
include $(sources:.c=.d)
endif
基于上面的这个例子,只要我们输入的命令不是“make clean”,那么makefile会自动包含“foo.d”和“bar.d”这两个makefile。
还有约定俗成的指定目标如下:
“all”
这个伪目标是所有目标的目标,其功能一般是编译所有的目标。
“clean”
这个伪目标功能是删除所有被make创建的文件。
“install”
这个伪目标功能是安装已编译好的程序,其实就是把目标执行文件拷贝到指定的目标中去。
“print”
这个伪目标的功能是例出改变过的源文件。
“tar”
这个伪目标功能是把源程序打包备份。也就是一个tar文件。
“dist”
这个伪目标功能是创建一个压缩文件,一般是把tar文件压成Z文件。或是gz文件。
“TAGS”
这个伪目标功能是更新所有的目标,以备完整地重编译使用。
“check”和“test”
这两个伪目标一般用来测试makefile的流程。
make的参数
-n -q -w
-debug等等,详细介绍debug
“—debug[=<options>]”
输出make的调试信息。它有几种不同的级别可供选择,如果没有参数,那就是输出最简单的调试信息。下面是<options>的取值:
a —— 也就是all,输出所有的调试信息。(会非常的多)
b —— 也就是basic,只输出简单的调试信息。即输出不需要重编译的目标。
v —— 也就是verbose,在b选项的级别之上。输出的信息包括哪个makefile被解析,不需要被重编译的依赖文件(或是依赖目标)等。
i —— 也就是implicit,输出所以的隐含规则。
(十二)隐含规则
自动推导,比如编译器会自动根据c生成对应的o文件,如果c没有找到,就会再根据p(Pascal)生成o文件
1、编译C程序的隐含规则。
“<n>.o”的目标的依赖目标会自动推导为“<n>.c”,并且其生成命令是“$(CC) –c $(CPPFLAGS) $(CFLAGS)”
2、编译C++程序的隐含规则。
“<n>.o”的目标的依赖目标会自动推导为“<n>.cc”或是“<n>.C”,并且其生成命令是“$(CXX) –c $(CPPFLAGS) $(CFLAGS)”。(建议使用“.cc”作为C++源文件的后缀,而不是“.C”)
隐含规则中包含一些变量,比如cc,CFLAGS等
一个目标可能被一系列的隐含规则所作用。例如,一个[.o]的文件生成,可能会是先被Yacc的[.y]文件先成[.c],然后再被C的编译器生成。我们把这一系列的隐含规则叫做“隐含规则链”。
隐含规则中间的,叫中间目标,中间目标文件一般会被删除,当然你可以通过参数指定不删除
(十三)模式规则
%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
其中,"$@"表示所有的目标的挨个值,"$<"表示了所有依赖目标的挨个值。这些奇怪的变量我们叫"自动化变量",后面会详细讲述。
下面的这个例子中有两个目标是模式的:
%.tab.c %.tab.h: %.y
bison -d $<
这条规则告诉make把所有的[.y]文件都以"bison -d <n>.y"执行,然后生成"<n>.tab.c"和"<n>.tab.h"文件。
自动化变量
$@
$%等
如果一个目标是"foo.a(bar.o)",那么,"$%"就是"bar.o","$@"就是"foo.a"。
模式的匹配
因为"%"代表一个或多个字符,所以在定义好了的模式中,我们把"%"所匹配的内容叫做"茎",例如"%.c"所匹配的文件"test.c"中"test"就是"茎"。
如有一个模式"e%t",文件"src/eat"匹配于该模式,于是"src/a"就是其"茎",如果这个模式定义在依赖目标中,而被依赖于这个模式的目标中又有个模式"c%r",那么,目标就是"src/car"。
后面的看不下去了。。。。
(十四)函数库文件
archive(member)
这个不是一个命令,而一个目标和依赖的定义。
如果我们使用"make foo.a(bar.o)"
make执行的命令大致如下:
cc -c bar.c -o bar.o
ar r foo.a bar.o
rm -f bar.o
你还可以在Makefile中书写其它的命令,如:tar、awk、mail、sed、cvs、compress、ls、rm、yacc、rpm、ftp……等等,等等,来完成诸如"程序打包"、"程序备份"、"制作程序安装包"、"提交代码"、"使用程序模板"、"合并文件"等等五花八门的功