Makefile语法简介
2013-10-17 10:21
281 查看
原文链接http://blog.163.com/zcym925@126/blog/static/534279222007101061757452/
Makefile 语法简介
Makefile 语法简介有稍稍在 Linux 下碰过程序设计的开发者应该会知道,make 是用来将程序代码、函式库、头文件及其它资源文件 build 成最终成果(即:最终的应用程序)的超强力辅助工具。
当然了,并不是非得动用到 make 才能 build 程序,或许有什么程序设计魔人喜欢什么都自己手动进行;但利用 make 及其参考档(输入档案)Makefile 将会让整个编译工作轻松许多。若您曾经打包过 Debian Package,那么应该会发现 debuan/rule 这个档案的语法和 Makefile 几乎是一模一样,所以学习 Makefile 的语法对于 Debian Package Maintainer 而言也是一门必要的功课。
Makefile 语法:
以下为 Makefile 的基本语法,
批注:
以 # 开头的即为批注。
变量宣告:(有人称之为宏)
语法:
MACRO = value |
在惯例上,Makefile 内部使用的变量名称使用小写;而使用者很可能从命令行自行另外指定数值的变量,像是 CFLAGS,则是使用大写。
在 Makefile 中,可利用 $(MACRO) 或 ${MACRO} 来存取已定义的变量。例:
tragets = foo $(targets): common.h gcc -o $(targets) foo.c |
foo: common.h gcc -o foo foo.c |
注意到,make 会将整个 Makefile 展开后,再决定变数的值。也就是说,变量的值将会是整个 Mackfile 中最后被指定的值。例:
x = foo y = $(x) bar x = xyz # y 的值为 xyz bar |
您可以利用 := 来避开这个问题。:= 表示变量的值决定于它在 Makefile 中的位置,而不是整个 Makefile 展开后最终的值。
x := foo y := $(x) bar x := xyz # y 的值为 foo bar |
?= 语法:
?= 是一个简化的语法:若变量未定义,则替它指定新的值。否则,采用原有的值。例:
FOO ?= bar |
+= 语法:
例:
CFLAGS = -Wall -g CFLAGS += -O2 |
define 语法:
使用 define 语法的唯一优点是它可以让变量直接使用『断行』。例:
define foo uname -a echo $$SHELL endef all: $(foo) |
foo = uname -a; echo $$SHELL all: $(foo) |
在 target 里另外指定变量的值
可以在 target 里另外指定变量的值。例:
foo = abc all: foo = xyz all: echo $(foo) # 此时,foo 的值为 xyz |
all: override foo = xyz
all: export foo = xyz
make 也可以存取环境变量。例:
all: @echo $(CFLAGS) |
可搭配 wildcard 指令在变量里展开 * ? [...] 等通配符。例:
objects=$(wildcard *.o) |
指示 make 如何进行编译。
主要语法:
target: dependencies <Tab>Commands |
target: dependencies; Commands <Tab>Commands |
target:所要建立的档案
dependencies:相依项目。make 会据此决定是否要重新编译 target。
Commands:建立 target 的指令。
在 Makefile 里并没有限定 Rule 的先后顺序。但默认上,make 会参考 all 这个目标项目,并依据它的 dependencies 来决定要建立哪些项目。若没有 all 项目,则会采用 Makefile 里的第一个项目。
target:(目标项目)
这个项目所要建立的档案,必须以 : 结尾。例:
foo.o: common.h gcc -c foo.c |
make 在编译时,若发现 target 比较新,也就是 dependencies 都比 target 旧,那么将不会重新建立 target,如此可以避免不必要的编译动作。
若该项目并非档案,则为 fake 项目。如此一来将不会建立 target 档案。但为了避免 make 有时会无去判断 target 是否为档案或 fake 项目,建议利用 .PHONY 来指定该项目为 fake 项目。例:
.PHONY: clean clean: rm *.o |
因为利用了 .PHONY 来指定 clean 为 fake 项目,所以 make 不会去检查目录中是否存在了一个名为 clean 的档案。如此也可以提升 make 的执行效率。
其它类以 .PHONY 的语法请参考:
GNU `make': 4.9 Special
Built-in Target Names
另外,如果某个非 fake 项目里的 dependencies 包含了 fake 项目的话,因为 make 一定会执行 fake 项目,这样一来,这个非 fake 项目一定也会被执行。这可能不是理想的做法。
dependencies:(相依性项目,以空白间隔)
dependencies 是指定在建立 target 之前,必须先检查的项目。可以不指定。例:
foo.o: common.h gcc -c foo.c |
相依性项目可以是 Makefile 中其它的 target。也因此,在建立该 target 之前,它会先检查在 dependencies 里所指定的所有 target。
Commands:(即为要执行的 Shell 指令)
必须以 <Tab> 开头。使用 Shell Script 语法。在 Makefile 里,只要以 <Tab> 开头都将会被视为 Shell Script 执行。
每条法则必须写在同一行。每条 Command 会启动一个新的 Shell,预设为 /bin/sh。若执行完某条 Command 但传回了错误值,make 就会中断执行。
因为每条 Command 会启动一个新的 Shell,所以有时执行的指令必须写在同一行,像是使用 if 来进行条件判断,此时可以用 ; 来分隔指令。例:
all: if [ -f foo ]; then rm foo; fi |
all: cd subdir; $(MAKE) |
为了避免这个问题,可以利用 && 来检查其中某个指令是否成功执行,再决定是否执行下个指令。例:
all: cd subdir && $(MAKE) |
@:不要显示执行的指令。
-:表示即使该行指令出错,也不会中断执行。
例:
.PHONY: clean clean: @echo "Clean..." -rm *.o |
而 make 只要遇到任何错误就会中断执行。但像是在进行 clean 时,也许根本没有任何档案可以 clean,因而 rm 会传回错误值,因而导致 make 中断执行。我们可以利用 - 来关闭错误中断功能,让 make 不会因而中断。
隐性法则:
在上例中的:
foo.o: common.h gcc -c foo.c |
foo.o: common.h |
您可以利用【空白指令】来避免 make 依据隐性法则而进行编译。例:
foo.o: common.h <Tab> |
$?: | 代表已被更新的 dependencies 的值。 也就是 dependencies 中,比 tragets 还新的值。 |
$@: | 代表 tragets 的值。 |
$<: | 代表第一个 dependencies 的值。 |
$* : | 代表 tragets 所指定的档案,但不包含扩展名。 |
print: foo1.c foo2.c foo3.c lpr -p $? touch print |
内部函数:
您可以在 Makefile 使用 make 所支持的一些内部函数。详情请参考:
GNU `make': 8 Functions for Transforming Text
条件判断:
可以在 Makefile 中使用以下的条件判断语法。但由于它们不是 rule,所以不可以 <Tab> 开头;但其后要执行的指令则必须以 <Tab> 开头,make 才会视其为 Shell 指令。
ifeq:(检查 value1, value2 是否相等)
ifeq (value1, value2) ... else ... endif |
ifneq (value1, value2) ... else ... endif |
ifdef variable ... else ... endif |
ifdef variable ... else .... endif |
将外部档案引入 Makefile 中。可以视为直接在此将该档案全数插入 Makefile 中。
例:
include foo.in |
可以同时引入多个档案、使用变量 $(MACRO) 或是使用通配符(* ? 或 [...])。例:
include foo.in common*.in $(MAKEINCS) |
如果该项目有多个目录,且每一个目录中都有 Makefile,则利用以下指令来进入子目录并进行编译:
cd dir;$(MAKE) |
SUBDIRS = dir1 dir2 dir3 all: for i in $(SUBDIRS); do (cd $$i; make); done clean: for i in $(SUBDIRS); do (cd $$i; make clean); done install: for i in $(SUBDIRS); do (cd $$i; make install); done |
可以用 make 的参数来盖过 Makefile 里,用变数所指定的参数。例:
make CFLAGS="-g -O2" |
override CFLAGS = -Wall -g |
make clean |
相关文章推荐
- Makefile 语法简介
- makefile语法简介
- makefile语法简介
- Makefile 语法简介
- Makefile 语法简介
- Makefile语法简介
- makefile 语法和写法
- linux内核学习(6)Kbuild Makefile语法分析 .
- JavaScript简介与基础语法
- Velocity脚本基本语法简介
- Linux下Makefile编写语法
- Markdown语法简介
- Google语法简介
- makefile的语法及写法
- Razor基础语法简介
- Makefile 语法分析
- 跟我一起写Makefile(11)--- 使用条件判断(示例+语法)
- 【ES6学习】— (6)class定义类语法与Module模块化简介
- yara语法简介
- makefile的语法及写法(一)