Files
CMake/Tests/ConfigSources/CMakeLists.txt
Brad King 16c5977504 Fix per-config sources in multi-config generators when first config adds none
Since commit b1c3ae33ea (cmTarget: Short-circuit language computation if
context independent., 2014-04-09, v3.1.0-rc1~669^2~1) we've tried to
avoid repeating computation of the list of sources for a target for
every configuration in the case that a per-config source (or object
library) contributes zero sources.  However, it is possible that an
entry contributes zero sources in the first configuration processed but
at least one source in other configurations.

Fixes: #25400
2023-11-13 14:00:12 -05:00

188 lines
7.3 KiB
CMake

cmake_minimum_required(VERSION 3.0)
get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(NOT _isMultiConfig AND NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build" FORCE)
endif()
project(ConfigSources CXX)
if("${CMAKE_CXX_COMPILER_ID};${CMAKE_CXX_SIMULATE_ID}" STREQUAL "Intel;MSVC")
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -Z7")
string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " -Z7")
endif()
# Source file(s) named with the configuration(s).
file(GENERATE
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/config_$<CONFIG>.cpp"
CONTENT [[
#if defined(_WIN32) && defined(OBJ_SHARED)
__declspec(dllexport)
#endif
void config_$<CONFIG>() {}
]]
)
# Custom command outputs named with the configuration(s).
add_custom_command(
OUTPUT "custom1_$<CONFIG>.cpp"
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/custom1.cpp.in" "custom1_$<CONFIG>.cpp"
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/custom1.cpp.in
VERBATIM
)
# Output path starts in a generator expression.
add_custom_command(
OUTPUT "$<1:custom2_$<CONFIG>.cpp>"
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/custom2.cpp.in" "custom2_$<CONFIG>.cpp"
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/custom2.cpp.in
VERBATIM
)
# Source file generated as a custom command's byproduct.
add_custom_command(
OUTPUT custom3.txt
BYPRODUCTS "$<1:custom3_$<CONFIG>.cpp>"
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/custom3.cpp.in" "custom3_$<CONFIG>.cpp"
COMMAND ${CMAKE_COMMAND} -E touch custom3.txt
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/custom3.cpp.in
VERBATIM
)
# Source file generated as a custom target's byproduct.
add_custom_target(custom4
BYPRODUCTS "custom4_$<CONFIG>.cpp"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/custom4.cpp.in" "custom4_$<CONFIG>.cpp"
VERBATIM
)
# Source file generated by appended custom command.
add_custom_command(
OUTPUT "custom5_$<CONFIG>.cpp"
COMMAND ${CMAKE_COMMAND} -E echo custom5_$<CONFIG>.cpp
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/custom5.cpp.in
VERBATIM
)
add_custom_command(APPEND
OUTPUT "custom5_$<CONFIG>.cpp"
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/custom5.cpp.in" "custom5_$<CONFIG>.cpp.in"
VERBATIM
)
# Appending through any configuration's output affects all configurations.
if(CMAKE_CONFIGURATION_TYPES MATCHES ";([^;]+)$")
set(last_config "${CMAKE_MATCH_1}")
else()
set(last_config ${CMAKE_BUILD_TYPE})
endif()
add_custom_command(APPEND
OUTPUT "custom5_${last_config}.cpp"
COMMAND ${CMAKE_COMMAND} -E copy "custom5_$<CONFIG>.cpp.in" "custom5_$<CONFIG>.cpp"
VERBATIM
)
foreach(n RANGE 1 5)
foreach(other ${CMAKE_BUILD_TYPE} Release RelWithDebInfo MinSizeRel)
set_property(SOURCE custom${n}_${other}.cpp PROPERTY COMPILE_DEFINITIONS CUSTOM_CFG_OTHER)
endforeach()
set_property(SOURCE custom${n}_Debug.cpp PROPERTY COMPILE_DEFINITIONS CUSTOM_CFG_DEBUG)
endforeach()
add_library(Custom STATIC
custom1_$<CONFIG>.cpp
custom2_$<CONFIG>.cpp
custom3_$<CONFIG>.cpp custom3.txt
custom4_$<CONFIG>.cpp
custom5_$<CONFIG>.cpp
)
# Per-config sources via INTERFACE_SOURCES.
add_library(iface INTERFACE)
target_sources(iface INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/iface_src.cpp"
"$<$<CONFIG:Debug>:${CMAKE_CURRENT_SOURCE_DIR}/iface_debug_src.cpp>"
"$<$<NOT:$<CONFIG:Debug>>:${CMAKE_CURRENT_SOURCE_DIR}/iface_other_src.cpp>"
"$<$<CONFIG:NotAConfig>:${CMAKE_CURRENT_SOURCE_DIR}/does_not_exist.cpp>"
)
target_compile_definitions(iface INTERFACE
"$<$<CONFIG:Debug>:CFG_DEBUG>"
"$<$<NOT:$<CONFIG:Debug>>:CFG_OTHER>"
)
add_executable(ConfigSources
$<$<CONFIG:Debug>:main_debug.cpp>
$<$<NOT:$<CONFIG:Debug>>:main_other.cpp>
$<$<CONFIG:NotAConfig>:does_not_exist.cpp>
${CMAKE_CURRENT_BINARY_DIR}/config_$<CONFIG>.cpp
)
target_link_libraries(ConfigSources Custom iface)
# Per-config sources via LINK_LIBRARIES.
add_library(iface_debug INTERFACE)
target_sources(iface_debug INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/iface_src.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/iface_debug_src.cpp"
)
add_library(iface_other INTERFACE)
target_sources(iface_other INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/iface_src.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/iface_other_src.cpp"
)
add_executable(ConfigSourcesLink main.cpp)
target_compile_definitions(ConfigSourcesLink PRIVATE
"$<$<CONFIG:Debug>:CFG_DEBUG>"
"$<$<NOT:$<CONFIG:Debug>>:CFG_OTHER>"
)
target_link_libraries(ConfigSourcesLink PRIVATE
Custom
"$<$<CONFIG:Debug>:iface_debug>"
"$<$<NOT:$<CONFIG:Debug>>:iface_other>"
"$<$<CONFIG:NotAConfig>:iface_does_not_exist>"
)
# Per-config sources via INTERFACE_LINK_LIBRARIES.
add_library(ConfigSourcesIface INTERFACE)
target_link_libraries(ConfigSourcesIface INTERFACE
"$<$<CONFIG:Debug>:iface_debug>"
"$<$<NOT:$<CONFIG:Debug>>:iface_other>"
"$<$<CONFIG:NotAConfig>:iface_does_not_exist>"
)
add_executable(ConfigSourcesLinkIface main.cpp)
target_compile_definitions(ConfigSourcesLinkIface PRIVATE
"$<$<CONFIG:Debug>:CFG_DEBUG>"
"$<$<NOT:$<CONFIG:Debug>>:CFG_OTHER>"
)
target_link_libraries(ConfigSourcesLinkIface Custom ConfigSourcesIface)
# A target with sources in only one configuration that is not the
# first in CMAKE_CONFIGURATION_TYPES.
if(CMAKE_CONFIGURATION_TYPES MATCHES ";([^;]+)")
set(one_config "${CMAKE_MATCH_1}")
else()
set(one_config "${CMAKE_BUILD_TYPE}")
endif()
add_library(OneConfigOnly OBJECT "$<$<CONFIG:${one_config}>:${CMAKE_CURRENT_SOURCE_DIR}/iface_src.cpp>")
set_property(TARGET OneConfigOnly PROPERTY LINKER_LANGUAGE CXX)
add_executable(ConfigSourcesUseOne main_one_config.cpp)
target_compile_definitions(ConfigSourcesUseOne PRIVATE "$<$<CONFIG:${one_config}>:CFG_ONE>")
target_link_libraries(ConfigSourcesUseOne PRIVATE "$<$<CONFIG:${one_config}>:OneConfigOnly>")
add_library(OneConfigOnlyIface INTERFACE)
target_sources(OneConfigOnlyIface INTERFACE "$<$<CONFIG:${one_config}>:${CMAKE_CURRENT_SOURCE_DIR}/iface_src.cpp>")
add_executable(ConfigSourcesUseOneIface main_one_config.cpp)
target_compile_definitions(ConfigSourcesUseOneIface PRIVATE "$<$<CONFIG:${one_config}>:CFG_ONE>")
target_link_libraries(ConfigSourcesUseOneIface PRIVATE "$<$<CONFIG:${one_config}>:OneConfigOnlyIface>")
# ---------------------------------------------------------------------------
# Makes sure that each configuration uses the correct generated file.
add_library(ObjLibFromGeneratedSources OBJECT)
set_property(TARGET ObjLibFromGeneratedSources PROPERTY POSITION_INDEPENDENT_CODE 1)
target_compile_definitions(ObjLibFromGeneratedSources PRIVATE OBJ_SHARED)
target_sources(ObjLibFromGeneratedSources PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/config_$<CONFIG>.cpp)
add_library(SharedLibFromObjLibFromGeneratedSources SHARED shared.cpp)
target_link_libraries(SharedLibFromObjLibFromGeneratedSources PRIVATE ObjLibFromGeneratedSources)
# ---------------------------------------------------------------------------
# Make sure that additional build-events do not confuse CMake when using generated files.
add_library(SharedLibFromGeneratedSources SHARED)
set_property(TARGET SharedLibFromGeneratedSources PROPERTY POSITION_INDEPENDENT_CODE 1)
target_sources(SharedLibFromGeneratedSources PRIVATE
shared.cpp
${CMAKE_CURRENT_BINARY_DIR}/config_$<CONFIG>.cpp
)
add_custom_command(TARGET SharedLibFromGeneratedSources POST_BUILD
COMMAND "${CMAKE_COMMAND}" "-E" "echo" "$<TARGET_FILE:SharedLibFromGeneratedSources>"
)