《跟我一起学makefile》学习笔记(三)

学习记录(对应文档的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,
后面的为参数。截取字符串,“$@”表示目标的集合,就像一个数组,“$@”依次取出目标,并执于命令。  
七、静态模式
: :

....
例子:
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) $< >[email protected]: \
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
    不想传到下级
unexport
    示例: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)