CMake:将第三方库链接到项目库

Posted

技术标签:

【中文标题】CMake:将第三方库链接到项目库【英文标题】:CMake: Linking a third-party library to a project library 【发布时间】:2017-05-09 13:25:00 【问题描述】:

我目前正在开发一个使用 CMake 作为其构建系统的 C++ 项目。

这些项目由几个输出可执行文件组成,每个可执行文件的自定义代码相对较少,但利用了一些常用库:

programX
|
├── CMakeLists.txt (this contains the main executable targets)
|
├── Engine
│   ├── ...
│   ├── CMakeLists.txt
|
├── Utils
│   ├── third_party (this is what I added)
│   │   └── backward-cpp
│   |       └ CMakeLists.txt
│   ├── ...
│   └── CMakeLists.txt
|
└── etc.

项目的主要功能包含在Engine 库中,该库使用target_link_libraries(programX Engine) 等静态链接到主要可执行文件。许多实用程序也包含在单独的Utils 库中。

我已将 CMake 依赖项添加到这些项目库之一(它是 backward-cpp stacktrace 美化器)。该项目也是使用 CMake 构建的。

为了模块化,我已将backward-cpp 项目作为依赖项添加到唯一实际使用它的项目库Utils。我这样做是为了不使用仅与项目的一小部分相关的指令“污染”主 CMakeLists.txt 文件。

我的Utils/CMakeLists.txt 因此看起来像这样:

SET(UTILS_HEADERS ...)
set(UTILS_OBJECTS Dummy.cpp $UTILS_HEADERS)

# This is the new dependency!
add_subdirectory(third_party/backward-cpp)

SOURCE_GROUP("" FILES $UTILS_HEADERS)

# 'BACKWARD_ENABLE' and 'add_backward' are needed for linking.
add_library(Utils $UTILS_OBJECTS $BACKWARD_ENABLE)
add_backward(Utils)

但是,这样做不起作用,并且项目最终无法链接(未找到 backward-cpp 库中的符号),除非我将输出的可执行文件链接到第三方直接库,在根 CMakeLists.txt 文件 (add_backward(MainExecutableA-Z)) 中。

我知道无法将静态库链接到其他静态库,但我想知道是否有一种很好的方法可以使用 CMake 实现静态库及其依赖项的模块化。

(或者,我总是可以将所有内容直接链接到主要目标,因为这总是有效的。)

更新(2017 年 5 月 22 日)

我现在已经设法让一切正常,backwards-cpp 100% 受到“最窄”CMakeLists.txt 文件的控制,这要感谢我得到的有用答案。这是我最终得到的Utils/CMakeLists.txt 文件(删除了不相关的部分):

SET(UTILS_HEADERS ...)   
SET(UTILS_SOURCES ...)


# If enabled, enables sensible stack traces on Linux, complete with corresponding source
# code, where available. CUDA errors also produce complete stack traces when this is on.
# If disabled, the error messages degrade gracefully to file/line information.
OPTION(WITH_BACKWARDS_CPP "Build with backwards-cpp stack trace dumping library? (Linux-only)" TRUE)
message(STATUS "backwards-cpp-enhanced stack traces? " $WITH_BACKWARDS_CPP)

if(WITH_BACKWARDS_CPP)
  # Support 'backward-cpp,' a lean stacktrace printing library for Linux.
  add_definitions(-DWITH_BACKWARDS_CPP)
  add_subdirectory(third_party/backward-cpp)
endif()

SOURCE_GROUP("" FILES $UTILS_HEADERS $UTILS_SOURCES)
add_library(Utils $UTILS_HEADERS $UTILS_SOURCES)

# ...unrelated CUDA stuff...

if(WITH_BACKWARDS_CPP)
  # Link agains libbfd to ensure backward-cpp can extract additional information from the binary,
  # such as source code mappings. The '-lbfd' dependency is optional, and if it is disabled, the
  # stack traces will still work, but won't show unmangled symbol names or source code snippets.
  # You may need to set BACKWARD_USE_BFD to 0 in its `hpp` and `cpp` files to avoid linker errors.
  target_link_libraries(Utils PUBLIC -lbfd)
  target_link_libraries(Utils PUBLIC backward)
endif()

【问题讨论】:

如果我理解得很好,您成功构建并链接了 Utils 静态库,但在尝试链接主可执行文件时收到链接器错误。我说的对吗? Utils 库始终可以构建。我也可以构建主要的可执行文件,但前提是我将它们直接与 Utils 和第三方库链接。当我尝试将 Utils 链接到第三方库以及带有 Utils 的主要可执行文件时,传递部分是不起作用的。 好吧,据我所知,静态库不会与其他静态库链接,因此在构建可执行文件时,需要将其与所有静态库链接。 【参考方案1】:

在查看BackwardConfig.cmake 并阅读项目的README 后,我得出结论,将可执行文件与Backward-cpp 链接的最简单方法是使用add_backward(target) 宏正如你在问题中提到的那样。

README 中的 Modifying CMAKE_MODULE_PATH 副标题下描述的其他选项也可以工作,但我没有测试。 Config 模式下的find_package 将搜索名为<name>Config.cmake 的文件,在这种情况下为BackwardConfig.cmake,因此您不必编写任何额外的CMake 模块,例如FindBackward.cmake。作为尝试,我会执行以下操作:

set(UTILS_HEADERS ...)
set(UTILS_OBJECTS Dummy.cpp $UTILS_HEADERS)

source_group("" FILES $UTILS_HEADERS)
add_library(Utils $UTILS_OBJECTS)

list(APPEND CMAKE_MODULE_PATH /path/to/backward-cpp)
find_package(Backward)

target_link_libraries(Utils PUBLIC Backward::Backward)

【讨论】:

【参考方案2】:

阅读README of backward-cpp后,我会尝试以下(仅最后两行更改):

SET(UTILS_HEADERS ...)
set(UTILS_OBJECTS Dummy.cpp $UTILS_HEADERS)

# This is the new dependency!
add_subdirectory(third_party/backward-cpp)

SOURCE_GROUP("" FILES $UTILS_HEADERS)

add_library(Utils $UTILS_OBJECTS)
target_link_libraries(Utils PUBLIC backward)

请注意,当您将其他目标链接到 Utils 时,最后一条语句中的 PUBLIC 负责设置包含目录和链接库。

【讨论】:

感谢您的回答!但是,使用它会导致target_link_libraries 出现问题,因为它期望Backward::Backward 成为目标(Target "Utils" links to target "Backward::Backward" but the target was not found. )。但是,尝试使用 README 中的第二种方法,即“修改 CMAKE_MODULE_PATH”,也不起作用,因为 CMake 然后无法找到向后的包。是否需要写一个自定义的FindBackward.cmake文件放入/cmake 如果将Backward::Backward 替换为backward 会怎样? 是的,在最后一行只使用backward 就可以了。我必须解决一些关于链接libbfd(更漂亮的堆栈跟踪所必需)和添加编译时标志以切换backwards-cpp 的使用的后续问题,但我设法让它工作。谢谢!我已经用我当前的CMakeLists.txt 文件更新了我的答案。

以上是关于CMake:将第三方库链接到项目库的主要内容,如果未能解决你的问题,请参考以下文章

使用 CMake 只构建一次外部库

Cmake:将子目录链接模式覆盖为 LINK_PRIVATE

怎么使用CMake链接不同版本的第三方库

CMAKE使用链接第三方SO库

CMake——第三方库引入

CMake:隐藏子目标的-WShadow全局编译标志