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

CMake: Linking a third-party library to a project library

我目前正在开发一个使用 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) 之类的东西静态 linked 到主要可执行文件。许多实用程序也包含在单独的 Utils 库中。

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

为了模块化,我将 backward-cpp 项目添加为唯一实际使用它的项目库 Utils 的依赖项。我这样做是为了不 "pollute" 主 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)

然而,这样做是行不通的,项目最终无法 linking(未找到 backward-cpp 库中的符号),除非我link直接输出可执行文件到第三方库,在根CMakeLists.txt文件(add_backward(MainExecutableA-Z)).

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

(或者,我总是可以 link 将所有内容直接指向主要目标,因为这样总是有效。)

更新(2017 年 5 月 22 日)

我现在已经设法让一切正常工作,backwards-cpp 100% 由 "narrowest" 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()

阅读 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)

请注意,当您 link 其他目标针对 Utils.[=14= 时,最后一条语句中的 PUBLIC 负责设置包含目录和 link 库]

在查看 BackwardConfig.cmake and reading the project's README 内部之后,我得出的结论是,使用 Backward-cpp link 可执行文件的最简单方法是使用问题中提到的 add_backward(target) 宏。

修改 CMAKE_MODULE_PATH 副标题下 README 中描述的其他选项也应该有效,但我没有测试过。 Config 模式中的 find_package 将搜索名为 <name>Config.cmake 的文件,在本例中为 BackwardConfig.cmake,因此您不必编写任何额外的内容像 FindBackward.cmake 这样的 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)