Makefile介绍和编写
makefile是一个辅助程序编译的文件,在其中可以申明编译所需要的依赖和规则。
# 1. 为什么需要makefile文件
- 常见的编译多个文件:
g++ -o out main.cpp example1.cpp ...
但是,在一个大的项目中,开发者常常会遇到:
## 1.1 有时候程序的依赖和链接是复杂的,需要手动处理;
## 1.2 项目会包含很多源文件,编译过程会很费时间;Makefile 支持多线程并发操作,并且可以编译特定文件(例如修改过的文件);
## 1.3 不同的源文件需要不同的编译器。
# 2. Makefile 规则
targets : prerequisites
command
#targets: 目标文件;
#prerequisites:依赖文件;
#command:需要执行的shell命令;
- 例子
main.o : main.cpp
g++ -c -I $(INCLUDE) main.cpp
# 3. 变量
## 3.1 Makefile 有四种基本变量赋值方式
-
简单赋值 ( := ) :只对当前语句的变量有效。
-
递归赋值 ( = ): 所有目标变量相关的其他变量都受影响。
-
条件赋值 ( ?= ): 如果变量未定义,则使用符号中的值定义变量。如果该变量已经赋值,则该赋值语句无效。
-
追加赋值 ( += ) :原变量添加一个新的值,空格分割;
## 3.2 变量的引用
- "$(variable)" 或者是 "${variable}"
OBJ=main.o test.o test1.o test2.o
main:$(OBJ)
gcc -o main $(OBJ)
## 3.3 预定义变量
-
$*:不包含扩展名的目标文件名称。
-
$+:所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件。
-
$<:第一个依赖文件的名称。
-
$?:所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标的创建日期晚。
-
$@:规则定义的目标文件。
-
$^:所有的依赖文件,空格分开,会去重。
-
例子
main:main.o
gcc -o $@ $^
# 4. 搜索路径
- Makefile文件中通过VPATH 或vpath设置搜索路径。
## 4.1 VPATH 设置环境变量
VPATH := src car
或
VPATH := src:car
VPATH=src car
main:main.o
gcc -o $@ $^
## 4.2 vpath 设置特定搜索模式和路径。
vpath *.c src car
或
vpath *.c src : car
vpath *.c src car
main:main.o
gcc -o $@ $^
# 5. 条件判断
-
ifeq:是否相等,相等返回 true,不相等返回 false。
-
ifneq:是否相等,不相等返回 true,相等返回 false。
-
ifdef:是否定义过,定义过返回返回 true,没有定义过返回 false。
-
ifndef:是否定义过,没有定义过返回 true,有定义过返回 false。
# 6. 函数调用
$(<function> <arguments>) 或
${<function> <arguments>}
- 例子
OBJ=$(patsubst %.c,%.o,1.c 2.c 3.c)
test:
@echo $(OBJ)
# 7. makefile文件模版
# makefile template
INCLUDE = ./include
binPath=$(HOME)/bin
OBJS = main.o test1.o test2.o
HH = ./include/test1.h ./include/teat2.h
ifndef CXX
CXX = $(CXX) $(CXXFLAGS)
endif
CXXFLAGS=-pipe \
-g \
-std=c++11
Tool : $(OBJS)
$(CXX) $(CXXFLAGS) -o Tool $(OBJS)
main.o : main.cpp
$(CXX) $(CXXFLAGS) -c -I $(INCLUDE) main.cpp
test1.o : test1.cpp $(HH)
$(CXX) $(CXXFLAGS) -c -I $(INCLUDE) test1.cpp
test2.o : test2.cpp $(HH)
$(CXX) $(CXXFLAGS) -c -I $(INCLUDE) test2.cpp
.PHONY : clean
clean :
@rm $(OBJS)
@mv $@ ${BIN}
@echo "Finish !"
-
多个命令之间要使用分号隔开,Makefile 中的任何命令都要以
tab
键开始。 -
make执行时,查找的文件顺序是:"GNUmakefile" 、"makefile" 、"Makefile"。
-
Makefile文件中第一个编译规则目标文件一般就是整个编译的目标文件
-
Tool是整个编译的目标文件; main.o、test1.o 和 test2.o是中间文件。
-
编译时,处理第一个规则(
$(CXX) $(CXXFLAGS) -o Tool $(OBJS)
)的时候,会根据依赖关系先生成依赖文件(main.o test1.o test2.o
) -
例子中使用了通配符(
*.c
)。当通配符和变量联合使用时,需要函数 "wildcard"。
OBJ=$(wildcard *.c)
test:$(OBJ)
gcc -o $@ $^
- 隐含规则中使用的变量:
# 命令的变量
CXX:C++编译程序
AR:函数库打包程序
AS:汇编语言编译程序
CC:C编译程序
CXX:C++编译程序
CO:从 RCS 中提取文件的程序。
CPP:C程序的预处理器
FC:Fortran 和 Ratfor 的编译器和预处理程序
GET:从SCCS文件中扩展文件的程序
LEX:Lex方法分析器程序
PC:Pascal 语言编译器
YACC:Yacc 文法分析器(针对于C程序)
YACCR:Yacc 文法分析器(针对于Ratfor程序)
# 命令参数的变量
CFLAGS: C语言编译器参数
CXXFLAGS: C++语言编译器参数
# 参考:
[GNU make