02_make
0. 前言
上一篇讨论的编译过程虽然清晰,但是一步一步的执行十分繁琐
为了简化项目编译的同时兼顾理解编译细节,我们采用 make 工具来管理我们的开发项目。很多项目也会使用 cmake 工具。cmake 更加简洁高效,不过本质上也是基于 makefile 的。
我们可以为项目提供 makefile 文件,在 makefile 中描述所有执行步骤。这样只需要简单执行 makefile 文件就可以编译整个项目,大大方便调试运行。此外,在之前的项目里,所有代码文件都放在一起,十分不方便,所以我们对代码进行架构管理。
本文主要讨论如下
- 理解 make 的使用
- 编写通用 makefile
- 编译运行 make 项目
1. 项目
终端输入命令,建立本文项目
ofsp
mkdir ofsp_03_make
code ofsp_03_make
继续使用终端命令或者使用 vscode 界面创建其他文件,最终文件结构如下
tree
.
├── Aerosand
│ ├── Aerosand.cpp
│ ├── Aerosand.h
│ └── makefile
├── makefile
└── ofsp_03_make.cpp
Tip
此时可以认为我们建立了一个库 Aerosand,其中包含一个同名的类 Aerosand
类 Aerosand 的声明 Declaration Aerosand.h
,内容不变
|
|
类 Aerosand 的定义 Definition Aerosand.cpp
,内容不变
|
|
主源码 ofsp_03_make.cpp
需要修改头文件,其他内容不变
|
|
2. make
自动化构建工具 make 可以根据 makefile 中的规则自动完成源代码的编译、链接过程。
makefile 文件一般的基本格式为
<target>: <support>
<command>
需要注意的是,当我们运行 make
命令的时候,它会尝试构建第一个目标以及它的依赖。所以原则上,makefile 除第一目标之外的其他目标顺序并不重要。如果 make 在构建的过程中发现某个目标缺少依赖,则会在 makefile 中寻求此依赖的构建。
当然,需要同时构建多个目标时,比较好的做法是使用 all
作为默认目标。
2.1. 库的 makefile
基于前文对 C++ 项目编译原理的过程的讨论,我们可以为库 Aerosand 提供 makefile 文件,直白的给出编译命令
注意,如果文件内容如下
|
|
则第一目标错误,执行 make
后,仅 Aerosand.o
生成,而无法得到动态库。
调整脚本中命令的顺序,可以编译成功的写法为
|
|
终端输入命令,成功生成动态库,
cd Aerosand
make
当前文件夹的文件结构如下
tree
.
├── Aerosand.cpp
├── Aerosand.h
├── Aerosand.o
├── libAerosand.so
└── makefile
可以看到动态库 libAerosand.so
已经成功生成。
2.2. 库编译的优化
如前讨论目标顺序问题,当构建目标繁多的时候,为了提高效率,便于维护,我们需要更好的组织 makefile 文件。优化 makefile 写法如下
|
|
Tip
.PHONY
是 makefile 中的一个特殊声明,用于告诉 Make 某些目标不是实际的文件名,而是伪目标(Phony Targets)。这是 makefile 中非常重要且常用的功能,优点如下
- 防止与真实文件冲突
- 提高性能
- 向其他阅读者明确表达意图
使用 makefile 自动变量如下
$^
表示所有依赖项$@
表示目标文件$<
表示第一个依赖项
希望读者不要对 makefile 的写法感到担心,文件中大量采用了宏变量,可以让脚本更加具有通用性。陌生的语法大概知道可以这么使用即可,不需要花费更多的时间了解原因和原理。
这里给出必要的解释如下
- 第一段和第二段定义了一些宏变量,方便后续脚本的书写
- 第三段和第四段使用宏变量实现了编译命令,调换这两段的先后顺序并不影响编译结果
- 第五段明确了第一目标,定义了
make all
命令,可以实现完整编译 - 第六段定义了
make clean
命令,可以实现代码清理
终端输入命令,完成库的编译
make clean
make all
与上一节的最终效果一样,动态库得到顺利编译生成。
2.3 项目的 makefile
有了前面讨论的经验,我们直接给出项目的 makefile 如下
|
|
相较于前一个 makefile 文件,这里多出了链接动态库的语句,其实也很是直白简单。
终端输入命令,完成代码编译
cd ..
make clean
make all
make run
运行结果如下
Hi, OpenFOAM! Here we are.
1 + 3.14159 = 4.14159
1 * 3.14159 = 3.14159
Current time step is : 0.2
3. vscode 插件
3.1. C/C++ Project Generator
对于一般的 C++ 项目,可以使用 vscode 的插件 C/C++ Project Generator
,这是一个基于 makefile 的多文件项目模版。
操作和备注如下
新建项目
- 使用
F1
打开快捷命令输入关键词,选择使用Create C++ project
- 输入项目名称
- 在弹出窗口中选择新项目的父目录,并打开
写代码
- 在
src/main.cpp
中开发主函数代码 - 在
include/
路径下开发头文件的声明 - 在
src/
路径下开发头文件的定义
编译运行
- 终端使用命令
make
编译此项目,make run
编译并运行,make clean
清理项目 - 终端使用命令
./output/main
直接运行该主程序
3.2. c cpp cmake project creator
这是一个基于 cmake 的多文件项目模板
操作和备注如下
新建项目
- 使用
F1
打开快捷命令输入关键词,选择使用CMake Project: Create Project
- 在弹出窗口中选择到准备好的空白项目文件夹,并打开
写代码
- 在
src/main.cpp
中开发主函数代码 - 在
include/
路径下开发头文件的声明 - 在
src/
路径下开发头文件的定义
编译运行
- 终端使用命令
cmake build/
生成构建系统 - 终端使用命令
make -C build/
进行项目编译 - 终端使用命令
./build/xxx
运行该主程序
4. 小结
本文完成讨论
- 理解 make 的使用
- 编写通用 makefile
- 编译运行 make 项目