如何基于生成器表达式CONFIG而非CMAKE_BUILD_TYPE使用add_subdirectory?
Great question! You're absolutely right about the limitation of CMAKE_BUILD_TYPE with multi-config generators like Visual Studio and Xcode — since those generators let you pick the build configuration at build time (not configure time), checking CMAKE_BUILD_TYPE during the initial configure step won't work as expected. And you're also correct that generator expressions can't directly control add_subdirectory, since that's a configure-time command.
Here's the cleanest way to handle this, which works seamlessly for both single-config and multi-config generators:
Step 1: Always add the subdirectory
First, remove the conditional if check and just add the subdirectory unconditionally. This ensures all target definitions are registered with CMake across all configurations, which is necessary for multi-config generators to recognize the target in any build setup:
add_subdirectory(only_in_my_config)
Step 2: Control target build visibility per configuration
Now, inside only_in_my_config/CMakeLists.txt, we'll configure your target(s) to only build when the active configuration is my_config. We need to handle two scenarios explicitly:
For multi-config generators (Visual Studio, Xcode)
Multi-config generators use CMAKE_CONFIGURATION_TYPES to list all available build configurations (e.g., Debug, Release, my_config). We can loop through these and set the EXCLUDE_FROM_DEFAULT_BUILD_<CONFIG> property to ON for every configuration except my_config. This tells the generator to exclude the target from the default build set for non-target configurations.
For single-config generators (Makefiles, Ninja)
Single-config generators set the build type at configure time via CMAKE_BUILD_TYPE. Here, we can set the EXCLUDE_FROM_ALL property to ON if the build type isn't my_config, which removes the target from the default all build target.
Putting it all together in the subdirectory's CMakeLists.txt:
# Create your target as you normally would add_library(only_my_config_lib src/your_source_file.cpp) # Handle multi-config generators if(CMAKE_CONFIGURATION_TYPES) foreach(config IN LISTS CMAKE_CONFIGURATION_TYPES) if(NOT config STREQUAL "my_config") set_target_properties(only_my_config_lib PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD_${config} ON ) endif() endforeach() endif() # Handle single-config generators if(CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE STREQUAL "my_config") set_target_properties(only_my_config_lib PROPERTIES EXCLUDE_FROM_ALL ON ) endif()
Why this works
- For multi-config generators: When you build with a non-
my_configsetup (likeDebug), the target won't be part of the default build. If you ever need to build it explicitly (e.g., via Visual Studio's project explorer orxcodebuild -target only_my_config_lib), you still can — this just keeps it out of regular builds. - For single-config generators: If you configure with
cmake -DCMAKE_BUILD_TYPE=Debug .., the target won't build when you runmakeorninjaunless you explicitly specify it (e.g.,make only_my_config_lib).
Bonus: Concise (but less clean) alternative
If you prefer a shorter approach (though it leaves an empty target in non-my_config builds), you can use a generator expression to conditionally add sources:
add_library(only_my_config_lib $<$<CONFIG:my_config>:src/your_source_file.cpp>)
Note that this may trigger warnings in some toolchains since it creates a target with no sources in non-target configurations, so the first approach is generally recommended.
内容的提问来源于stack exchange,提问作者Adam Badura

