使用CMake组织C++项目
使用CMake组织C++项目
前言
如果你使用过 Visual Studio 或者其他 IDE,那么应该能体验到这些 IDE 在组织 C++ 项目源代码时的便利。使用 Visual Studio 创建的项目往往依赖于一个 sln 文件,只要用 Visual Studio 打开这个 sln 文件,就能打开一个文件结构清晰的 C++ 项目。哪些文件应该被包括到项目中,哪些排除在外,都被 Visual Studio 记录得很好。
大多数情况下,使用 Visual Studio 来组织 C++ 源代码很方便,但也有一些例外的情况。比如 sln 文件有自己的版本,使用新版 Visual Studio 创建的 sln 文件在旧版 Visual Studio 有可能打不开。直接分享 Visual Studio 项目的体验可能不会很好,因为不是所有人装上 Visual Studio 都能直接打开你的项目。
接下来我想介绍的是 CMake 。虽然 CMake 不是专门用来解决上面说的这个问题,但是借助 Visual Studio 或者其他 IDE 管理项目的方式,可以很快理解 CMake 是怎么组织 C++ 项目的。
CMake 是一个工具,它用一些命令(有点像函数)来描述一个项目的安装/编译过程。CMake 描述的内容包括有哪些头文件、源代码文件、依赖哪些第三方库等等。
Cmake 并不直接建构出最终的软件,而是产生标准的建构档(如 Unix 的 Makefile 或 Windows Visual C++ 的 projects/workspaces),然后再依一般的建构方式使用。
快速入门
下面借助 Hello World 项目来说明 CMake 是如何工作的。这个项目非常简单,只有一个源文件 main.cpp,没有头文件。使用 CMake 来描述编译 main.cpp 的过程,需要把描述编译过程的 CMake 命令放在 CMakeLists.txt 文件里。因此一个使用 CMake 管理的项目(以下简称 CMake 项目)可能会像这样:
1 | . |
main.cpp:
1 |
|
CMakeLists.txt:
1 | project(hello-world) |
正如使用 Visual Studio 创建的项目一样,CMake 项目也有项目名称,项目类型等概念。在 CMakeLists.txt 文件中,命令 project(hello-world)
描述该 CMake 项目的名字是 hello-world。而命令 add_executable(${PROJECT_NAME} main.cpp)
,则描述该 CMake 项目有一个可执行文件,名字是 ${PROJECT_NAME}
,源文件有一个,是在当前目录下的 main.cpp。
可以用变量的方式理解 ${PROJECT_NAME}
,因此它的内容就是由 project
命令定义的 hello-world。
使用 Visual Studio 2019 (好像有的旧版 Visual Studio 也能打开 CMake 项目) 打开 CMake 项目所在的文件夹,按照 VS 的提示就可以编译运行了。
常用的 CMake 命令
以下介绍一些常见 CMake 命令的简单用法。之所以是简单的用法,是因为这些命令非常灵活,一篇文章难以介绍全面,了解他们的最好的方式是阅读 官方文档。
- 创建可执行文件项目
使用 add_executable(<project name> <src>)
命令可以创建一个可执行程序项目。
使用方法:
1 | # 简单写法 |
- 让CMake找到我的源文件
如果源文件太多了,可以把源文件都放到一个目录里。比如把所有的源文件都放在了 src 目录里。
使用 aux_source_directory(<src_dir> <var_name>)
命令把 src_dir 目录下的所有源文件都放到 var_name 变量里。
使用方法:
1 | aux_source_directory(./src SRCS) |
注意:aux_source_directory
不会递归包含子目录,而且在源代码目录新增源文件后,要刷新 CMake 缓存才能生效。
- 让CMake找到我的头文件
用 include_directories(<dir> [dir2] [dir3] ...)
命令设置头文件目录,告诉 CMake 应该到哪些目录里寻找头文件。如果用 target_link_libraries()
让构建目标链接一个库,可以不对这个库的头文件目录使用这个命令,具体参考下文。
使用方法:1
include_directories(./include)
- 创建库项目
使用 add_library(<project name> <type> <src>)
命令可以创建一个库项目。
使用 target_include_directories(<project name> <INTERFACE|PUBLIC|PRIVATE> <include_dir>)
设置库的头文件目录。为了让链接本库的项目能够正常使用,一般设置 PUBLIC 属性。
使用方法:
1 | # 静态链接库 |
常用的项目结构
上面介绍了几个常用的 CMake 命令,接下来结合实际项目常用的结构,谈一谈 CMakeLists.txt 的写法。
- 简单的可执行文件项目
简单的可执行项目,包括一些头文件、一些 C++ 源文件,其文件结构大致如下:
1 | . |
CMakeLists.txt:
1 | # 项目名称 hello-world |
- 带有 examples 的库项目
对于库项目,我个人一般会写一些 examples。这样可以方便实时执行库代码,同时顺便写了使用样例,方便给别人参考。
1 | . |
./CMakeLists.txt:
1 | # 项目名称 hello-world |
./examples/CMakeLists.txt:
1 | # 项目名称,因为这个是库的样例项目,不是库的一部分,所以另取一个名字 |
结语
这篇文章只是简略地总结了 CMake 的大概用法,没有细致地讲解 CMake 以及其命令。关于 CMake 更详细地用法,推荐读者结合官方文档以及其他文章慢慢探索。阅读开源项目的 CMakeLists.txt 也是个好做法,不过那些文件经过多年积累,内容多且复杂,读不懂也不要灰心(读不懂的还有我😭)。
使用CMake组织C++项目