问题
Lets say I have a project with two independent subprojects. If I understood cmake correctly, the idea would be to have one root CMakeLists.txt
defining a project(...)
and then using add_subdirectory(...)
to include the subprojects. Each subproject would have its own CMakeLists.txt
defining its own project. This way projects can be build either together (using the root cmake file) or individually (using the subprojects cmake file).
I now would like to change the CMAKE_CONFIGURATION_TYPES
. Should I do this in the root CMakeLists.txt
or in each subproject, or both?
Changing it in the root would mean that building a subproject individually would offer the wrong configuration types; the other options would duplicate the cmake code. I think I'm missing something here.
回答1:
Factorize out the code that sets up configuration-dependent settings. Create a file, say, SetUpConfigurations.cmake
with this content:
if(NOT SET_UP_CONFIGURATIONS_DONE)
set(SET_UP_CONFIGURATIONS_DONE TRUE)
# No reason to set CMAKE_CONFIGURATION_TYPES if it's not a multiconfig generator
# Also no reason mess with CMAKE_BUILD_TYPE if it's a multiconfig generator.
get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(isMultiConfig)
set(CMAKE_CONFIGURATION_TYPES "Debug;Release;Profile" CACHE STRING "" FORCE)
else()
if(NOT CMAKE_BUILD_TYPE)
message("Defaulting to release build.")
set(CMAKE_BUILD_TYPE Release CACHE STRING "" FORCE)
endif()
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY HELPSTRING "Choose the type of build")
# set the valid options for cmake-gui drop-down list
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug;Release;Profile")
endif()
# now set up the Profile configuration
set(CMAKE_C_FLAGS_PROFILE "...")
set(CMAKE_CXX_FLAGS_PROFILE "...")
set(CMAKE_EXE_LINKER_FLAGS_PROFILE "...")
endif()
Then include(..)
this file at the beginning of the CMakeLists.txt
's.
You have two choices about where to put SetUpConfigurations.cmake
, it depends on how you organize your projects, repositories:
The quick'n'dirty way: Copy and commit this script into each project that needs it. Its location will be fixed, relative to the
CMakeLists.txt
of the project. So you can include it, for example, withinclude(${CMAKE_CURRENT_SOURCE_DIR}/<...>/SetUpConfigurations.cmake)
The disciplined way: Maintain a repository with your custom CMake scripts, like this one. Each time you generate a project with the
cmake
command, you pass the path to this repository in theCMAKE_MODULE_PATH
variable:cmake -DCMAKE_MODULE_PATH=<dir-of-cmake-script-repo> ...
In this case include the script with include(SetUpConfigurations)
(no .cmake
extension).
A note about what a multiconfig generator is:
Xcode
and Visual Studio
are multiconfig generators. They respect the value of CMAKE_CONFIGURATION_TYPES
but CMAKE_BUILD_TYPE
has no effect since no concrete configuration is defined when the CMakeLists.txt
is processed. It will be selected on the IDE's user interface later.
On the other hand, the makefile-style generators are not interested in CMAKE_CONFIGURATION_TYPES
. CMAKE_BUILD_TYPE
defines the configuration. It is a concrete value when the CMakeLists.txt
file is processed but still: never make any decisions based on the value of CMAKE_BUILD_TYPE
:
if(CMAKE_BUILD_TYPE STREQUAL "Release") # WRONG!
....
endif()
You project won't work as intended in multiconfig generators.
回答2:
When use add_subdirectory
into subproject dir, you propagate almost all variables into that subproject, which contradicts to "subproject independency".
Instead, it is better to build and install subproject using nested cmake
call inside execute_process()
. If you want to make some subproject's definitions available for top-level project, you need to "export" this definitions when subproject is installed. This question/answer post describes, how to do that.
来源:https://stackoverflow.com/questions/31546278/where-to-set-cmake-configuration-types-in-a-project-with-subprojects