07 May 2016

基本概念

makefile 一般采用从上而下(top-down)的结构,所以默认会更新 最上层的工作目标(通常叫all),下层的目标用来让上层工作目标保持在最新状态。例如用来删除无用的临时文件的clean工作目标应该放在最下层。

target1 target2 target3 : prerequisite1 prerequisite2
  command1
  command2
  command3
  • 每个命令必须以制表符[Tab]开头
  • # 为注释符
  • \ 为延续行符

规则

通配符

  • ~ 当前用户主目录
  • . 匹配任意字符
  • * 匹配任意数量
  • ?
  • [...] 字符集
  • [^...] 字符集的补集

假想目标

.PHONY 显式指定为假想目标,告诉 make 这不是一个目录,即使有这个目录存在.

.PHONY: clean
clean:
  rm -f *.o xxxxx

标准的假想工作目标

  • all 执行编译应用程序的所有工作
  • install 从已编译的二进制文件进行应用程序的安装
  • clean 清理
  • distclean 删除编译过程中除了可执行文件外的所有文件
  • TAGS 建立可供编辑器使用的标记列表
  • info 从 Texinfo 源代码来创建 GNU info 文件
  • check 执行与应用程序相关的任何测试

补充说明:当不带参数运行 make 时,默认运行 all 目标

变量

# 定义变量
variable-name = xxxxxxx
# 扩展变量
${variable-name}
# 或
$(variable-name)

自动变量(automatic variable)

由 make 设定,可作为工作目标或元素.

  • $@ 工作目标的文件名
  • $% 档案文件成员结构的文件名元素.
  • $< 第一个必要(需求)文件的文件名
  • $? 时间戳在工作目标后的所有必要条件,以空格分割
  • $^ 所有必要条件的文件名,空格分割,自动去重
  • $+$^ 但包含重复文件名(比如,传给连接器 linker 时有意义)
  • $* 工作目标的主文件名(一个文件名由主文件名 stem 和 后缀名 suffix 组成) 注: 若工作目标是 foo.a(bar.o), 则 $% 是 bar.o, $@是 foo.a, $* 是 foo

用 VPATH 和 vpath 来查找文件

可以用 vpath 来告诉 make 到不同目录去查找源文件.

vpath pattern directory-list

除非明确指出, make 只会在当前目录下寻找工作目标和必要条件. 下例中的源文件 *.c 均位于 src 目录下,头文件 *.h 均在 include 目录下:

CPPFLAGS = -I include
VPATH = src include
count_words: count_words.o counter.o lexer.o -lf1
  gcc $^ -o $@
count_words.o: count_words.c include/counter.h
  gcc --c $< -o $@
counter.o: counter.c include/counter.h include/lexer.h
  gcc -c $< -o $@
lexer.o: lexer.c include/lexer.h
  gcc -c $< -o $@
lexer.c: lexer.l
  flex -t $< > $@

更安全的方式是,用通配符形式指定相应目录下用到的文件形式.

vpath %.l %.c src
vpath %.h include

注: -lfl make会去标准程序库找到 libfl.a

模式规则

首先,所有C编译器会假设,文件若是以 .c 为扩展名,其所包含的就是C源代码,把扩展名从 .c 替换成 .o (对 WIN 的一些编译器来说是 .obj)就可以得到目标文件的文件名. make可以使用这些内置规则,makefile就变为:

VPATH = src include
CPPFLAGS  = -I include

count_words: counter.o lexer.o -lfl
count_words.o: counter.h
counter.o: conuter.h lexer.h
lexer.o: lexer.h

上述文件之所以能用,是因为 make 中内置了三条规则:

  • 如何从一个 .c 编译出一个 .o
    %.o %.c
    $(COMPILE.c) $(OUTPUT_OPTION) $<
    
  • 如何冲一个 .l 产生一个 .c
    %.c %.l
    @$(RM) $@
    $(LEX.l) $< > $@
    
  • 如何冲一个 .c 产生一个不带扩展名的,可执行文件
    %: %.c
    $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
    

可以用 make --print-data-base 命令查看所有的默认规则

模式规则中的 % 大体上相当于 shell 中的 * 但只能出现一次 例如:

%: %.mod
  $(COMPILE.mod) -o $@ -e $@ $^

%: %.cpp
  $(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@

%: %.sh
  cat $< >$@
  chmod a+x $@


blog comments powered by Disqus