在 Linux(unix )环境下使用GNU 的make工具能够比较容易的构建一个属于你自己的工程,整个工程的编译只需要一个命令就可以完成编译、连接以至于最后的执行。不过这需要我们投入一些时间去完成一个或者多个称之为Makefile
文件的编写。所要完成的Makefile 文件描述了整个工程的编译、连接等规则。
makefile 带来的好处就是——“自动化编译”,一旦写好,只需要一个make 命令,整个工程完全自动编译,极大的提高了软件开发的效率。
默认的情况下,make命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、“makefile”、“Makefile”的文件,找到 后就解释并执行该文件,如果找不到就提示错误并退出。一般Makeifle文件名我们会用Makefile或makefile,而不会使用 GNUmakefile。接下来我们以之前的静态库和动态库为例讲解makefile的编写和使用。
Makefile 主要的 5个部分 (显示规则, 隐晦规则, 变量定义, 文件指示, 注释)
- 变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点像C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。
- 显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。 刚才写的疑似shell脚本的Makefile全部都是显示规则。
- 隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。
- 文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样。
- 注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符。
Makefile基本格式如下:
#以'#'开头的行表示注释
#定义变量VAR为test,可以使用后面定义的变量
VAR = test
#定义变量VAR为test,只能使用前面定义好的变量
VAR := test
# target第一条目标为总的目标,
# depend依赖可以是文件(目录)或为其他目标
# 动作可以是Linux命令,动作的那一行必须以TAB键开头
#目标必须得有:依赖和动作有一个即可
target: depend1 depend2 depend3 ...
[TAB] action1
[TAB] action2
#每个动作必须以tab开头
target1:
[TAB] action1
[TAB] action2
- target :总目标文件, 可以是 Object File, 也可以是可执行文件;
- depend:生成 target 所需要的文件或者目标;
- action:make需要执行的命令 (任意的shell命令), Makefile中的命令必须以
[tab]
开头。
常用命令:
make
找makefile或Makefile文件执行总的目标
make clean
执行makefile文件中的clean目标
make -C directory
进入到directory文件夹中去执行总的目标
make clean -C direcotry
进入到directory文件夹中去执行clean目标
make -f comm_makefile
通过-f选项指定一个makefile文件
make VAR=value
给Makefile传一个参数VAR,其值为value
Makefile 隐晦规则
由于伪目标的特性:总是被执行
这里只列一个和编译C相关的,
编译C/C++时,xx.o 的目标会自动推导为 xx.c/ xx.cpp
# Makefile 中
main : main.o
gcc -o main main.o
#会自动变为:
main : main.o
gcc -o main main.o
#main.o 这个目标是隐含生成的
main.o: main.c
gcc -c main.c
自动变量
直接上代码比较直观:
#最后形成的Makefile
INCL=-I${HOME}/incl
BIN=$(HOME)/bin
OBJ1=hellocpp.o
OBJ2=hello.o
#这个隐晦规则其实就是告诉大家,
#后缀为cpp的文件怎么编译成.o 后缀为c的文件怎么编译成.o
.SUFFIXES: .cpp .c
.cpp.o:
g++ ${INCL} -c $<
.c.o:
gcc ${INCL} -c $<
all: hellocpp hello
#C++编译
hellocpp:${OBJ1}
@echo "============开始编译============"
g++ -o $@ $?
@rm -f ${OBJ1}
@mv $@ ${BIN}
@echo "============编译结束============"
@echo ""
#C编译
hello:${OBJ2}
@echo "============开始编译============"
gcc -o $@ $?
@rm -f ${OBJ2}
@mv $@ ${BIN}
@echo "============编译结束============"
@echo ""
运行结果如图:
更为详细的makefile使用,可以参考下面链接: