参看文档:《跟我一起写 Makefile》
Makefile的基本规则:
target ... : prerequisites ... command ... ...target 也就是一个目标文件,可以是 Object File,也可以是执行文件。还可以是一个标签(Label),对于标签这种特性,在后续的“伪目标”章节中会有叙述。 prerequisites 就是,要生成那个 target 所需要的文件或是目标。 command 也就是 make 需要执行的命令。(任意的 Shell 命令)
举一个例子:
*表示通配符main: main.o input.o calcu.o gcc -o main main.o input.o calcu.o main.o: main.c gcc -c main.c input.o: input.c gcc -c input.c calcu.o: calcu.c gcc -c calcu.c clean: rm *.o rm mainmake编译如下: make clean如下: 下面说明一个一个规则,将上面的Makefile代码进行简化:
1、Makefile中使用变量:
objects = main.o input.o calcu.o main: $(objects) gcc -o main $(objects) main.o: main.c gcc -c main.c input.o: input.c gcc -c input.c calcu.o: calcu.c gcc -c calcu.c clean: rm $(objects) rm main
2、让Makefile自动推导:
objects = main.o input.o calcu.o main: $(objects) main.o: main.c input.o: input.c calcu.o: calcu.c clean: rm $(objects) rm main
3、清空目标文件的规则:
.PHONY表示一个“伪目标”,也是一种Makefile编写规范objects = main.o input.o calcu.o main: $(objects) main.o: main.c input.o: input.c calcu.o: calcu.c .PHONY : clean clean: rm $(objects) rm main
Makefile总述:
1、显式规则: 显式规则说明了,如何生成一个或多的的目标文件。 2、隐晦规则: 由于我们的 make 有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写 Makefile,这是由 make 所支持的。 3、变量的定义: 在 Makefile 中我们要定义一系列的变量,变量一般都是字符串,这个有点你 C 语言中的宏,当 Makefile 被执行时,其中的变量都会被扩展到相应的引用位置上。 4、文件指示: 其包括了三个部分,一个是在一个 Makefile 中引用另一个 Makefile,就像 C 语言中的include 一样;另一个是指根据某些情况指定 Makefile 中的有效部分,就像 C 语言中的预编译#if 一样;还有就是定义一个多行的命令。 5、注释: Makefile 中只有行注释,和 UNIX 的 Shell 脚本一样,其注释是用“#”字符,这个就像 C/C++中的“//”一样。如果你要在你的 Makefile 中使用“#”字符,可以用反斜框进行转义,如:“\#”。 值得一提的是,在 Makefile 中的命令,必须要以[Tab]键开始。引入其他的Makefile:
在 Makefile 使用 include 关键字可以把别的 Makefile 包含进来,这很像 C 语言的#include,被包含的文件会原模原样的放在当前文件的包含位置。include 的语法是: include filename 可以是当前操作系统 Shell 的文件模式(可以保含路径和通配符) 在 include前面可以有一些空字符,但是绝不能是[Tab]键开始。include 和可以用一个或多个空格隔开。举个例子, 有这样几个 Makefile:a.mk、b.mk、c.mk,还有一个文件叫foo.make,以及一个变量$(bar),其包含了 e.mk 和 f.mk,那么,下面的语句: include foo.make *.mk $(bar) 等价于: include foo.make a.mk b.mk c.mk e.mk f.mk make 命令开始时,会把找寻 include 所指出的其它 Makefile,并把其内容安置在当前的位。就好像 C/C++的#include 指令一样。如果文件都没有指定绝对路径或是相对路径的话,make 会在当前目录下首先寻找,如果当前目录下没有找到,那么,make 还会在下面的几个目录下找: 1、如果 make 执行时,有“-I”或“--include-dir”参数,那么 make 就会在这个参数 所指定的目录下去寻找。 2、如果目录/include(一般是:/usr/local/bin 或/usr/include)存在的话,make 也会去找。如果有文件没有找到的话,make 会生成一条警告信息,但不会马上出现致命错误。它会继续载入其它的文件,一旦完成 makefile 的读取,make 会再重试这些没有找到,或是不能读取的文件,如果还是不行,make 才会出现一条致命信息。如果你想让 make不理那些无法读取的文件,而继续执行,你可以在 include 前加一个减号“-”。 如: -include 其表示,无论 include 过程中出现什么错误,都不要报错继续执行。和其它版本 make兼 容的相关命令是 sinclude,其作用和这一个是一样的。文件搜索:
在一些大的工程中,有大量的源文件,我们通常的做法是把这许多的源文件分类,并存放在不同的目录中。所以,当 make 需要去找寻文件的依赖关系时,你可以在文件前加上路 径,但最好的方法是把一个路径告诉 make,让 make 在自动去找。 Makefile 文件中的特殊变量“VPATH”就是完成这个功能的,如果没有指明这个变量,make 只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么,make 就会在当当前目录找不到的情况下,到所指定的目录中去找寻文件了。 VPATH = src:../headers 上面的的定义指定两个目录,“src”和“../headers”,make 会按照这个顺序进行搜索。目录由“冒号”分隔。(当然,当前目录永远是最高优先搜索的地方) 例如: vpath %.h ../headers 该语句表示,要求 make 在“../headers”目录下搜索所有以“.h”结尾的文件。(如果某文件在当前目录没有找到的话)使用变量:
1、变量:$
2、可使用变量中的变量:
先看第一种方式,也就是简单的使用“=”号,在“=”左侧是变量,右侧是变量的值,右侧变量的值可以定义在文件的任何一处,也就是说,右侧中的变量不一定非要是已定义好的值, 其也可以使用后面定义的值。如:foo = $(bar) bar = $(ugh) ugh = Huh? all: echo $(foo)我们执行“make all”将会打出变量$(foo)的值是“Huh?”( $(foo)的值是$(bar),$(bar)的值是$(ugh),$(ugh)的值是“Huh?”)可见,变量是可以使用后面的变量来定义的。 为了避免上面的这种方法,我们可以使用 make 中的另一种用变量来定义变量的方法。 这种方法使用的是“:=”操作符,如:
x := foo y := $(x) bar x := later其等价于:
y := foo bar x := later值得一提的是,这种方法,前面的变量不能使用后面的变量,只能使用前面已定义好了的变量。如果是这样:
y := $(x) bar x := foo那么,y 的值是“bar”,而不是“foo bar”。
3、?=
FOO ?= bar其含义是,如果 FOO 没有被定义过,那么变量 FOO 的值就是“bar”,如果 FOO 先前被定义过,那么这条语将什么也不做
4、变量值的替换
我们可以替换变量中的共有的部分,其格式是“$(var:a=b)”或是“${var:a=b}”,其意思是,把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串。这里的“结尾”意思是“空格”或是“结束符”。 看一个示例吧:foo := a.o b.o c.o bar := $(foo:.o=.c)这个示例中,我们先定义了一个“$(foo)”变量,而第二行的意思是把“$(foo)”中所有以“.o”字串“结尾”全部替换成“.c”,所以我们的“$(bar)”的值就是“a.c b.c c.c”。 另外一种变量替换的技术是以“静态模式”(参见前面章节)定义的,如:
foo := a.o b.o c.o bar := $(foo:%.o=%.c)这依赖于被替换字串中的有相同的模式,模式中必须包含一个“%”字符,这个例子同样让$(bar)变量的值为“a.c b.c c.c”。
5、合成使用
再来看看结合第一种技术的例子:a_objects := a.o b.o c.o 1_objects := 1.o 2.o 3.o这个例子中,如果$(a1)的值是“a”的话,那么,$(sources)的值就是“a.c b.c c.c”;如果$(a1)的值是“1”,那么$(sources)的值是“1.c 2.c 3.c”。
sources := $($(a1)_objects:.o=.c)
6、追加变量值
可以使用“+=”操作符给变量追加值,如:objects = main.o foo.o bar.o utils.o objects += another.o于是,$(objects)值变成:“main.o foo.o bar.o utils.o another.o”(another.o被追加进去了)
7、override指示符
如果有变量是通常 make的命令行参数设置的,那么 Makefile中对这个变量的赋值会被忽略。如果你想在 Makefile 中设置这类参数的值,那么,你可以使用“override”指示符。其语法是:override = override := override +=
8、环境变量
make 运行时的系统环境变量可以在 make 开始运行时被载入到 Makefile 文件中判断语句
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可见,在上面示例的这个规则中,目标“foo”可以根据变量“$(CC)”值来选取不同的函数库来编译程序。 从上面的示例中看到三个关键字:ifeq、else 和 endif。ifeq 的意思表示条件语句的开始,并指定一个条件表达式,表达式包含两个参数,以逗号分隔,表达式以圆括号括起。else 表示条件表达式为假的情况。endif 表示一个条件语句的结束,任何一个条件表达式都应该以 endif 结束。 ifeq:if equal 标签:foo,bar,变量,make,Makefile,学习,main From: https://www.cnblogs.com/lethe1203/p/18079327