Skip to content

Multi-config Generators generate wrong build scripts when sources for OBJECT libraries are generated and their names depend on $<CONFIG>

While investigation issue #21144 (closed) I realized that sometimes multi-config generators generate build-scripts which only work for the default CONFIG type but fail for other configured CONFIG types, because they try to link object-files that are not available for that specific CONFIG.

This problem is very specific to and occurs with OBJECT libraries and generated source files whose names depend on the $<CONFIG> generator expression.

As examples are always easier to understand, here is the simple CMakeLists.txt script that demonstrates the problem:

cmake_minimum_required(VERSION 3.18)
project(Test VERSION 1.0.0)

file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_$<CONFIG>.cpp" CONTENT "// content")
add_library(test-obj OBJECT)
target_sources(test-obj PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/Generated_$<CONFIG>.cpp")

add_library(test-lib SHARED)
target_link_libraries(test-lib PRIVATE test-obj)

Note:
Instead of using file(GENERATE ...) you could replace that line with the following,

set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/Generated_$<CONFIG>.cpp" PROPERTIES GENERATED 1)

and create the source-files (Generated_Debug.cpp, Generated_Release.cpp ...) by hand in the build-directory before cmaking.

CMaking with a multi-config generator (e.g. Ninja Multi-Config) succeeds without errors, as well as building the default CONFIG (e.g. Debug). But building another CONFIG (e.g. Release) fails:

$  cd /tmp/cmake-problem/build
$  make -G "Ninja Multi-Config" ../source/
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/cmake-problem/build

$  cmake --build . --config Debug
[2/2] Linking CXX shared library Debug/libtest-lib.so

$  cmake --build . --config Release
ninja: error: 'CMakeFiles/test-obj.dir/Release/Generated_Debug.cpp.o', needed by 'Release/libtest-lib.so', missing and no known rule to make it

Note, that ninja is expecting the Generated_Debug.cpp.o object-file in the Release build directory when building Release.
This cannot be correct!

This problem, however, only occurs with OBJECT libraries. If I make target test-obj a STATIC library, this failure does not occur. (But I do not know if that static library was then built from the correct sources or not.)

This problem is not specific to the Ninja Multi-Config generator, because I was able to reproduce it on Windows with the Visual Studio 16 2019 generator. The error-message then reads (translated from German):

LINK : fatal error LNK1181: Cannot open input file "...\cmake-problem\build\test-obj.dir\Release\Generated_Debug.obj". [...\cmake-problem\build\test-lib.vcxproj]
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information