红联Linux门户
Linux帮助

Makefile,Linux程序员你伤不起

发布时间:2014-12-14 15:43:52来源:linux网站作者:yfkiss

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,就是一个极好的工具。