具有自定义构建类型的 CMake 接口依赖项

CMake Interface dependency with custom build type

所以,我在 CMake 中发现了非常奇怪的行为,它创建了对 target_link_library 的依赖。 一句话很难说清楚,所以这里列出了一些要求(希望最后能说得通)

这里是 CMakeLists.txt 文件的代码,让它更清晰一些:


cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR)
project(multiconfiguration-test LANGUAGES CXX)

set(CMAKE_CONFIGURATION_TYPES Debug Release Tools)

set(CMAKE_CXX_FLAGS_TOOLS               ${CMAKE_CXX_FLAGS_DEBUG})

set(CMAKE_EXE_LINKER_FLAGS_TOOLS        ${CMAKE_EXE_LINKER_FLAGS_DEBUG})
set(CMAKE_STATIC_LINKER_FLAGS_TOOLS     ${CMAKE_STATIC_LINKER_FLAGS_DEBUG})

add_library(test-env INTERFACE)
# EXCLUDE_FROM_ALL used to not build this target by default
add_library(test-lib STATIC EXCLUDE_FROM_ALL "test-lib.cpp")
target_link_libraries(test-env INTERFACE $<$<CONFIG:Tools>:test-lib>)

add_executable(test-exe "test-exe.cpp")
target_link_libraries(test-exe PRIVATE test-env)

(文件test-exe.cpp和test-lib.cpp很简单,test-lib.cpp有一个简单的函数,test-exe.cpp声明了这个函数然后从 main 调用它。)

当您尝试使用 visual studio 2019/2017 生成器构建此项目时(当然使用“工具”作为配置类型:cmake --build . --config Tools),您将遇到下一个错误:

LINK : fatal error LNK1104: cannot open file 'Tools\test-lib.lib' [<none_important_path_to_the_project>\test-exe.vcxproj]

而且,重要的是,您不会在正在构建的终端目标 test-lib 中看到。

所以,发生的事情是目标 test-exe 知道它必须针对 test-lib linked,但是构建系统不知道目标 test-exe 依赖于目标 test-lib。

而现在最奇怪的事情!如果我们将 link 这个库像这样:target_link_libraries(test-env INTERFACE $<$<CONFIG:Debug>:test-lib>)(所以构建类型必须是 Debug),并且仍然使用 Tools 作为构建类型构建项目,您将在终端中看到目标 test-lib 是现在建设! (是的,我们有 link 错误,因为 test-exe 找不到在 test-lib 中定义的函数,但这至少是预期的)

所以,实际发生了什么,目标测试 exe 的 link 标志正确地依赖于生成器表达式但是,实际构建依赖性,以某种方式将此生成器表达式中的任何自定义构建类型转换为调试。

同样,这只发生在我上面指出的要求中,所以这不仅是生成器表达式的错误,它也与接口依赖性有关..

如果我们不能打破任何要求,一个可能的解决方案是将 test-lib 目标的直接依赖添加到 test-env(例如:add_dependecies(test-env test-lib)),但这并不完美, 因为即使我们只使用 test-lib 然后 where is Tools 作为构建类型,我们仍然每次都会构建这个库,这可能是不希望的行为。

我并不是真的在这里寻求解决方案(但如果您有解决方案,请分享),我是在寻求解释为什么会发生这种情况?这是一个错误还是一个非常奇怪的功能?

编辑 我刚刚发现的小更新: 它甚至不能是自定义构建类型。即使使用 Release 构建类型也会遇到相同的错误,因此最终代码看起来像这样简单:

cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR)
project(multiconfiguration-test LANGUAGES CXX)

add_library(test-env INTERFACE)
add_library(test-lib STATIC EXCLUDE_FROM_ALL "test-lib.cpp")
target_link_libraries(test-env INTERFACE $<$<CONFIG:Release>:test-lib>)

add_executable(test-exe "test-exe.cpp")
target_link_libraries(test-exe PRIVATE test-env)

并使用下一个命令构建:cmake --build . --config Release

我觉得 Visual Studio 生成器有问题。我刚刚在 Linux 和 Windows 上测试了 Ninja Multi-Config 生成器,cmake --build <build-dir> --config Release 工作正常。