学习记录(对应文档的p21-p30)
伪目标一般没有依赖的文件,但也可以指定。
需要生成多个可执行文件
all : prog1 prog2 prog3
.PHONY : all
六、多目标
自动化变量$@
例子:
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
其中,-$(subst output,,$@)中的“$”表示执行一个 Makefile 的函数(后面详讲)subst,
后面的为参数。截取字符串,“$@”表示目标的集合,就像一个数组,“$@”依次取出目标,并执于命令。
七、静态模式
<targets...>: <target-pattern>: <prereq-patterns...>
<command>
....
例子:
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
目标从$objects获取
“%.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
Makefile的filter函数,只要file中以.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.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参数
到Makefile中,使用:
把编译器为每一个源文件的自动生成的依赖关系放到一个文件中。
为每一个name.c的文件都生成一个name.d的Makefile文件
%.d: %.c
@set -e: rm -f $@: \
$(CC) -M $(CPPFLAGS) $< >$@.SSSS: \
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]文件的依赖,
即把依赖关系:
main.o : main.c defs.h
转成:
main.o main.d : main.c defs.h
Makefile 的“include”命令,来引入别的 Makefile 文件
sources = foo.c bar.c
include $(sources:.c=.d)
说明, “.c=.d” 做替换,把变量$(sources)所有[.c]的字串都替换(后面详讲)成[.d]
第六部分 书写命令
一、显示命令
make会把要执行的命令输出到屏幕,当在命令前加@,不显示。
例子:
@echo 正在编译xxx模块......
当 make 执行时,会输出“正在编译 XXX 模块......”字串
make 执行时,带参数“-n”或“--just-print”,只显示命令,但不会执行
用于调试Makefile,看书写的命令是执行起来是什么样子的或是什么顺序
参数-s或--silent 全面禁止命令的显示
二、命令执行
第2个命令在第1个的基础上执行,写在同一行,用;分隔开
三、命令出错
忽略命令出错,在命令前加- 或者给make加-i或--ignore-errors
一个规则是以“.IGNORE”作为目标的,那么这个规则中的所有命令将会忽略错误。
make的-k或--keep-going 某规则中命令出错,终止该规则,但继续执行其他规则
四、嵌套执行make
每个目录写一个该目录的Makefile
例子:有个子目录subdir,该目录下有Makefile,总的Makefile
subsystem:
cd subdir && $(MAKE)
等价于:进入subbir,执行make
subsystem:
$(MAKE) -C subdir
总控Makefile的变量可传递到下级Makefile(显示的声明)
但不会覆盖下层的Makefile定义的变量,除非指定-e参数
显示声明:
export <variable ...>
不想传到下级
unexport <variable ...>
示例:export variable = value
等价:
variable = value
export variable
等价:export variable := value
等价:
variable := value
export variable
有2个变量:SHELL、MAKEFLAGS,不管是否export,总要传给下层
make有几个参数并不往下传递,它们是“-C”,“-f”,“-h”“-o”和“-W”(细节将在后面说明)
不想往下层传递参数:
subsystem:
cd subdir && $(MAKE) MAKEFLAGS=
如果你定义了环境变量 MAKEFLAGS,那么你得确信其中的选项是大家都会用到的,如果
其中有“-t”,“-n”,和“-q”参数,那么将会有让你意想不到的结果,或许会让你异常地恐慌。
在嵌套执行中有用的参数-w或--print-directory,输出信息,看到当前工作目录
例子:下级make目录是/home/hchen/gnu/make,使用make -w,进入该目录,会输出:
make: Entering directory `/home/hchen/gnu/make'.
完成下层 make 后离开目录时,看到:
make: Leaving directory `/home/hchen/gnu/make'
-C”参数来指定 make 下层Makefile 时,“-w”会被自动打开的。如果参数中有
“-s”(“--slient”)或是“--no-print-directory”,那么,“-w”总是失效的。
五、定义命令包
相同的命令序列,定义一个变量
define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef
说明:
run-yacc是命令包的名字
第一个命令是运行 Yacc程序,Yacc 程序总是生成“y.tab.c”的文件
第二行的命令就是把这个文件改名字。
示例:
foo.c : foo.y
$(run-yacc)
使用这个命令包,我们就好像使用变量一样。
命令包“run-yacc”中的“$^”就是“foo.y”,“$@”就是“foo.c”
有关这种以“$”开头的特殊变量,我们会在后面介绍
第七部分 使用变量
传统的 Makefile 的变量名是全大写的命名方式,推荐使用大小写搭配的变量名
如:MakeFlags。避免和系统的变量冲突,而发生意外的事情。
本文深入讲解Makefile的高级用法,包括伪目标、多目标、静态模式规则、自动生成依赖性等功能,以及如何通过Makefile简化项目的构建流程。
5936

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



