如何搞定 CMake 依赖关系?(冗余还是依赖?-取决于你的选择)

如何搞定 CMake 依赖关系?(冗余还是依赖?-取决于你的选择)_第1张图片

生活中充满红蓝药丸的选择,红色是真相,痛苦却现实,蓝色是假象,快乐而愚昧。就像电影《黑客帝国》,亲爱的读者,你肯定也会选择红药丸,勇敢探寻 CMake 依赖关系的真相。想了解其中的水有多深,请继续阅读!

任何复杂的软件都有其依赖关系,无论是系统API还是其他库调用,都是静态或动态进行连接。作为构建系统生成器,CMake 可以帮助我们以最自然的方式管理这些依赖关系。

案例1:开发人员处理标准软件的 CMake 依赖关系

开发人员会知道编译项目需要哪些依赖关系。在 CMakeLists.txt 文件中,开发人员根据需要标记这些标准包。例如,如果 OpenCV 是一个包,没有它项目将无法编译,因此它将被标记为:

find_package(OpenCV REQUIRED)

备注:建议阅读博客《如何使用 OpenCV 和 CMake》以更好地理解:

一旦找到所需的包,你也会同时看到相关的头文件目录和其他设置。例如,你的项目需要 Boost 库,那么其 CMakeLists.txt 文件构造如下:

cmake_minimum_required (VERSION 3.8)project(cmake_boost_demo)
find_package(Boost REQUIRED COMPONENTS
date_time)include_directories(${Boost_INCLUDE_DIR})link_directories( ${Boost_LIBRARY_DIRS})set(Boost_USE_STATIC_LIBS OFF)set(Boost_USE_MULTITHREADED ON)set(Boost_USE_STATIC_RUNTIME OFF)set(BOOST_ALL_DYN_LINK ON)
add_executable( ${PROJECT_NAME}main.cpp)target_link_libraries( ${PROJECT_NAME} ${Boost_LIBRARIES})

如果找不到所需的包,则构建失败。你需要帮助 CMake 确定依赖关系,具体有两种方式:

  • 使用 CMAKE_PREFIX_PATH
  • 使用包含 config.cmake 的特定 DIR 路径

下面的示例中使用了 Boost 库,我将用这个简单的例子分别演示这两种方法。这是主 .cpp 文件:

#include #include using namespace std;namespace pt = boost::posix_time;
int main(int argc, char** argv) {pt::ptime now = pt::second_clock::local_time();cout << “Year : ” << (int)now.date().year() << ” ”
<< “Month : ” << (int)now.date().month() << ” ”
<< “Day :” << (int)now.date().day() << endl;
return 0;}

使用上述 CMakeLists.txt 文件,如果我们发布一个构建,我们会得到:

cmake -S. -BBuild .Could NOT find Boost (missing: Boost_INCLUDE_DIR)

使用 CMAKE_PREFIX_PATH 方法,我们发布:

cmake -S. -BBuild . -DCMAKE_PREFIX_PATH=D:\boost_1_75_0

现在我们可以看到,生成成功(假设已经在 D:\boost_1_75_0 目录下安装了 Boost)

— Found Boost: D:/boost_1_75_0 (found version “1.75.0”) found components: date_time

使用 Boost_DIR 方法,我们可以发布如下构建:

cmake -S. -BBuild . -DBoost_DIR=D:\boost_1_75_0\lib64-msvc-14.2\cmake\Boost-1.75.0

在 D:\boost_1_75_0\lib64-msvc-14.1\cmake\Boost-1.75.0 文件夹中,你可以看到:
如何搞定 CMake 依赖关系?(冗余还是依赖?-取决于你的选择)_第2张图片Config.cmake 文件就在目录下方,这也是确定 CMake 依赖关系的文件。

然后,你可以得到想要的输出:
在这里插入图片描述

案例2:开发人员处理内部库 CMake 依赖关系

如何搞定 CMake 依赖关系?(冗余还是依赖?-取决于你的选择)_第3张图片
如果项目内部有顶级项目依赖的库,则可以将 CMakeLists.txt 文件细分成很多小文件,将顶级 CMakeLists.txt 文件指定依赖项分散。可以通过以下方式实现:

  • add_library + target_link_libraries·
  • add_subdirectory

在现代 CMake中,很少会使用 add_dependencies 选项,因此我没有把 CMake add_dependencies 列出来。我们先来看看如何使用 add_ 子目录来添加依赖项。

最好的例子就是 CMake 自身的构建。你可以看看 CMakeLists.txt 文件的位置:https://github.com/Kitware/CMake/blob/master/CMakeLists.txt

你可以看到 20 个 add_ 子目录实例,其中第一个给出了清晰的图片:

#Build CMake std library for CMake and CTest.set(CMAKE_STD_LIBRARY cmstd)
add_subdirectory(Utilities/std)

Utilities/Std 文件夹内可以找到 CMakeLists.txt 文件,如下:

#To ensure maximum portability across various compilers and platforms#deactivate any compiler extensionsset(CMAKE_CXX_EXTENSIONS FALSE)
#source files for CMake std libraryset(SRCS cm/bits/fs_path.cxx
cm/bits/string_view.cxx
cm/filesystem
cm/memory
cm/optional
cm/shared_mutex
cm/string_view
cm/utility
cmext/string_view)
add_library(cmstd STATIC${SRCS})

这清楚地展示了 CMAKE_STD_LIBRARY cmstd 是如何构建的。具体可查看博客文章《CMake、OpenCV 和单元测试》,找到使用 target_link_libraries 的例子。

注意:想了解 CMake add_dependencies 的用法示例,请参考https://github.com/spurious/SDL-mirror/blob/master/test/CMakeLists.txt。很明显,这里没有使用现代 CMake。

结语:

如果你是开发人员,想要了解 CMake C++ 依赖关系有复杂,水有多深?这篇博客就是为你而写的,我们深入探讨了用户处理 CMake 依赖关系的方法,希望能对你有所帮助。

点击获取试用License!

你可能感兴趣的:(C++,c++,cmake)