Makefile 简单引入

本贴最后更新于 1681 天前,其中的信息可能已经时移俗易

Targets and dependencies

make 程序试图通过一个 target 带动起所有 target 的依赖保持更新. 这些依赖或许还会有更多的依赖关系. 所以当在处理一个"Makefile"的时候一个潜在的复杂的依赖关系图就会形成. 一个简单的"Makefile"长这样:

all: foo 
foo: foo.o bar.o baz.o
.c.o: 
       $(CC) $(CFLAGS) -c $< -o $@
.l.c:
       $(LEX) $< && mv lex.yy.c $@

我们也可以画出来这个依赖关系图:

graph LR; foo-->all foo.o-->foo bar.o-->foo baz.o-->foo foo.c-->foo.o bar.c-->bar.o baz.l-->baz.c baz.c-->baz.o

"all"这个 target, 是一个文件名. 必须要写一些规则来通过规则来生成这个文件, 并且保持更新.
当在依赖图中找到叶子结点时, "Makefile" 必须包含一系列的 shell 命令使得依赖者和被依赖者保持更新. 使得 make 用户很恼火的是, 更新意思是说依赖者有着更新的时间戳, 相较于 target. 此外, 每个这样的 shell 命令都在它们自己的子 shell 中运行, 除非说是 Makefile 对 make 提出了明确的指示, 否则每一个命令必须以 0 退出码来说明执行成功了.
Target 规则也可以是无条件的执行, 这种情况是指定的 target 是没有依赖关系的. 我们熟悉的不能再熟悉的:

clean:
      	-rm *.o core 

Makefile syntax

"Makefile"有着比较特殊的语法规则,这也是困扰住初学者的原因之一. 那里有着许多 make 的实现, 一些还提供不可移植的扩展. 下面对语法进行简单的阐述, 为了便于可移植性, 可能会比你自己习惯的更加严格.
注释以"#"开头, 它们能出现在任何地方, 除了在命令序列中--因为会当成命令去执行了. 下面的这个"Makefile"展示了三个独立的 target 在自己名下的依赖关系:

 target1:  dep1 dep2 ... depN
     <tab>   cmd1
     <tab>   cmd2
     <tab>   ... 
     <tab> cmdN

 target2:  dep4 dep5
     <tab>   cmd1
     <tab>   cmd2 

 dep4 dep5:
     <tab>   cmd1 

Target 规则是在行的开头开始,紧接着就是":", 然后后面跟着的就是以空格分割的依赖. 接下来几行几行的就是执行的 shell 命令. (默认是 Bash). 需要注意的是, 每一行都必须是以 tab 进行缩紧. 这个是新人最容易犯的错误.
这些 shell 命令的前面是可以加"@"前缀, 表示的就是使命令在被执行前不被回显, 在 make 执行时候, 输出的信息中, 不要显示此行命令. 也可以加上"-", 就是, 忽略当前此行命令执行时候所遇到的错误. 而如果不忽略, make 在执行命令的时候, 如果遇到 error, 会退出执行的, 加上减号的目的, 是即便此行命令执行中出错, 比如删除一个不存在的文件等, 那么也不要管, 继续执行 make.

Macros

一系列非常有用的宏贯穿着整个 Makefile. 宏是用"$"打头, 就像是 shell 变量:

$(CC) $(CFLAGS) -c $< -o $@

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...