Makefile 及其工作原理
2015-04-23 00:00
309 查看
用这个方便的工具来更有效的运行和编译你的程序。
当你需要在一些源文件改变后运行或更新一个任务时,通常会用到
本文将通过一些基础和进阶的示例来展示
总结一下,一个典型的规则的语法为:
再回到上面的示例中,当
在
下面删除掉
定义变量最简单的方式是使用
以
变量
规则:
规则:
最后,在
下面是重写后的
via: https://opensource.com/article/18/8/what-how-makefile
当你需要在一些源文件改变后运行或更新一个任务时,通常会用到
make工具。
make工具需要读取一个
Makefile(或
makefile)文件,在该文件中定义了一系列需要执行的任务。你可以使用
make来将源代码编译为可执行程序。大部分开源项目会使用
make来实现最终的二进制文件的编译,然后使用
make install命令来执行安装。
本文将通过一些基础和进阶的示例来展示
make和
Makefile的使用方法。在开始前,请确保你的系统中安装了
make。
基础示例
依然从打印 “Hello World” 开始。首先创建一个名字为myproject的目录,目录下新建
Makefile文件,文件内容为:
在say_hello: echo "Hello World"
myproject目录下执行
make,会有如下输出:
在上面的例子中,“say_hello” 类似于其他编程语言中的函数名。这被称之为目标target。在该目标之后的是预置条件或依赖。为了简单起见,我们在这个示例中没有定义预置条件。$ makeecho "Hello World"Hello World
echo ‘Hello World'命令被称为步骤recipe。这些步骤基于预置条件来实现目标。目标、预置条件和步骤共同构成一个规则。
总结一下,一个典型的规则的语法为:
作为示例,目标可以是一个基于预置条件(源代码)的二进制文件。另一方面,预置条件也可以是依赖其他预置条件的目标。目标: 预置条件<TAB> 步骤
目标并不要求是一个文件,也可以只是步骤的名字,就如我们的例子中一样。我们称之为“伪目标”。final_target: sub_target final_target.c Recipe_to_create_final_target sub_target: sub_target.c Recipe_to_create_sub_target
再回到上面的示例中,当
make被执行时,整条指令
echo "Hello World"都被显示出来,之后才是真正的执行结果。如果不希望指令本身被打印处理,需要在
echo前添加
@。
重新运行say_hello: @echo "Hello World"
make,将会只有如下输出:
接下来在$ makeHello World
Makefile中添加如下伪目标:
generate和
clean:
随后当我们运行say_hello: @echo "Hello World"generate: @echo "Creating empty text files..." touch file-{1..10}.txtclean: @echo "Cleaning up..." rm *.txt
make时,只有
say_hello这个目标被执行。这是因为
Makefile中的第一个目标为默认目标。通常情况下会调用默认目标,这就是你在大多数项目中看到
all作为第一个目标而出现。
all负责来调用它他的目标。我们可以通过
.DEFAULT_GOAL这个特殊的伪目标来覆盖掉默认的行为。
在
Makefile文件开头增加
.DEFAULT_GOAL:
.DEFAULT_GOAL := generate
make会将
generate作为默认目标:
顾名思义,$ makeCreating empty text files...touch file-{1..10}.txt
.DEFAULT_GOAL伪目标仅能定义一个目标。这就是为什么很多
Makefile会包括
all这个目标,这样可以调用多个目标。
下面删除掉
.DEFAULT_GOAL,增加
all目标:
运行之前,我们再增加一些特殊的伪目标。all: say_hello generatesay_hello: @echo "Hello World"generate: @echo "Creating empty text files..." touch file-{1..10}.txtclean: @echo "Cleaning up..." rm *.txt
.PHONY用来定义这些不是文件的目标。
make会默认调用这些伪目标下的步骤,而不去检查文件名是否存在或最后修改日期。完整的
Makefile如下:
.PHONY: all say_hello generate cleanall: say_hello generatesay_hello: @echo "Hello World"generate: @echo "Creating empty text files..." touch file-{1..10}.txtclean: @echo "Cleaning up..." rm *.txt
make命令会调用
say_hello和
generate:
$ makeHello WorldCreating empty text files...touch file-{1..10}.txt
clean不应该被放入
all中,或者被放入第一个目标中。
clean应当在需要清理时手动调用,调用方法为
make clean。
现在你应该已经对$ make cleanCleaning up...rm *.txt
Makefile有了基础的了解,接下来我们看一些进阶的示例。
进阶示例
变量
在之前的实例中,大部分目标和预置条件是已经固定了的,但在实际项目中,它们通常用变量和模式来代替。定义变量最简单的方式是使用
=操作符。例如,将命令
gcc赋值给变量
CC:
这被称为递归扩展变量,用于如下所示的规则中:CC = gcc
你可能已经想到了,这些步骤将会在传递给终端时展开为:hello: hello.c ${CC} hello.c -o hello
gcc hello.c -o hello
${CC}和
$(CC)都能对
gcc进行引用。但如果一个变量尝试将它本身赋值给自己,将会造成死循环。让我们验证一下:
此时运行CC = gccCC = ${CC}all: @echo ${CC}
make会导致:
为了避免这种情况发生,可以使用$ makeMakefile:8: *** Recursive variable 'CC' references itself (eventually). Stop.
:=操作符(这被称为简单扩展变量)。以下代码不会造成上述问题:
CC := gccCC := ${CC}all: @echo ${CC}
模式和函数
下面的Makefile使用了变量、模式和函数来实现所有 C 代码的编译。我们来逐行分析下:
# Usage:# make # compile all binary# make clean # remove ALL binaries and objects.PHONY = all cleanCC = gcc # compiler to useLINKERFLAG = -lmSRCS := $(wildcard *.c)BINS := $(SRCS:%.c=%)all: ${BINS}%: %.o @echo "Checking.." ${CC} ${LINKERFLAG} $< -o $@%.o: %.c @echo "Creating object.." ${CC} -c $<clean: @echo "Cleaning up..." rm -rvf *.o ${BINS}
以
#开头的行是评论。
.PHONY = all clean行定义了
all和
clean两个伪目标。
变量
LINKERFLAG定义了在步骤中
gcc命令需要用到的参数。
SRCS := $(wildcard *.c):
$(wildcard pattern)是与文件名相关的一个函数。在本示例中,所有 “.c”后缀的文件会被存入
SRCS变量。
BINS := $(SRCS:%.c=%):这被称为替代引用。本例中,如果
SRCS的值为
'foo.c bar.c',则
BINS的值为
'foo bar'。
all: ${BINS}行:伪目标
all调用
${BINS}变量中的所有值作为子目标。
规则:
下面通过一个示例来理解这条规则。假定%: %.o @echo "Checking.." ${CC} ${LINKERFLAG} $< -o $@
foo是变量
${BINS}中的一个值。
%会匹配到
foo(
%匹配任意一个目标)。下面是规则展开后的内容:
如上所示,foo: foo.o @echo "Checking.." gcc -lm foo.o -o foo
%被
foo替换掉了。
$<被
foo.o替换掉。
$<用于匹配预置条件,
$@匹配目标。对
${BINS}中的每个值,这条规则都会被调用一遍。
规则:
之前规则中的每个预置条件在这条规则中都会都被作为一个目标。下面是展开后的内容:%.o: %.c @echo "Creating object.." ${CC} -c $<
foo.o: foo.c @echo "Creating object.." gcc -c foo.c
最后,在
clean目标中,所有的二进制文件和编译文件将被删除。
下面是重写后的
Makefile,该文件应该被放置在一个有
foo.c文件的目录下:
关于# Usage:# make # compile all binary# make clean # remove ALL binaries and objects.PHONY = all cleanCC = gcc # compiler to useLINKERFLAG = -lmSRCS := foo.cBINS := fooall: foofoo: foo.o @echo "Checking.." gcc -lm foo.o -o foofoo.o: foo.c @echo "Creating object.." gcc -c foo.cclean: @echo "Cleaning up..." rm -rvf foo.o foo
Makefile的更多信息,GNU Make 手册提供了更完整的说明和实例。
via: https://opensource.com/article/18/8/what-how-makefile
相关文章推荐
- 详解JSP 中Spring工作原理及其作用
- Java规则引擎工作原理及其应用
- SPI协议及其工作原理浅析
- 机制设计:谷歌智能出价及其工作原理
- live555 实现一个最简单的RTSP服务器及其makefile
- 路由器及其工作原理
- http的介绍及其工作原理
- Struts2工作原理及其核心思想(二)
- Struts2的优势及其工作原理
- makefile自动化变量及其说明
- makefile自动化变量及其说明
- Ajax及其工作原理
- SPI协议及其工作原理浅析
- Spring工作原理及其作用
- AppWizard及其工作原理(转载)
- (3) iphone 开发 从应用程序看UITableView的:分组,分区,索引,工作原理及其变换法则,plist文件数据定义规则
- 浅析Spring MVC的工作原理及其与Spring的关系
- sql全文索引的工作原理,及其优化
- SPI协议及其工作原理浅析
- 索引的工作原理及其优缺点