1. 概述
Makefile,what??很多windows程序可能都没听说过
简单的说,Makefile是Unix/Linux环境下描述了整个工程的编译、连接等规则的文件,其主要包括三点:
1) 工程中的哪些源文件需要编译以及如何编译
2) 依赖库以及库所在的位置
3) 想得到什么:可执行文件?静态库?动态库?
项目中,我们会有很多源文件、头文件、依赖库文件、配置文件等等,通过Makefile定义规则来制定编译顺序,编译规则,编译依赖,甚至更复杂的功能,将极大的方便我们的开发,其最大的好处就是”自动化编译“,通过‘make’就可以方便的进行整个项目的编译工作。
2. 编译链接
从源码到可执行文件,具体步骤:
源码--->预处理--->编译--->汇编--->链接
我们常常把预处理、编译和汇编三个阶段统称为编译阶段,在这个阶段,编译器会检查程序语法、函数与变量是否声明等。
经过编译之后,unix/linux下,将得到.o文件(一般来说,每个源文件都能生成一个对应的.o文件),即object file(windows下即.obj文件),.o不能直接运行,我们需要将其合成可执行文件,这个过程就叫链接。在链接过程,链接器会在所有的.o文件中找寻函数的实现,如果找不到,则会报链接错误。
3.Makefile规则
Makefile只有一个规则:
target: prerequisites
command
target:即目标,它可以是可执行文件、可以是.o文件,也可以是一个标签,简单的说,它就是你要做的事情。
prerequisites:生成target所需要的条件,它可以是一个文件,也可以是另外一个target
command:具体执行的命令
解释如下:target这个目标依赖于prerequisites中的文件,其生成规则定义在command中。
更简单一点表达:如果prerequisites中任何一个文件的时间要比target文件更新的话,command所定义的命令就会执行。
eg:
=====makefile=====
#第一个规则
test: main.o hello.o
gcc main.o hello.o –o test
#第二个规则
main.o: main.c
gcc –c main.c
#第三个规则
hello.o: hello.c hello.h
gcc –c hello.c
#第四个规则
clean :
rm –rf *.o
rm –rf test
=====makefile=====
第一个规则:
test就是target, main.o和hello.o是prerequisites,'gcc main.o hello.o –o test’是command。
即:要生成test,就需要有main.o和hello.o,如果main.o或者hello.o文件的时间比test新(或者test文件不存在),则会执行命令’gcc main.o hello.o –o test’,
第二个规则:
target是main.o,main.c是prerequisites,’gcc –c main.c’是command
即:要生成test,就需要main.c,如果main.c文件的时间比main.o新,则会执行’gcc –c main.c’
第三个规则和第二个规则类似
第四个规则:
这里,target是clean,此处,clean并不是一个文件,而是一个动作的名字,它的执行,需要显示的在make命令后制定,例如,此处执行‘make clean’,将调用其后的command,即‘rm –rf *.o rm –rf test’,另外,此处没有prerequisites,即任何时候都执行command
我们来看下如果执行'make'会做什么:
1、make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
2、如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“test”这个文件,并把这个文件作为最终的目标文件。
3、如果test文件不存在,或是test所依赖的后面的[.o]文件的文件修改时间要比test这个文件新,那么,他就会执行后面所定义的命令来生成test这个文件。
4、如果test所依赖的.o文件存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。
5、依次类推,直到生成的所有的target都是最新的。
用户如果执行'make clean',由于其后面没有依赖,则执行command所定义的命令。
如果我们修改了代码main.c,然后执行‘make’,由于main.c时间比main.o新,那么main.o会重新编译生成,由于main.o文件的时间比test新,那么test也会重新生成。
4. 一个好用的Makefile模板
###################################################################### # makefile 模版 # ###################################################################### ###################项目路径和程序名称################################# DIR=$(shell pwd) BIN_DIR=$(DIR)/bin LIB_DIR=$(DIR)/lib SRC_DIR=$(DIR)/src INCLUDE_DIR=$(DIR)/include OBJ_DIR=$(DIR)/obj DEPS_DIR=$(DIR)/deps #PROGRAM=$(BIN_DIR)/test PROGRAM=$(BIN_DIR)/test ###################OBJ文件及路径############################################ EXTENSION=cpp OBJS=$(patsubst $(SRC_DIR)/%.$(EXTENSION), $(OBJ_DIR)/%.o,$(wildcard $(SRC_DIR)/*.$(EXTENSION))) DEPS=$(patsubst $(OBJ_DIR)/%.o, $(DEPS_DIR)/%.d, $(OBJS)) ###################include头文件路径################################## INCLUDE=\ -I$(INCLUDE_DIR) ###################lib文件及路径###################################### ###################编译选项及编译器################################### CC=g++ CFLAGS=-Wall -W -g LDFLAGS= ###################编译目标########################################### .PHONY: all clean rebuild all:$(OBJS) @echo $(DEPS_DIR) $(CC) -o $(PROGRAM) $(OBJS) $(LDFLAGS) $(DEPS_DIR)/%.d: $(SRC_DIR)/%.$(EXTENSION) $(CC) -MM $(INCLUDE) $(CFLAGS) {1}lt; | sed -e 1's,^,$(OBJ_DIR)/,' > $@ sinclude $(DEPS) $(OBJ_DIR)/%.o:$(SRC_DIR)/%.$(EXTENSION) $(CC) {1}lt; -o $@ -c $(CFLAGS) $(INCLUDE) rebuild: clean all clean: rm -rf $(OBJS) $(PROGRAM)
工作目录结构:
bin deps include lib Makefile obj src
5. 结语
以上只是Makefile的冰山一角,有兴趣的同学可以看下make的info pages。
Makefile可以很方便的维护中小型项目,但是,在项目大到一定程度,存在众多依赖之后,人力维护Makefile也是一件极为困难的事情。目前有一些自动化的工具,例如Automake,就是一个极好的工具,可参考:http://www.ibm.com/developerworks/cn/linux/l-makefile/。