MakeFile构建工程
MAKEFILE 简介
在软件开发中,Make是一个构建自动化工具,它通过读取称为Makefiles的文件来自动从源代码构建 可执行程序和库,该文件指定了如何派生目标程序。尽管集成开发环境和特定于语言的编译器功能也可以用于管理构建过程,但Make仍被广泛使用,尤其是在Unix和类似Unix的操作系统中。————维基百科
make就是一个构建自动化编译的一个工具,构建在执行时的类似脚本的文件就是makefile文件。市面上有很多make工具,cmake,nmake,gmake等。
学习makefile的必要性
对于构建单个插件或者可执行文件,一般我们搭建一个工程会选择使用IDE(例如VS,Eclipese)协助我们生成makefile,这样也方便我们进行管理。这么说我们学习makefile就没有必要了吗,其实不然,学习makefile可以进行多工程的集体管理自动化生成,尤其是巨型工程,构建依赖关系,根据依赖来选择部分编译,节省编译时间,而不必全部重新编译。当然我也见过单个工程使用IDE搭建生成makefile,然后使用shell脚本依次调用每个makefile,如果不使用一些其他辅助的版本管理控制编译,那么每次都会进行全部重新编译,费时费力。
make 常用知识点
主要参考《跟我一起makefile》 链接 https://seisman.github.io/how-to-write-makefile/
当然你得了解gcc的编译相关知识,这是使用make的基础。
基本语句规则
以下是一个makefile文件的模式实例的部分,当然一般还有其他变量定义等操作:
targets : prerequisites
command
...
targets1 : prerequisites1
command1
...
targets2 : prerequisites2
command2
...
-
targets
- 可以是一个object file(目标文件),也可以是一个执行文件,还可以是一个标签(label)。make命令不指定参数,一个makefile以从上往下第一个目标文件为最终执行目标,即targets。 prerequisites
- 生成该target所依赖的文件和目录或targets,例如prerequisites 的内容可以包含XX目录的XX.cpp文件XX.h文件或者targets1,targets2,是一个树状的结构,一层层传递到真实文件。 command
- 该target要执行的命令(任意的shell命令),以 Tab键起始,可以不断换行执行直至最后没有 Tab键起始。
这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则(需要执行的命令)定义在command中。说白一点就是说:prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。
这就是makefile的核心规则。
光使用这一条即可写出几乎所有的makefile,其他的(函数,模式规则等)基本都是一些辅助手段,进行模式的匹配减少编写makefile的文字量或者编译逻辑的变通。
常用模式规则符号
%符号-模式匹配符号
%.o : %.cpp
command
...
利用%来类似通配符*来指代任意字符,上式即所有被依赖的.o文件都将依赖同名.cpp。例如 test.o -> test.cpp,test1.o -> test1.cpp,test2.o -> test2.cpp 这三个依赖只需要这一行模式规则即可表达。%后的后缀可以根据需要的匹配模式进行修改。
$@,$<符号-自动化变量
这两个符号通常成对使,用举个例子比较直观
CXX=g++
%.o : %.cpp
$(CXX) -I./inc -c $< -o $@
接着上面的%使用模式,每个*.o文件都需要对应的*.cpp文件生成,那么要是有100个cpp文件,手写哪受得了,于是使用自动化变量来完成该项操作。
$<变量指代的是目标文件列表(%.o)的一个目标,$@变量指代的是依赖文件列表(%.cpp)的对应目标,即$<为a.o那么$@为a.cpp;
例如:%.o : %.cpp 展开为test.o -> test.cpp,test1.o -> test1.cpp,test2.o -> test2.cpp的依赖那么,上文展开后的样子如下:
test.o : test.cpp
g++ -I./inc -c test.o -o test.cpp
test1.o : test1.cpp
g++ -I./inc -c test1.o -o test1.cpp
test2.o : test2.cpp
g++ -I./inc -c test2.o -o test2.cpp
$(abc:.c=.o)替换后缀
all_source_files = a.c b.cc d.c e.cxx
source_obj1 := $(all_source_files:.cpp=.o)
source_obj2 := $(source_obj1:.c=.o)
source_obj3 := $(source_obj2:.s=.o)
source_obj4 := $(source_obj3:.S=.o)
source_obj5 := $(source_obj4:.cc=.o)
source_objs := $(source_obj5:.cxx=.o)
例如上文将all_source_files中所指代的源文件全部替换为.o结尾,以便于进行依赖编译。
makefile常用的函数
这里只罗列函数,具体的可以完善查或者文档里查询,不在赘述。
-
include
- 用于包引用其他makefile error
- 打印错误并退出 ifeq else endif
- 判断语句 += := ?=
- 各种赋值 addprefix addsuffix
- 前后缀添加 notdir dir
- 提取(非)文件夹 shell
- 执行shell命令 firstword
- 第一个词 filter filter-out
- (反)过滤 basename
- 去后缀 subst patsubst
- 替换/模式替换 call
- 类似格式化字符串