CMake 和 Make 编译
Make 与 MakeFile
makefile 文件使代码编译更加便捷高效, make 程序解析 makefile 文件的指令,进行编译和链接程序。
makefile 优点:
如果这个工程没有编译过,那么我们的所有 c 文件都要编译并被链接。
如果这个工程的某几个 c 文件被修改,那么我们只编译被修改的 c 文件,并链接目标程序。
如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的 c 文件,并链接目标程序。
编译命令复杂,例如:
gcc -o hellomake hellomake.c hellofunc.c -I.
- 节省重复编译时,重新输入编译命令所需的时间,尤其是要编译的源文件很多时。
- 如果编译命令丢失了,你就需要重新输入
MakeFile 的几个常用关键字段与知识:
Makefile 文件名默认的情况下,make 命令会在当前目录下按顺序找寻文件名为 “GNUmakefile”、“makefile”、“Makefile” 的文件,建议优先使用“Makefile”文件名。
也可用别的文件名来书写 Makefile,比如 CMake 生成的 Makefile 一般为 xxx.make,注意:要指定非默认的 Makefile,使用 make 的“- f”和“--file”参数,一般如下:
1
2
3make
make -f ./Makefile ./build
make -f ./build.make ./build默认情况下,make 解析 Makefile 中第一个不以
.
开头的 target 作为默认编译目标例如:
1
2
3
4
5
6
7
8
9.DEFAULT_GOAL := mytarget
# 或
default: mytarget ;
# 或
default_target: all
.PHONY : default_target
对于一个 C/C++ 项目,一般有着与下面类似的目录结构:
1 | . |
其中,test 是最后生成的可执行二进制文件,include 是头文件存放的目录,src 存放源文件,build 存放目标文件,depend 存放依赖的库,按照惯例,我们一般会将 Makefile 放在项目的根目录下。
一般将所有生成的目标文件输出到 build 目录下,这样目录就比较干净,当然也不乏将最后的二进制可执行文件生成在 build 下的,具体看 MakeFile 如何指定。
make
make 常见用法三种:
make
寻找默认的 Makefile 进行编译,可通过-f
指定 MakeFilemake install
是编译并安装make clean
用来清除所有的目标文件,以便重编译。
linux 编译安装软件的流程如下,如果编译项目则不执行
make install
安装
1 | ./configure |
configure、make 和 make install 作用如下:
- ./configure 是用来检测你的安装平台的目标特征的。比如它会检测你是不是有 CC 或 GCC,并不是需要 CC 或 GCC,它是个 shell 脚本。
- make 是用来编译的,它从 Makefile 中读取指令,然后编译。
- make install 是用来安装的(例如把 C++ 库编译安装到系统目录),它也从 Makefile 中读取指令,安装到指定的位置。
CMake
不同平台(linux、Windows、MacOS)的编译环境是有差异的,为了应对这种差异,各平台编译所需的 MakeFile 文件也各不相同。而 cmake, 作为一个一个跨平台的安装(编译)工具,它抽象了一套上层的编译配置语法,并负责了将 Ta 针对平台进行 MakeFile 文件解释的任务。
CMake 定义了一套语法来组织 CMakeLists.txt 文件,然后通过 cmake 命令可以结合 CMakeLists.txt 文件的”配置“生成 MakeFile,然后交给 make 解析
外部构建
CMake 可以将将所有的编译信息有效地管理在一个文件夹下!当我们想清理编译数据时,只需要删除 build 文件夹。其生成的 MakeFile 中的变量 CMAKE_BINARY_DIR 指向 cmake 命令的根文件夹,所有二进制文件在这个文件夹里产生,一般可以在 CMake 之后查看,确定二进制文件的位置。
外部构建常规步骤:创建 build 文件夹,然后进入该文件夹,通过为 cmake 指定上层目录寻找 CMakeLists.txt, 将编译文件生成在该文件夹下。
1 | mkdir build |
一般文件树如下:
1 | ├── build |
build 文件夹下生成了许多二进制文件,如果要从头开始重新创建 cmake 环境,只需删除构建目录 build,然后重新运行 cmake 即可。