summaryrefslogtreecommitdiffstats
path: root/cmake
diff options
context:
space:
mode:
authorAlexandru Croitor <alexandru.croitor@qt.io>2019-12-06 15:12:17 +0100
committerAlexandru Croitor <alexandru.croitor@qt.io>2020-01-27 11:47:57 +0000
commitc9bea1ad62addb7582ddf0e8d790719c96a0ea90 (patch)
treee2f9c807399606e839c76504be8617fee18dfc20 /cmake
parentcce8ada8141d786c1deda78fdba485b4c67f9687 (diff)
Add initial support for CMake "Ninja Multi-Config" generator
This allows doing debug_and_release builds with Ninja on all platforms. The "Ninja Multi-Config generator" is available starting with CMake 3.17. Desired configurations can be set via CMAKE_CONFIGURATION_TYPES. Possible values: "Release, Debug, RelWithDebInfo, MinRelSize". For example -DCMAKE_CONFIGURATION_TYPES="Release;Debug". The first configuration is the 'default' configuration which is built when calling ninja with no arguments. To build all targets of a certain configuration use "ninja all:Release" or "ninja all:Debug". To build all targets in all configurations use "ninja all:all". Note that the first configuration influences which configuration of tools will be used when building the libraries for all configurations. In simple terms, when configured with -DCMAKE_CONFIGURATION_TYPES="Release;Debug" the release version of moc is used by AUTOMOC. When configured with -DCMAKE_CONFIGURATION_TYPES="Debug;Release" the debug version of moc is used by AUTOMOC. Framework builds and Ninja Multi-Config don't currently work together due to multiple bugs in CMake, which ends up generating an invalid ninja file with duplicate rules. There are also issues with placement of the debug artifacts. This will be handled in a follow up patch after CMake is fixed. Task-number: QTBUG-76899 Change-Id: If224adc0b71b7d1d6606738101536146aa866cd7 Reviewed-by: Qt CMake Build Bot Reviewed-by: Leander Beernaert <leander.beernaert@qt.io> Reviewed-by: Cristian Adam <cristian.adam@qt.io>
Diffstat (limited to 'cmake')
-rw-r--r--cmake/QtAutoDetect.cmake18
-rw-r--r--cmake/QtBaseConfigureTests.cmake8
-rw-r--r--cmake/QtBaseGlobalTargets.cmake20
-rw-r--r--cmake/QtBuild.cmake48
-rw-r--r--cmake/QtBuildInternalsExtra.cmake.in4
-rw-r--r--cmake/QtPostProcess.cmake27
-rw-r--r--cmake/QtSetup.cmake14
7 files changed, 130 insertions, 9 deletions
diff --git a/cmake/QtAutoDetect.cmake b/cmake/QtAutoDetect.cmake
index 1823d1e572..95ace249ad 100644
--- a/cmake/QtAutoDetect.cmake
+++ b/cmake/QtAutoDetect.cmake
@@ -156,6 +156,24 @@ function(qt_auto_detect_ios)
endif()
endfunction()
+function(qt_auto_detect_cmake_config)
+ if(CMAKE_CONFIGURATION_TYPES)
+ # Allow users to specify this option.
+ if(NOT QT_MULTI_CONFIG_FIRST_CONFIG)
+ list(GET CMAKE_CONFIGURATION_TYPES 0 first_config_type)
+ set(QT_MULTI_CONFIG_FIRST_CONFIG "${first_config_type}")
+ set(QT_MULTI_CONFIG_FIRST_CONFIG "${first_config_type}" PARENT_SCOPE)
+ endif()
+
+ set(CMAKE_TRY_COMPILE_CONFIGURATION "${QT_MULTI_CONFIG_FIRST_CONFIG}" PARENT_SCOPE)
+ if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config")
+ set(CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE ON PARENT_SCOPE)
+ set(CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE "${QT_MULTI_CONFIG_FIRST_CONFIG}" PARENT_SCOPE)
+ endif()
+ endif()
+endfunction()
+
+qt_auto_detect_cmake_config()
qt_auto_detect_ios()
qt_auto_detect_android()
qt_auto_detect_vpckg()
diff --git a/cmake/QtBaseConfigureTests.cmake b/cmake/QtBaseConfigureTests.cmake
index 777adb7b5f..0d6bb1407b 100644
--- a/cmake/QtBaseConfigureTests.cmake
+++ b/cmake/QtBaseConfigureTests.cmake
@@ -28,8 +28,14 @@ function(qt_run_config_test_architecture)
if (EMSCRIPTEN)
set(_arch_file_suffix ".wasm")
endif()
+
+ set(arch_test_location "config.tests/arch")
+ if(QT_MULTI_CONFIG_FIRST_CONFIG)
+ string(APPEND arch_test_location "/${QT_MULTI_CONFIG_FIRST_CONFIG}")
+ endif()
+
set(_arch_file
- "${CMAKE_CURRENT_BINARY_DIR}/config.tests/arch/architecture_test${_arch_file_suffix}")
+ "${CMAKE_CURRENT_BINARY_DIR}/${arch_test_location}/architecture_test${_arch_file_suffix}")
if (NOT EXISTS "${_arch_file}")
message(FATAL_ERROR
"Failed to find compiled architecture detection executable at ${_arch_file}.")
diff --git a/cmake/QtBaseGlobalTargets.cmake b/cmake/QtBaseGlobalTargets.cmake
index 5f38f96681..9274512577 100644
--- a/cmake/QtBaseGlobalTargets.cmake
+++ b/cmake/QtBaseGlobalTargets.cmake
@@ -137,6 +137,26 @@ else()
qt_install(PROGRAMS "${QT_BUILD_DIR}/bin/qt-cmake.bat" DESTINATION "${INSTALL_BINDIR}")
endif()
+# Provide a private convenience wrapper with options which should not be propagated via the public
+# qt-cmake wrapper e.g. CMAKE_GENERATOR.
+# These options can not be set in a toolchain file, but only on the command line.
+# These options should not be in the public wrapper, because a consumer of Qt might want to build
+# their CMake app with the Unix Makefiles generator, while Qt should be built with the Ninja
+# generator.
+# The private wrapper is more conveient for building Qt itself, because a developer doesn't need
+# to specify the same options for each qt module built.
+set(__qt_cmake_extra "-G\"${CMAKE_GENERATOR}\"")
+if(UNIX)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake.in"
+ "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-private" @ONLY)
+ qt_install(PROGRAMS "${QT_BUILD_DIR}/bin/qt-cmake-private" DESTINATION "${INSTALL_BINDIR}")
+else()
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake.bat.in"
+ "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-private.bat" @ONLY)
+ qt_install(PROGRAMS "${QT_BUILD_DIR}/bin/qt-cmake-private.bat" DESTINATION "${INSTALL_BINDIR}")
+endif()
+unset(__qt_cmake_extra)
+
## Library to hold global features:
## These features are stored and accessed via Qt::GlobalConfig, but the
## files always lived in Qt::Core, so we keep it that way
diff --git a/cmake/QtBuild.cmake b/cmake/QtBuild.cmake
index 0b434045b6..0070aac2d7 100644
--- a/cmake/QtBuild.cmake
+++ b/cmake/QtBuild.cmake
@@ -1463,7 +1463,9 @@ function(qt_finalize_framework_headers_copy target)
# Create a fake header file and copy it into the framework by marking it as PUBLIC_HEADER.
# CMake now takes care of creating the symlink.
set(fake_header ${target}_fake_header.h)
- file(GENERATE OUTPUT ${fake_header} CONTENT "// ignore this file\n")
+ qt_get_main_cmake_configuration(main_config)
+ file(GENERATE OUTPUT ${fake_header} CONTENT "// ignore this file\n"
+ CONDITION "$<CONFIG:${main_config}>")
string(PREPEND fake_header "${CMAKE_CURRENT_BINARY_DIR}/")
target_sources(${target} PRIVATE ${fake_header})
set_source_files_properties(${fake_header} PROPERTIES GENERATED ON)
@@ -1475,6 +1477,24 @@ function(qt_finalize_framework_headers_copy target)
endif()
endfunction()
+function(qt_clone_property_for_configs target property configs)
+ get_target_property(value "${target}" "${property}")
+ foreach(config ${configs})
+ string(TOUPPER "${config}" upper_config)
+ set_property(TARGET "${target}" PROPERTY "${property}_${upper_config}" "${value}")
+ endforeach()
+endfunction()
+
+function(qt_handle_multi_config_output_dirs target)
+ set(possible_configs "${CMAKE_BUILD_TYPE}")
+ if(CMAKE_CONFIGURATION_TYPES)
+ set(possible_configs "${CMAKE_CONFIGURATION_TYPES}")
+ endif()
+ qt_clone_property_for_configs(${target} LIBRARY_OUTPUT_DIRECTORY "${possible_configs}")
+ qt_clone_property_for_configs(${target} RUNTIME_OUTPUT_DIRECTORY "${possible_configs}")
+ qt_clone_property_for_configs(${target} ARCHIVE_OUTPUT_DIRECTORY "${possible_configs}")
+endfunction()
+
# This is the main entry function for creating a Qt module, that typically
# consists of a library, public header files, private header files and configurable
# features.
@@ -1542,12 +1562,11 @@ function(qt_add_module target)
set_target_properties(${target} PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}"
RUNTIME_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}"
- RUNTIME_OUTPUT_DIRECTORY_RELEASE "${QT_BUILD_DIR}/${INSTALL_BINDIR}"
- RUNTIME_OUTPUT_DIRECTORY_DEBUG "${QT_BUILD_DIR}/${INSTALL_BINDIR}"
ARCHIVE_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}"
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
)
+ qt_handle_multi_config_output_dirs("${target}")
if(is_framework)
set_target_properties(${target} PROPERTIES
@@ -2203,6 +2222,7 @@ function(qt_add_plugin target)
RUNTIME_OUTPUT_DIRECTORY "${output_directory}"
ARCHIVE_OUTPUT_DIRECTORY "${output_directory}"
QT_PLUGIN_CLASS_NAME "${arg_CLASS_NAME}")
+ qt_handle_multi_config_output_dirs("${target}")
qt_internal_library_deprecation_level(deprecation_define)
@@ -3028,6 +3048,21 @@ function(qt_add_cmake_library target)
endfunction()
+function(qt_get_tool_cmake_configuration out_var)
+ qt_get_main_cmake_configuration("${out_var}")
+ string(TOUPPER "${${out_var}}" upper_config)
+ set("${out_var}" "${upper_config}" PARENT_SCOPE)
+endfunction()
+
+function(qt_get_main_cmake_configuration out_var)
+ if(CMAKE_BUILD_TYPE)
+ set(config "${CMAKE_BUILD_TYPE}")
+ elseif(QT_MULTI_CONFIG_FIRST_CONFIG)
+ set(config "${QT_MULTI_CONFIG_FIRST_CONFIG}")
+ endif()
+ set("${out_var}" "${config}" PARENT_SCOPE)
+endfunction()
+
# This function is used to define a "Qt tool", such as moc, uic or rcc.
# The BOOTSTRAP option allows building it as standalone program, otherwise
# it will be linked against QtCore.
@@ -3146,8 +3181,11 @@ function(qt_add_tool name)
)
qt_internal_add_target_aliases("${name}")
+ # If building with a multi-config configuration, the main configuration tool will be placed in
+ # ./bin, while the rest will be in <CONFIG> specific subdirectories.
+ qt_get_tool_cmake_configuration(tool_cmake_configuration)
set_target_properties("${name}" PROPERTIES
- RUNTIME_OUTPUT_DIRECTORY_RELEASE "${QT_BUILD_DIR}/${INSTALL_BINDIR}"
+ RUNTIME_OUTPUT_DIRECTORY_${tool_cmake_configuration} "${QT_BUILD_DIR}/${INSTALL_BINDIR}"
)
if(NOT arg_NO_INSTALL AND arg_TOOLS_TARGET)
@@ -3394,7 +3432,7 @@ function(qt_add_docs)
# Generate include dir list
- set(target_include_dirs_file "${doc_ouput_dir}/includes.txt")
+ set(target_include_dirs_file "${doc_ouput_dir}/$<CONFIG>/includes.txt")
set(include_paths_property "$<TARGET_PROPERTY:${target},INCLUDE_DIRECTORIES>")
if (NOT target_type STREQUAL "INTERFACE_LIBRARY")
diff --git a/cmake/QtBuildInternalsExtra.cmake.in b/cmake/QtBuildInternalsExtra.cmake.in
index 68e1271781..5278890337 100644
--- a/cmake/QtBuildInternalsExtra.cmake.in
+++ b/cmake/QtBuildInternalsExtra.cmake.in
@@ -3,7 +3,6 @@ set(QT_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
option(BUILD_SHARED_LIBS "Build Qt statically or dynamically" @BUILD_SHARED_LIBS@)
set(QT_CMAKE_EXPORT_NAMESPACE @QT_CMAKE_EXPORT_NAMESPACE@)
set(INSTALL_CMAKE_NAMESPACE @INSTALL_CMAKE_NAMESPACE@)
-set(CMAKE_BUILD_TYPE @CMAKE_BUILD_TYPE@)
set(QT_BUILD_INTERNALS_PATH "${CMAKE_CURRENT_LIST_DIR}")
# Propagate the original install prefix, so that a developer building a child module can
@@ -31,5 +30,8 @@ set(QT_NO_MAKE_TESTS @QT_NO_MAKE_TESTS@ CACHE BOOL
set(QT_NO_MAKE_EXAMPLES @QT_NO_MAKE_EXAMPLES@ CACHE BOOL
"Should examples be built as part of the default 'all' target.")
+# Propagate usage of ccache.
+set(QT_USE_CCACHE @QT_USE_CCACHE@ CACHE BOOL "Enable the use of ccache")
+
# Extra set of exported variables
@QT_EXTRA_BUILD_INTERNALS_VARS@
diff --git a/cmake/QtPostProcess.cmake b/cmake/QtPostProcess.cmake
index b20b85bef9..807b32063d 100644
--- a/cmake/QtPostProcess.cmake
+++ b/cmake/QtPostProcess.cmake
@@ -298,7 +298,6 @@ endfunction()
function(qt_generate_build_internals_extra_cmake_code)
if(PROJECT_NAME STREQUAL "QtBase")
- set(QT_EXTRA_BUILD_INTERNALS_VARS)
foreach(var IN LISTS QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT)
string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS "set(${var} \"${${var}}\" CACHE INTERNAL \"\")\n")
endforeach()
@@ -307,6 +306,32 @@ function(qt_generate_build_internals_extra_cmake_code)
qt_path_join(extra_file_path
${QT_CONFIG_BUILD_DIR}
${INSTALL_CMAKE_NAMESPACE}BuildInternals/QtBuildInternalsExtra.cmake)
+
+ if(CMAKE_BUILD_TYPE)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(CMAKE_BUILD_TYPE \"${CMAKE_BUILD_TYPE}\")\n")
+ endif()
+ if(CMAKE_CONFIGURATION_TYPES)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(CMAKE_CONFIGURATION_TYPES \"${CMAKE_CONFIGURATION_TYPES}\")\n")
+ endif()
+ if(CMAKE_TRY_COMPILE_CONFIGURATION)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(CMAKE_TRY_COMPILE_CONFIGURATION \"${CMAKE_TRY_COMPILE_CONFIGURATION}\")\n")
+ endif()
+ if(QT_MULTI_CONFIG_FIRST_CONFIG)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(QT_MULTI_CONFIG_FIRST_CONFIG \"${QT_MULTI_CONFIG_FIRST_CONFIG}\")\n")
+ endif()
+ if(CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE \"${CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE}\")\n")
+ endif()
+ if(CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE \"${CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE}\")\n")
+ endif()
+
configure_file(
"${CMAKE_CURRENT_LIST_DIR}/QtBuildInternalsExtra.cmake.in"
"${extra_file_path}"
diff --git a/cmake/QtSetup.cmake b/cmake/QtSetup.cmake
index 65bd5b9a21..90588c99b3 100644
--- a/cmake/QtSetup.cmake
+++ b/cmake/QtSetup.cmake
@@ -10,10 +10,22 @@ if(EXISTS "${CMAKE_SOURCE_DIR}/.git")
set(_default_build_type "Debug")
endif()
+# Reset content of extra build internal vars for each inclusion of QtSetup.
+unset(QT_EXTRA_BUILD_INTERNALS_VARS)
+
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to '${_default_build_type}' as none was specified.")
set(CMAKE_BUILD_TYPE "${_default_build_type}" CACHE STRING "Choose the type of build." FORCE)
- set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") # Set the possible values of build type for cmake-gui
+ set_property(CACHE CMAKE_BUILD_TYPE
+ PROPERTY STRINGS
+ "Debug" "Release" "MinSizeRel" "RelWithDebInfo") # Set the possible values for cmake-gui.
+elseif(CMAKE_CONFIGURATION_TYPES)
+ message(STATUS "Building for multiple configurations: ${CMAKE_CONFIGURATION_TYPES}.")
+ message(STATUS "Main configuration is: ${QT_MULTI_CONFIG_FIRST_CONFIG}.")
+ if(CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE)
+ message(STATUS
+ "Default build configuration set to '${CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE}'.")
+ endif()
endif()
# Appends a 'debug postfix' to library targets (not executables)