diff options
Diffstat (limited to 'cmake/QtBuildInternals')
-rw-r--r-- | cmake/QtBuildInternals/QtBuildInternalsConfig.cmake | 140 |
1 files changed, 123 insertions, 17 deletions
diff --git a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake index b41e75dd7b..618f120597 100644 --- a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake +++ b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake @@ -719,6 +719,10 @@ macro(qt_internal_set_up_build_dir_package_paths) list(APPEND CMAKE_PREFIX_PATH "${QT_BUILD_DIR}") # Make sure the CMake config files do not recreate the already-existing targets set(QT_NO_CREATE_TARGETS TRUE) + + # TODO: Remove reliance on CMAKE_FIND_ROOT_PATH_MODE_PACKAGE and instead pass any required + # prefixes as a combination of CMAKE_PREFIX_PATH and CMAKE_FIND_ROOT_PATH like we do in + # qt_internal_add_tool. set(BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ${CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "BOTH") endmacro() @@ -733,7 +737,6 @@ macro(qt_examples_build_begin) # 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. # We always depend on all plugins so as to prevent opportunities for @@ -789,13 +792,25 @@ macro(qt_examples_build_begin) endif() endif() + # TODO: Change this to TRUE when all examples in all repos are ported to use + # qt_internal_add_example. + # We shouldn't need to call qt_internal_set_up_build_dir_package_paths when + # QT_IS_EXTERNAL_EXAMPLES_BUILD is TRUE. + # Due to not all examples being ported, if we don't + # call qt_internal_set_up_build_dir_package_paths -> set(QT_NO_CREATE_TARGETS TRUE) we'll get + # CMake configuration errors saying we redefine Qt targets because we both build them and find + # them as part of find_package. + set(__qt_all_examples_ported_to_external_projects FALSE) + # Examples that are built as part of the Qt build need to use the CMake config files from the # build dir, because they are not installed yet in a prefix build. # Appending to CMAKE_PREFIX_PATH helps find the initial Qt6Config.cmake. # Appending to QT_EXAMPLES_CMAKE_PREFIX_PATH helps find components of Qt6, because those # find_package calls use NO_DEFAULT_PATH, and thus CMAKE_PREFIX_PATH is ignored. - qt_internal_set_up_build_dir_package_paths() - list(APPEND QT_EXAMPLES_CMAKE_PREFIX_PATH "${QT_BUILD_DIR}") + if(NOT QT_IS_EXTERNAL_EXAMPLES_BUILD OR NOT __qt_all_examples_ported_to_external_projects) + qt_internal_set_up_build_dir_package_paths() + list(APPEND QT_EXAMPLES_CMAKE_PREFIX_PATH "${QT_BUILD_DIR}") + endif() # Because CMAKE_INSTALL_RPATH is empty by default in the repo project, examples need to have # it set here, so they can run when installed. @@ -896,8 +911,6 @@ unset(CMAKE_INSTALL_PREFIX) endfunction() function(qt_internal_add_example_external_project subdir) - # FIXME: Support building examples externally for prefix builds as well. - set(options "") set(singleOpts NAME) set(multiOpts "") @@ -918,15 +931,33 @@ function(qt_internal_add_example_external_project subdir) set(arg_NAME "${arg_NAME}-${short_hash}") endif() - if(QtBase_BINARY_DIR) - # Always use the copy in the build directory, even for prefix builds. - # We may build examples without installing, so we can't use the - # install or staging area. - set(qt_cmake_dir ${QtBase_BINARY_DIR}/lib/cmake/${QT_CMAKE_EXPORT_NAMESPACE}) + # TODO: Fix 'prefix Qt' example builds not to rely on CMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH + # for finding Qt packages when cross-compiling. + # TODO: Fix example builds when using Conan / install prefixes are different for each repo. + if(QT_SUPERBUILD OR QtBase_BINARY_DIR) + # When doing a top-level build or when building qtbase, + # always use the Config file from the current build directory, even for prefix builds. + # We strive to allow building examples without installing Qt first, which means we can't + # use the install or staging Config files. + set(qt_prefixes "${QT_BUILD_DIR}") + set(qt_cmake_dir "${QT_CONFIG_BUILD_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}") else() # This is a per-repo build that isn't the qtbase repo, so we know that # qtbase was found via find_package() and Qt6_DIR must be set - set(qt_cmake_dir ${${QT_CMAKE_EXPORT_NAMESPACE}_DIR}) + set(qt_cmake_dir "${${QT_CMAKE_EXPORT_NAMESPACE}_DIR}") + + # In a prefix build of a non-qtbase repo, we want to pick up the installed Config files + # for all repos except the one that is currently built. For the repo that is currently + # built, we pick up the Config files from the current repo build dir instead. + # For non-prefix builds, there's only one prefix, the main build dir. + set(qt_prefixes "${QT_BUILD_DIR}") + if(QT_WILL_INSTALL) + list(APPEND qt_prefixes "${QT6_INSTALL_PREFIX}") + + # Appending to QT_EXAMPLES_CMAKE_PREFIX_PATH helps find Qt6 components in + # non-qtbase prefix builds because we use NO_DEFAULT_PATH in find_package calls. + set(QT_EXAMPLES_CMAKE_PREFIX_PATH "${qt_prefixes}") + endif() endif() set(vars_to_pass_if_defined) @@ -935,16 +966,14 @@ function(qt_internal_add_example_external_project subdir) # Android NDK forces CMAKE_FIND_ROOT_PATH_MODE_PACKAGE to ONLY, so we # can't rely on this setting here making it through to the example # project. - # TODO: We should probably leave CMAKE_FIND_ROOT_PATH_MODE_PACKAGE - # alone. It may be a leftover from earlier methods that are no - # longer used or that no longer need this. + # TODO: Remove CMAKE_FIND_ROOT_PATH_MODE_PACKAGE once cross-compiling examples uses + # CMAKE_FIND_ROOT_PATH + CMAKE_PREFIX_PATH instead. list(APPEND var_defs -DCMAKE_TOOLCHAIN_FILE:FILEPATH=${qt_cmake_dir}/qt.toolchain.cmake -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE:STRING=BOTH ) else() - get_filename_component(prefix_dir ${qt_cmake_dir}/../../.. ABSOLUTE) - list(PREPEND CMAKE_PREFIX_PATH ${prefix_dir}) + list(PREPEND CMAKE_PREFIX_PATH ${qt_prefixes}) # Setting CMAKE_SYSTEM_NAME affects CMAKE_CROSSCOMPILING, even if it is # set to the same as the host, so it should only be set if it is different. @@ -955,9 +984,36 @@ function(qt_internal_add_example_external_project subdir) endif() endif() + # In multi-config mode by default we exclude building tools for configs other than the main one. + # Trying to build an example in a non-default config using the non-installed + # QtFooConfig.cmake files would error out saying moc is not found. + # Make sure to build examples only with the main config. + # When users build an example against an installed Qt they won't have this problem because + # the generated non-main QtFooTargets-$<CONFIG>.cmake file is empty and doesn't advertise + # a tool that is not there. + if(QT_GENERATOR_IS_MULTI_CONFIG) + set(CMAKE_CONFIGURATION_TYPES "${QT_MULTI_CONFIG_FIRST_CONFIG}") + endif() + + # We need to pass the modified CXX flags of the parent project so that using sccache works + # properly and doesn't error out due to concurrent access to the pdb files. + # See qt_internal_set_up_config_optimizations_like_in_qmake, "/Zi" "/Z7". + if(MSVC AND QT_FEATURE_msvc_obj_debug_info) + qt_internal_get_enabled_languages_for_flag_manipulation(enabled_languages) + set(configs RELWITHDEBINFO DEBUG) + foreach(lang ${enabled_languages}) + foreach(config ${configs}) + set(flag_var_name "CMAKE_${lang}_FLAGS_${config}") + list(APPEND vars_to_pass_if_defined "${flag_var_name}:STRING") + endforeach() + endforeach() + endif() + list(APPEND vars_to_pass_if_defined CMAKE_BUILD_TYPE:STRING + CMAKE_CONFIGURATION_TYPES:STRING CMAKE_PREFIX_PATH:STRING + QT_EXAMPLES_CMAKE_PREFIX_PATH:STRING CMAKE_FIND_ROOT_PATH:STRING CMAKE_FIND_ROOT_PATH_MODE_PACKAGE:STRING BUILD_SHARED_LIBS:BOOL @@ -1023,19 +1079,69 @@ function(qt_internal_add_example_external_project subdir) endif() endif() + # QT_EXAMPLE_INSTALL_MARKER + # The goal is to install each example project into a directory that keeps the example source dir + # hierarchy, without polluting the example projects with dirty INSTALL_EXAMPLEDIR and + # INSTALL_EXAMPLESDIR usage. + # E.g. ensure qtbase/examples/widgets/widgets/wiggly is installed to + # $qt_example_install_prefix/examples/widgets/widgets/wiggly/wiggly.exe + # $qt_example_install_prefix defaults to ${CMAKE_INSTALL_PREFIX}/${INSTALL_EXAMPLEDIR} + # This needs to work both: + # - when using ExternalProject to build examples + # - when examples are built in-tree as part of Qt (no ExternalProject). + # The reason we want to support the latter is for nicer IDE integration: a can developer can + # work with a Qt repo and its examples using the same build dir. + # + # In both case we have to ensure examples are not accidentally installed to $qt_prefix/bin or + # similar. + # + # Example projects installation matrix. + # 1) ExternalProject + unclean example install rules (INSTALL_EXAMPLEDIR is set) => + # use _qt_internal_override_example_install_dir_to_dot + ExternalProject_Add's INSTALL_DIR + # using relative_dir from QT_EXAMPLE_BASE_DIR to example_source_dir + # + # 2) ExternalProject + clean example install rules => + # use ExternalProject_Add's INSTALL_DIR using relative_dir from QT_EXAMPLE_BASE_DIR to + # example_source_dir, _qt_internal_override_example_install_dir_to_dot would be a no-op + # + # 3) in-tree + unclean example install rules (INSTALL_EXAMPLEDIR is set) + # + + # 4) in-tree + clean example install rules => + # ensure CMAKE_INSTALL_PREFIX is unset in parent cmake_install.cmake file, set non-cache + # CMAKE_INSTALL_PREFIX using relative_dir from QT_EXAMPLE_BASE_DIR to + # example_source_dir, use _qt_internal_override_example_install_dir_to_dot to ensure + # INSTALL_EXAMPLEDIR does not interfere. + + set(qt_example_install_prefix "${CMAKE_INSTALL_PREFIX}/${INSTALL_EXAMPLESDIR}") + set(example_install_prefix "${qt_example_install_prefix}/${example_rel_path}") + + set(ep_binary_dir "${CMAKE_CURRENT_BINARY_DIR}/${subdir}") ExternalProject_Add(${arg_NAME} EXCLUDE_FROM_ALL TRUE SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${subdir}" PREFIX "${CMAKE_CURRENT_BINARY_DIR}/${subdir}-ep" STAMP_DIR "${CMAKE_CURRENT_BINARY_DIR}/${subdir}-ep/stamp" - BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/${subdir}" + BINARY_DIR "${ep_binary_dir}" + INSTALL_DIR "${example_install_prefix}" INSTALL_COMMAND "" TEST_COMMAND "" DEPENDS ${deps} CMAKE_CACHE_ARGS ${var_defs} + -DCMAKE_INSTALL_PREFIX:STRING=<INSTALL_DIR> + -DQT_INTERNAL_SET_EXAMPLE_INSTALL_DIR_TO_DOT:BOOL=TRUE ${terminal_args} ) + # Install the examples when the the user runs 'make install', and not at build time (which is + # the default for ExternalProjects). + install(CODE "\ +# Install example from inside ExternalProject into the main build's install prefix. +execute_process( + COMMAND + \"${CMAKE_COMMAND}\" --build \"${ep_binary_dir}\" --target install +) +") + # Force configure step to re-run after we configure the main project set(reconfigure_check_file ${CMAKE_CURRENT_BINARY_DIR}/reconfigure_${arg_NAME}.txt) file(TOUCH ${reconfigure_check_file}) |