Makefile杂记

因为一些原因要看 qemuMakefile,然而看的一脸懵逼,做个总结。

make的一些常用选项

  • -d 显示调试信息
  • -f 指定从哪个文件中读取依赖关系信息。默认文件是Makefile或makefile, - 表示从标准输入
  • -h 显示所有的Makefile的help信息
  • -n 打印所有Makefile执行命令,但不执行这些命令
  • -s  运行时不显示任何信息  
  • 注释 #
  • 连接符 \

变量

变量在声明时需要给予初值,而在使用时,需要给在变量名前加上 $ 符号,但最好用小括号 () 或是大括号 {} 把变量给包括起来。如果你要使用真实的 $ 字符,那么你需要用 $$ 来表示。
@表示当前目标的名称

1
2
3
4
5
objects = program.o foo.o utils.o
program : $(objects)
cc -o program $(objects)
$(objects) : defs.h

Makefile规则

1
2
3
4
target ... : prerequisites ...
command
...
...

target 可以是一个object file(目标文件),也可以是一个执行文件,还可以是一个标签(label)。对 于标签这种特性,在后续的“伪目标”章节中会有叙述。
prerequisites 生成该 target 所依赖的文件
commandtarget 要执行的命令(任意的 shell 命令)

prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。

1
objects = *.o

通配符同样可以用在变量中。并不是说 *.o 会展开, objects的值就是 *.o 。如果你要让通配符在变量中展开:

1
objects := $(wildcard *.o)

编译并链接所有.c.o 文件

1
2
3
objects := $(patsubst %.c,%.o,$(wildcard *.c))
foo : $(objects)
cc -o foo $(objects)

伪目标

1
2
clean:
rm *.o temp

上面的 clean 就是一个伪目标。也可以通过 .PHONY 来显式地指明一个目标是伪目标

1
.PHONY : clean

一个小例子

1
2
3
4
5
6
7
8
9
10
11
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

函数调用语法

$(<function> < arguments>)

<function>是函数名,make 支持的函数不多。<arguments> 是函数的参数,参数
间以逗号,分隔,函数名和参数之间以空格分隔。函数调用以 $ 开头,以圆
括号或花括号把函数名和参数括起。
例子如下,

1
2
3
4
5
6
7
8
9
comma:= ,
empty:=
space:= $(empty) $(empty)
foo:= a b c
bar:= $(subst $(space),$(comma),$(foo))
all:
@echo $(bar)
// a b c

条件判断

判断 $(CC) 变量是否 gcc ,如果是的话,则使用 GNU 函数编译目标。

1
2
3
4
5
6
7
8
9
libs_for_gcc = -lgnu
normal_libs =
foo: $(objects)
ifeq ($(CC),gcc)
$(CC) -o foo $(objects) $(libs_for_gcc)
else
$(CC) -o foo $(objects) $(normal_libs)
endif

多目标

自动化变量 $@ 表示目前规则中所有的目标的集合

1
2
bigoutput littleoutput : text.g
generate text.g -$(subst output,,$@) > $@

相当于

1
2
3
4
bigoutput : text.g
generate text.g -big > bigoutput
littleoutput : text.g
generate text.g -little > littleoutput

静态模式

1
2
3
4
5
6
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))表示调用Makefilefilter函数,过滤$files集,只要其中模式 为%.o的内容。

常用函数

1
$(subst <from>,<to>,<text> )

字符串替换函数,把字串 <text> 中的 <from> 字符串替换成 <to>。函数返回被替换过后的字符串。

1
$(patsubst <pattern>,<replacement>,<text> )

模式字符串替换函数,查找 <text> 中的单词(单词以空格、Tab 或回车,换行分隔)是否符合模式<pattern>,如果匹配的话,则以<replacement> 替换。<pattern>可以包括通配符 %,表示任意长度的字串。如果 <replacement>中 也包含 %,那么,<replacement> 中的这个 % 将是 <pattern> 中的那个 % 所代表的字串。

1
$(strip <string> )

去掉字串中开头和结尾的空字符,返回被去掉空格的字符串值。

1
$(findstring <find>,<in>)

查找字符串函数,在字串 <in> 中查找 <find> 字串。如果找到,那么返回 <find> ,否则返回空字符串。

1
$(filter <pattern...>,<text>)

过滤函数,以 <pattern> 模式过滤 <text> 字符串中的单词,保留符合模式 <pattern> 的单词。可以有多个模式。返回符合模式 <pattern> 的字串

1
2
3
sources := foo.c bar.c baz.s ugh.h
foo: $(sources)
cc $(filter %.c %.s,$(sources)) -o foo

输出foo.c bar.c baz.s

1
$(filter-out <pattern...>,<text>)

filter 相反

1
$(sort <list>)

给字符串 <list> 中的单词排序(升序)。$(sort foo bar lose) 返回 bar foo lose

1
$(dir <names...>)

取目录函数,从文件名序列 <names> 中取出目录部分。目录部分是指最后一个反斜杠( / )之前 的部分。如果没有反斜杠,那么返回 ./

1
$(notdir <names...>)

$(notdir src/foo.c hacks) 返回值是 foo.c hacks

1
$(join <list1>,<list2>)

<list2> 中的单词对应地加到 <list1> 的单词后面。如果 <list1> 的 单词个数要比 <list2> 的多,那么, <list1> 中的多出来的单词将保持原样。如果 <list2> 的单词个数要比 <list1> 多,那么, <list2> 多出来的单词将被复制到 <list1>

1
$(call <expression>,<parm1>,<parm2>,...,<parmn>)

call函数是唯一一个可以用来创建新的参数化的函数。当make执行这个函数时, <expression> 参数中的变量,如 $(1)$(2) 等,会 被参数 <parm1><parm2><parm3> 依次取代。而 <expression> 的 返回值就是 call 函数的返回值。

1
2
3
reverse = $(2) $(1)
foo = $(call reverse,a,b)

foo 的值就是 b a

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. make的一些常用选项
  2. 2. 变量
  3. 3. Makefile规则
  4. 4. 伪目标
  5. 5. 函数调用语法
  6. 6. 条件判断
  7. 7. 多目标
  8. 8. 静态模式
  9. 9. 常用函数
,