From ac4a913f333561803003650817de453f43be924d Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Tue, 14 Dec 2021 16:27:58 +0100 Subject: [PATCH] CMake: Deduce install prefix of example in qt_internal_add_example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to get rid of the INSTALL_EXAMPLEDIR and INSTALL_EXAMPLESDIR code in each example project. This was an internal workaround to ensure examples are installed into a relative path somewhere under $qt_prefix/examples and not in $qt_prefix/bin or similar. To achieve that we do two things. First, deduce the install prefix for each example in the implementation of qt_internal_add_example (our add_subdirectory wrapper) and assign it to CMAKE_INSTALL_PREFIX before calling add_subdirectory. We need to make sure to remove the default value of CMAKE_INSTALL_PREFIX in the generated cmake_install.cmake file. Second, we set an internal variable called QT_INTERNAL_SET_EXAMPLE_INSTALL_DIR_TO_DOT before the add_subdirectory call, which will be checked whenever find_package(Qt6Core) is called in an example project. If the variable is set, the INSTALL_EXAMPLEDIR var is set to "." in the scope of where Qt6Core is found. This ensures that the hardcoded INSTALL_EXAMPLEDIR values in our example projects are changed to ".". With both changes, our example project install(TARGET DESTINATION) calls will now install to "${CMAKE_INSTALL_PREFIX}/examples/${example_relative_dir}/." Once all repositories are updated to use qt_internal_add_example instead of add_subdirectory, we can get rid of the QT_INTERNAL_SET_EXAMPLE_INSTALL_DIR_TO_DOT workaround. For repositories that still don't use qt_internal_add_example, the install prefix rewriting will not happen, but the examples will still be installed to the proper place because they use their own hardcoded INSTALL_EXAMPLEDIR value. Amends d97fd7af2bc5c89a0ad9e5fac080041b78d01179 Pick-to: 6.2 6.3 Task-number: QTBUG-96232 Task-number: QTBUG-98545 Change-Id: I78c118e10c41b519c570c7d87529afd15aeed900 Reviewed-by: Jörg Bornemann --- .../QtBuildInternalsConfig.cmake | 45 ++++++++++++++++++- src/corelib/Qt6CoreConfigExtras.cmake.in | 2 + src/corelib/Qt6CoreMacros.cmake | 10 +++++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake index fe6c0c7f7ba..b41e75dd7b7 100644 --- a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake +++ b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake @@ -730,6 +730,9 @@ macro(qt_examples_build_begin) cmake_parse_arguments(arg "${options}" "${singleOpts}" "${multiOpts}" ${ARGN}) + # Use by qt_internal_add_example. + set(QT_EXAMPLE_BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + # FIXME: Support prefix builds as well QTBUG-96232 if(arg_EXTERNAL_BUILD AND QT_BUILD_EXAMPLES_AS_EXTERNAL) # Examples will be built using ExternalProject. @@ -750,7 +753,6 @@ macro(qt_examples_build_begin) list(APPEND QT_EXAMPLE_DEPENDENCIES ${qt_repo_targets_name}_tools) endif() - set(QT_EXAMPLE_BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(QT_IS_EXTERNAL_EXAMPLES_BUILD TRUE) string(TOLOWER ${PROJECT_NAME} project_name_lower) @@ -802,6 +804,13 @@ macro(qt_examples_build_begin) # seems there's no way to query such information from CMake itself. set(CMAKE_INSTALL_RPATH "${_default_install_rpath}") set(QT_DISABLE_QT_ADD_PLUGIN_COMPATIBILITY TRUE) + + install(CODE " +# Backup CMAKE_INSTALL_PREFIX because we're going to change it in each example subdirectory +# and restore it after all examples are processed so that QtFooToolsAdditionalTargetInfo.cmake +# files are installed into the original install prefix. +set(_qt_internal_examples_cmake_install_prefix_backup \"\${CMAKE_INSTALL_PREFIX}\") +") endmacro() macro(qt_examples_build_end) @@ -839,6 +848,11 @@ macro(qt_examples_build_end) endforeach() set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ${BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}) + + install(CODE " +# Restore backed up CMAKE_INSTALL_PREFIX. +set(CMAKE_INSTALL_PREFIX \"\${_qt_internal_examples_cmake_install_prefix_backup}\") +") endmacro() function(qt_internal_add_example subdir) @@ -849,8 +863,35 @@ function(qt_internal_add_example subdir) endif() endfunction() +# Use old non-ExternalProject approach, aka build in-tree with the Qt build. function(qt_internal_add_example_in_tree subdir) - # Use old non-ExternalProject approach, aka build in-tree with the Qt build. + file(RELATIVE_PATH example_rel_path + "${QT_EXAMPLE_BASE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${subdir}") + + # Unset the default CMAKE_INSTALL_PREFIX that's generated in + # ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake + # so we can override it with a different value in + # ${CMAKE_CURRENT_BINARY_DIR}/${subdir}/cmake_install.cmake + # + install(CODE " +# Unset the CMAKE_INSTALL_PREFIX in the current cmake_install.cmake file so that it can be +# overridden in the included add_subdirectory-specific cmake_install.cmake files instead. +unset(CMAKE_INSTALL_PREFIX) +") + + # Override the install prefix in the subdir cmake_install.cmake, so that + # relative install(TARGETS DESTINATION) calls in example projects install where we tell them to. + set(CMAKE_INSTALL_PREFIX + "${CMAKE_INSTALL_PREFIX}/${INSTALL_EXAMPLESDIR}/${example_rel_path}") + + # Make sure unclean example projects have their INSTALL_EXAMPLEDIR set to "." + # Won't have any effect on example projects that don't use INSTALL_EXAMPLEDIR. + # This plus the install prefix above takes care of installing examples where we want them to + # be installed, while allowing us to remove INSTALL_EXAMPLEDIR code in each example + # incrementally. + # TODO: Remove once all repositories use qt_internal_add_example instead of add_subdirectory. + set(QT_INTERNAL_SET_EXAMPLE_INSTALL_DIR_TO_DOT ON) + add_subdirectory(${subdir} ${ARGN}) endfunction() diff --git a/src/corelib/Qt6CoreConfigExtras.cmake.in b/src/corelib/Qt6CoreConfigExtras.cmake.in index d7ce721bbf6..3b9cbb883d8 100644 --- a/src/corelib/Qt6CoreConfigExtras.cmake.in +++ b/src/corelib/Qt6CoreConfigExtras.cmake.in @@ -55,3 +55,5 @@ endif() if(EMSCRIPTEN) include("${CMAKE_CURRENT_LIST_DIR}/@QT_CMAKE_EXPORT_NAMESPACE@WasmMacros.cmake") endif() + +_qt_internal_override_example_install_dir_to_dot() diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake index 588b6cc0ec7..7ed5e2b1a66 100644 --- a/src/corelib/Qt6CoreMacros.cmake +++ b/src/corelib/Qt6CoreMacros.cmake @@ -2205,6 +2205,16 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS) endfunction() endif() +# TODO: Remove once all repositories use qt_internal_add_example instead of add_subdirectory. +macro(_qt_internal_override_example_install_dir_to_dot) + # Set INSTALL_EXAMPLEDIR to ".". + # This overrides the install destination of unclean Qt example projects to install directly + # to CMAKE_INSTALL_PREFIX. + if(QT_INTERNAL_SET_EXAMPLE_INSTALL_DIR_TO_DOT) + set(INSTALL_EXAMPLEDIR ".") + endif() +endmacro() + function(qt6_allow_non_utf8_sources target) set_target_properties("${target}" PROPERTIES QT_NO_UTF8_SOURCE TRUE) endfunction()