当个文件可以用gcc或g++直接编译,如果有几十甚至上千文件的时候,如果用gcc一行行编译那会累死,为了革命事业,先辈们发明了make
所谓工程管理器:就是管理工程的工具,它能自动能根据文件时间戳自动发现更新过的文件而减少编译的工作量,同时通过读入Makefile文件来执行大量的编译工作。
makefile格式
target: dependency_files 目标项:依赖项
<TAB>command 必须以tab开头,负责它不嬲你
如,有makefile文件,内容如下:
|
使用make编译
对于该makefile文件,程序make处理过程如下:
l make程序首先读到第1行的目标文件main.exe和它的两个依赖文件main.o和func.o;然后比较文件main.exe和main.o/func.o的产生时间,如果main.exe比main.o/func.o旧的话,则执行第2条命令,以产生目标文件main.exe。
l 在执行第2行的命令前,它首先会查看makefile中的其他定义,看有没有以第1行main.o和func.o为目标文件的依赖文件,如果有的话,继续按照(1)、(2)的方式匹配下去。
l 根据(2)的匹配过程,make程序发现第3行有目标文件main.o依赖于main.cpp,则比较目main.o与它的依赖文件main.cpp的文件新旧,如果main.o比main.cpp旧,则执行第4行的命令以产生目标文件main.o.在执行第4条命令时,main.cpp在文件makefile不再有依赖文件第定义,make程序不再继续往下匹配,而是执行第4条命令,产生目标文件main.o
l 目标文件func.o按照上面的同样方式判断产生.
l 执行(3)、(4)产生完main.o和func.o以后,则第2行的命令可以顺利地执行了,最终产生了第1行的目标文件main.exe。
1.1. 特殊处理与伪目标
.PHONY是makefile文件的关键字,表示它后面列表中的目标均为伪目标,这样,不论文件b是否存在,执行make b时,echo ‘b’都将被调用。
伪目标通常用在清理文件、强制重新编译等情况下,例如:
|
执行make clean将清除掉文件夹中的二进制可执行文件
执行make rebuild则先执行清除,再重新编译连接。
1.2. 变量、函数与规则
随着软件项目的变大、变复杂,源文件也越来越多,如果采用前面的方式写makefile文件,将会使makefile也变得复杂而难于维护。通过make支持的变量定义、规则和内置函数,可以写出通用性较强的makefile文件,使得同一个makefile文件能够适应不能的项目。
变量:用来代替一个文本字符串
定义变量的2方法:
变量名=变量值 递规变量展开(几个变量共享一个值)
变量名:=变量值 简单变量展开(类似于C++的赋值)
使用变量的一般方法:$(变量名)=??? 赋值
???=$(变量名) 引用
例:
|
变量分为:用户自定义变量,预定义变量,自动变量,环境变量
自动变量: 指在使用的时候,自动用特定的值替换。
常用的有:
变量 | 说明 |
$@ | 当前规则的目标文件 |
$< | 当前规则的第一个依赖文件 |
$^ | 当前规则的所有依赖文件,以逗号分隔 |
$? | 规则中日期新于目标文件的所有相关文件列表,逗号分隔 |
$(@D) | 目标文件的目录名部分 |
$(@F) | 目标文件的文件名部分 |
预定义变量:内部事先定义好的变量,但是它的值是固定的,并且有些的值是为空的。
AR:库文件打包程序默认为ar
AS:汇编程序,默认为as
CC:c编译器默认为cc
CPP:c预编译器,默认为$(CC) –E
CXX:c++编译器,默认为g++
RM:删除,默认为rm –f
ARFLAGS:库选项,无默认
ASFLAGS:汇编选项,无默认
CFLAGS:c编译器选项,无默认
CPPFLAGS:c预编译器选项,无默认
CXXFLAGS:c++编译器选项
根据内部变量,可以将makefile改写为:
|
规则分为:普通规则,隐含规则,模式规则
隐含规则:
.c变.o
.cc或.c变.o
OBJS = main.o fun.o
CC = gcc
CFLAGS = -Wall -O -g
main.exe: $(OBJS)
$(CC) $^ -o $@
模式规则:通过匹配模式找字符串, %匹配1或多个任意字符串
%.o: %.cpp任何目标文件的依赖文件是与目标文件同名的并且扩展名为.cpp的文件
%.o: %.cpp
$(CC) -o $@ -c $^
函数:
wildcard搜索当前目录下的文件名,展开成一列所有符合由其参数描述的文件名,文件间以空格间隔。SOURCES = $(wildcard *.cpp)把当前目录下所有'.cpp'文件存入变量 SOURCES里。
字符串替换函数:$(patsubst,要查找的子串,替换后的目标子串,源字符串)将源字符串(以空格分隔)中的所有要查找的子串替换成目标子串。如OBJS = $(patsubst %.cpp,%.o,$(SOURCES))
把SOURCES中'.cpp' 替换为'.o' 。
$(addprefix 前缀,源字符串)函数把第二个参数列表的每一项前缀上第一个参数值
下面是一个较为通用的makefile:
DIR := ./debug
EXE := $(DIR)/Main.exe
CC := g++
LIBS :=
SRCS := $(wildcard *.cpp) $(wildcard *.c)$(wildcard *.cc)
OCPP := $(patsubst %.cpp, $(DIR)/%.o, $(wildcard*.cpp))
OC := $(patsubst %.c, $(DIR)/%.co,$(wildcard *.c))
OCC := $(patsubst %.cc, $(DIR)/%.cco,$(wildcard *.cc))
OBJS := $(OC) $(OCC) $(OCPP)
RM := rm -rf
CXXFLAGS := -Wall -g
start : mkdebug $(EXE)
mkdebug :
@if [ ! -d $(DIR) ]; then mkdir $(DIR); fi;
$(EXE) : $(OBJS)
$(CC) -o $@ $(OBJS) $(addprefix -l,$(LIBS))
$(DIR)/%.o : %.cpp
$(CC) -c $(CXXFLAGS) $< -o $@
$(DIR)/%.co : %.c
$(CC) -c $(CXXFLAGS) $< -o $@
$(DIR)/%.cco : %.cc
$(CC) -c $(CXXFLAGS) $< -o $@
.PHONY : clean rebuild
clean :
@$(RM) $(DIR)/*.exe $(DIR)/*.o $(DIR)/*.co$(DIR)/*.cco
rebuild: cleanstart