使用 CMake 构建模块化 C++ 项目
Posted
技术标签:
【中文标题】使用 CMake 构建模块化 C++ 项目【英文标题】:Modular C++ Project Build with CMake 【发布时间】:2014-06-18 19:40:50 【问题描述】:我正在尝试寻找一种方法来使用 CMake 构建一个大型模块化 C++ 项目。
项目结构如下:
--project_root
--src
--folder_1
--source_1.h
--source_1.cc
--test_source_1.cc // file containing a main with unit tests
--folder_2
--source_2.h
--source_2.cc
--test_source_2.cc // file containing a main with unit tests
--folder_3
...
等等。
每个文件夹代表一个项目模块,每个模块可能依赖于其他模块,例如 source_1.h 可能包含 source_2.h。 每个模块文件夹还可能包含一个测试文件,因此整个项目将有多个可执行文件。
如何使用 CMake 构建整个项目?我应该如何编写我的 CMakeLists.txt 文件?
非常感谢。
【问题讨论】:
试试吧,这样做没问题...使用add_subdirectory
。
我建议您更改术语,在使用 cmake 命令/语法谈论 cmake 时使用“模块”,基本上是为 cmake 编写的扩展,与您的源文件无关。您可以为 cmake 编写一个模块以添加默认情况下在 cmake 中不可用的功能。如果你开始调用你的源文件 moduleX.h 你会造成很多混乱。还有官方wiki有很多教程和资料cmake.org/Wiki/CMake
@user2485710 谢谢你的建议
【参考方案1】:
有很多很多关于如何为 C++ 构建 CMake 项目的示例,其中很多都在他的评论中建议的教程 @user2485710 中引用,所以我不打算在这里进行深入讨论,但是我至少会根据您想要布置文件夹结构的方式为您提供一个很好的起点。
CMake 的好处在于,它基本上可以使用add_subdirectory
命令来做树体。这让我们可以轻松地将 CMake 代码划分为仅执行任何特定目录级别所需的操作。换句话说,每个 CMakeLists.txt 文件应该只做在目录树的当前深度正确设置事物所需的最少工作量。在您的示例中,您的 CMake 树可能如下所示:
--project_root
--src
--CMakeLists.txt
--folder_1
--CMakeLists.txt
--source_1.h
--source_1.cc
--test_source_1.cc // file containing a main with unit tests
--folder_2
--CMakeLists.txt
--source_2.h
--source_2.cc
--test_source_2.cc // file containing a main with unit tests
...
在src/CMakeLists.txt
中,您完成了所有项目级初始化,即 I.E。 find_package
,设置您的包含路径等。然后您只需在末尾添加以下内容:
add_subdirectory(folder_1)
add_subdirectory(folder_2)
...
这告诉 CMake 它应该在这些文件夹中查找其他要做的事情。现在在src/folder_1/CMakeLists.txt
中,我们执行add_executable
和add_library
的任何组合的实际工作,您需要正确构建source_1.cc
和test_source_1.cc
,同样在src/folder_2/CMakeLists.txt
中为source_2.cc
等等。
另一个好处是,您在树上设置的任何 CMake 变量都会通过add_subdirectory
向下传播。因此,例如,在src/CMakeLists.txt
中,您可以检查某种“构建单元测试”标志并在那里设置 CMake 变量,然后您在其他 CMakeLists.txt 文件中要做的就是检查该变量。如果您有一个项目,其中 CMake 根据检查路径名等环境变量为您动态生成头文件,这也可能非常有用。
【讨论】:
【参考方案2】:如果项目结构规范,可以编写自定义宏或cmake函数来定义模块及其依赖关系。
OpenCV project 中的 cmake 脚本是一个很好的参考:
/libs/opencv-2.4.8/sources/
|+cmake/
|+doc/
|~modules/
| |+core/
| | |+doc/
| | |+include/
| | |+perf/
| | |+src/
| | |+test/
| | `-CMakeLists.txt
| |~imgproc/
| | |+doc/
| | |+include/
| | |+perf/
| | |+src/
| | |+test/
| | `-CMakeLists.txt
| |+ml/
| |+...
| |-CMakeLists.txt
|-CMakeLists.txt
root/modules/imgproc/CMakeLists.txt
set(the_description "Image Processing")
ocv_define_module(imgproc opencv_core)
【讨论】:
谁能用简单的例子解释一下OpenCV这样的项目是如何组织的,好吗?很难阅读数千行这些 CMakeLists 文件。我很乐意在一个更简单的项目中理解它。 好的,我找到了github.com/pabloariasal/modern-cmake-sample。【参考方案3】:您需要在将要进行构建的每个文件夹中都有一个 CMakeLists.txt。
project() 用于设置整个项目的名称。
add_subdirectory() 用于命令配置处理该目录中的 CMakeLists.txt。
add_executable() 用于从包含的源创建可执行文件。
add_library() 用于创建静态或动态库,可以作为依赖项添加到可执行文件或库中。
使用构建脚本(.bat、.cmd 或 .sh)将允许您自动化一些 cmake 过程,例如设置源外配置或构建。
您应该在 cmake 网站上查找这些命令的文档,https://cmake.org/cmake/help/latest/
【讨论】:
以上是关于使用 CMake 构建模块化 C++ 项目的主要内容,如果未能解决你的问题,请参考以下文章
调试不适用于 Android Studio 的 C++/本机库模块(使用 Cmake)