# Copyright (C) 2023 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause macro(qt_examples_build_begin) set(options EXTERNAL_BUILD) set(singleOpts "") set(multiOpts DEPENDS) cmake_parse_arguments(arg "${options}" "${singleOpts}" "${multiOpts}" ${ARGN}) # Examples are not unity-ready. set(CMAKE_UNITY_BUILD OFF) # Skip running deployment steps when the developer asked to deploy a minimal subset of examples. # Each example can then decide whether it wants to be deployed as part of the minimal subset # by unsetting the QT_INTERNAL_SKIP_DEPLOYMENT variable before its qt_internal_add_example call. # This will be used by our CI. if(NOT DEFINED QT_INTERNAL_SKIP_DEPLOYMENT AND QT_DEPLOY_MINIMAL_EXAMPLES) set(QT_INTERNAL_SKIP_DEPLOYMENT TRUE) endif() # Use by qt_internal_add_example. set(QT_EXAMPLE_BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") if(QT_BUILD_STANDALONE_EXAMPLES) # Find all qt packages, so that the various if(QT_FEATURE_foo) add_subdirectory() # conditions have correct values, regardless whether we will use ExternalProjects or not. qt_internal_find_standalone_parts_config_files() endif() if(arg_EXTERNAL_BUILD AND QT_BUILD_EXAMPLES_AS_EXTERNAL) # Examples will be built using ExternalProject. # We depend on all plugins built as part of the current repo as well as current repo's # dependencies plugins, to prevent opportunities for # weird errors associated with loading out-of-date plugins from # unrelated Qt modules. # We also depend on all targets from this repo's src and tools subdirectories # to ensure that we've built anything that a find_package() call within # an example might use. Projects can add further dependencies if needed, # but that should rarely be necessary. set(QT_EXAMPLE_DEPENDENCIES ${qt_repo_plugins_recursive} ${arg_DEPENDS}) if(TARGET ${qt_repo_targets_name}_src) list(APPEND QT_EXAMPLE_DEPENDENCIES ${qt_repo_targets_name}_src_for_examples) endif() if(TARGET ${qt_repo_targets_name}_tools) list(APPEND QT_EXAMPLE_DEPENDENCIES ${qt_repo_targets_name}_tools) endif() set(QT_IS_EXTERNAL_EXAMPLES_BUILD TRUE) string(TOLOWER ${PROJECT_NAME} project_name_lower) if(NOT TARGET examples) if(QT_BUILD_EXAMPLES_BY_DEFAULT) add_custom_target(examples ALL) else() add_custom_target(examples) endif() endif() if(NOT TARGET examples_${project_name_lower}) add_custom_target(examples_${project_name_lower}) add_dependencies(examples examples_${project_name_lower}) endif() include(ExternalProject) else() # This repo has not yet been updated to build examples in a separate # build from this main build, or we can't use that arrangement yet. # Build them directly as part of the main build instead for backward # compatibility. if(NOT BUILD_SHARED_LIBS) # Ordinarily, it would be an error to call return() from within a # macro(), but in this case we specifically want to return from the # caller's scope if we are doing a static build and the project # isn't building examples in a separate build from the main build. # Configuring static builds requires tools that are not available # until build time. return() endif() if(NOT QT_BUILD_EXAMPLES_BY_DEFAULT) set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL TRUE) 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. # Prepending to CMAKE_PREFIX_PATH helps find the initial Qt6Config.cmake. # Prepending to QT_BUILD_CMAKE_PREFIX_PATH helps find components of Qt6, because those # find_package calls use NO_DEFAULT_PATH, and thus CMAKE_PREFIX_PATH is ignored. # Prepending to CMAKE_FIND_ROOT_PATH ensures the components are found while cross-compiling # without setting CMAKE_FIND_ROOT_PATH_MODE_PACKAGE to BOTH. 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(PREPEND CMAKE_FIND_ROOT_PATH "${QT_BUILD_DIR}") list(PREPEND QT_BUILD_CMAKE_PREFIX_PATH "${QT_BUILD_DIR}/${INSTALL_LIBDIR}/cmake") 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. # This means that installed examples are not relocatable at the moment. We would need to # annotate where each example is installed to, to be able to derive a relative rpath, and it # seems there's no way to query such information from CMake itself. set(CMAKE_INSTALL_RPATH "${_default_install_rpath}") 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) # We use AUTOMOC/UIC/RCC in the examples. When the examples are part of the # main build rather than being built in their own separate project, make # sure we do not fail on a fresh Qt build (e.g. the moc binary won't exist # yet because it is created at build time). _qt_internal_collect_buildsystem_targets(targets "${CMAKE_CURRENT_SOURCE_DIR}" EXCLUDE UTILITY ALIAS) foreach(target ${targets}) qt_autogen_tools(${target} ENABLE_AUTOGEN_TOOLS "moc" "rcc") if(TARGET Qt::Widgets) qt_autogen_tools(${target} ENABLE_AUTOGEN_TOOLS "uic") endif() set_target_properties(${target} PROPERTIES UNITY_BUILD OFF) endforeach() install(CODE " # Restore backed up CMAKE_INSTALL_PREFIX. set(CMAKE_INSTALL_PREFIX \"\${_qt_internal_examples_cmake_install_prefix_backup}\") ") set(CMAKE_UNITY_BUILD ${QT_UNITY_BUILD}) endmacro() # Allows building an example either as an ExternalProject or in-tree with the Qt build. # Also allows installing the example sources. function(qt_internal_add_example subdir) # Don't show warnings for examples that were added via qt_internal_add_example. # Those that are added via add_subdirectory will see the warning, due to the parent scope # having the variable set to TRUE. if(QT_FEATURE_developer_build AND NOT QT_NO_WARN_ABOUT_EXAMPLE_ADD_SUBDIRECTORY_WARNING) set(QT_WARN_ABOUT_EXAMPLE_ADD_SUBDIRECTORY FALSE) endif() # Pre-compute unique example name based on the subdir, in case of target name clashes. qt_internal_get_example_unique_name(unique_example_name "${subdir}") # QT_INTERNAL_NO_CONFIGURE_EXAMPLES is not meant to be used by Qt builders, it's here for faster # testing of the source installation code path for build system engineers. if(NOT QT_INTERNAL_NO_CONFIGURE_EXAMPLES) if(NOT QT_IS_EXTERNAL_EXAMPLES_BUILD) qt_internal_add_example_in_tree("${subdir}") else() qt_internal_add_example_external_project("${subdir}" NAME "${unique_example_name}") endif() endif() if(QT_INSTALL_EXAMPLES_SOURCES) string(TOLOWER ${PROJECT_NAME} project_name_lower) qt_internal_install_example_sources("${subdir}" NAME "${unique_example_name}" REPO_NAME "${project_name_lower}") endif() endfunction() # Gets the install prefix where an example should be installed. # Used for computing the final installation path. function(qt_internal_get_example_install_prefix out_var) # Allow customizing the installation path of the examples. Will be used in CI. if(QT_INTERNAL_EXAMPLES_INSTALL_PREFIX) set(qt_example_install_prefix "${QT_INTERNAL_EXAMPLES_INSTALL_PREFIX}") elseif(QT_BUILD_STANDALONE_EXAMPLES) # TODO: We might need to reset and pipe through an empty CMAKE_STAGING_PREFIX if we ever # try to run standalone examples in the CI when cross-compiling, similar how it's done in # qt_internal_set_up_fake_standalone_parts_install_prefix. qt_internal_get_fake_standalone_install_prefix(qt_example_install_prefix) else() set(qt_example_install_prefix "${CMAKE_INSTALL_PREFIX}/${INSTALL_EXAMPLESDIR}") endif() file(TO_CMAKE_PATH "${qt_example_install_prefix}" qt_example_install_prefix) set(${out_var} "${qt_example_install_prefix}" PARENT_SCOPE) endfunction() # Gets the install prefix where an example's sources should be installed. # Used for computing the final installation path. function(qt_internal_get_examples_sources_install_prefix out_var) # Allow customizing the installation path of the examples source specifically. if(QT_INTERNAL_EXAMPLES_SOURCES_INSTALL_PREFIX) set(qt_example_install_prefix "${QT_INTERNAL_EXAMPLES_SOURCES_INSTALL_PREFIX}") else() qt_internal_get_example_install_prefix(qt_example_install_prefix) endif() file(TO_CMAKE_PATH "${qt_example_install_prefix}" qt_example_install_prefix) set(${out_var} "${qt_example_install_prefix}" PARENT_SCOPE) endfunction() # Gets the relative path of an example, relative to the current repo's examples source dir. # QT_EXAMPLE_BASE_DIR is meant to be already set in a parent scope. function(qt_internal_get_example_rel_path out_var subdir) file(RELATIVE_PATH example_rel_path "${QT_EXAMPLE_BASE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${subdir}") set(${out_var} "${example_rel_path}" PARENT_SCOPE) endfunction() # Gets the install path where an example should be installed. function(qt_internal_get_example_install_path out_var subdir) qt_internal_get_example_install_prefix(qt_example_install_prefix) qt_internal_get_example_rel_path(example_rel_path "${subdir}") set(example_install_path "${qt_example_install_prefix}/${example_rel_path}") set(${out_var} "${example_install_path}" PARENT_SCOPE) endfunction() # Gets the install path where an example's sources should be installed. function(qt_internal_get_examples_sources_install_path out_var subdir) qt_internal_get_examples_sources_install_prefix(qt_example_install_prefix) qt_internal_get_example_rel_path(example_rel_path "${subdir}") set(example_install_path "${qt_example_install_prefix}/${example_rel_path}") set(${out_var} "${example_install_path}" PARENT_SCOPE) endfunction() # Get the unique name of an example project based on its subdir or explicitly given name. # Makes the name unique by appending a short sha1 hash of the relative path of the example # if a target of the same name already exist. function(qt_internal_get_example_unique_name out_var subdir) qt_internal_get_example_rel_path(example_rel_path "${subdir}") set(name "${subdir}") # qtdeclarative has calls like qt_internal_add_example(imagine/automotive) # so passing a nested subdirectory. Custom targets (and thus ExternalProjects) can't contain # slashes, so extract the last part of the path to be used as a name. if(name MATCHES "/") string(REPLACE "/" ";" exploded_path "${name}") list(POP_BACK exploded_path last_dir) if(NOT last_dir) message(FATAL_ERROR "Example subdirectory must have a name.") else() set(name "${last_dir}") endif() endif() # Likely a clash with an example subdir ExternalProject custom target of the same name in a # top-level build. if(TARGET "${name}") string(SHA1 rel_path_hash "${example_rel_path}") string(SUBSTRING "${rel_path_hash}" 0 4 short_hash) set(name "${name}-${short_hash}") endif() set(${out_var} "${name}" PARENT_SCOPE) endfunction() # Use old non-ExternalProject approach, aka build in-tree with the Qt build. function(qt_internal_add_example_in_tree 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. # Also unset the deployment prefix, so it can be recomputed for each example subdirectory. unset(CMAKE_INSTALL_PREFIX) unset(QT_DEPLOY_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. qt_internal_get_example_install_path(example_install_path "${subdir}") set(CMAKE_INSTALL_PREFIX "${example_install_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}) endfunction() function(qt_internal_add_example_external_project subdir) set(options "") set(singleOpts NAME) set(multiOpts "") cmake_parse_arguments(PARSE_ARGV 1 arg "${options}" "${singleOpts}" "${multiOpts}") _qt_internal_get_build_vars_for_external_projects( CMAKE_DIR_VAR qt_cmake_dir PREFIXES_VAR qt_prefixes ADDITIONAL_PACKAGES_PREFIXES_VAR qt_additional_packages_prefixes ) list(APPEND QT_ADDITIONAL_PACKAGES_PREFIX_PATH "${qt_additional_packages_prefixes}") set(vars_to_pass_if_defined) set(var_defs) if(QT_HOST_PATH OR CMAKE_CROSSCOMPILING) list(APPEND var_defs -DCMAKE_TOOLCHAIN_FILE:FILEPATH=${qt_cmake_dir}/qt.toolchain.cmake ) else() 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. # See https://gitlab.kitware.com/cmake/cmake/-/issues/21744 if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND NOT CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME) list(APPEND vars_to_pass_if_defined CMAKE_SYSTEM_NAME:STRING) endif() endif() # We we need to augment the CMAKE_MODULE_PATH with the current repo cmake build dir, to find # files like FindWrapBundledFooConfigExtra.cmake. set(module_paths "${qt_prefixes}") list(TRANSFORM module_paths APPEND "/${INSTALL_LIBDIR}/cmake/${QT_CMAKE_EXPORT_NAMESPACE}") list(APPEND CMAKE_MODULE_PATH ${module_paths}) # Pass additional paths where qml plugin config files should be included by Qt6QmlPlugins.cmake. # This is needed in prefix builds, where the cmake files are not installed yet. set(glob_prefixes "${qt_prefixes}") list(TRANSFORM glob_prefixes APPEND "/${INSTALL_LIBDIR}/cmake/${QT_CMAKE_EXPORT_NAMESPACE}Qml") set(qml_plugin_cmake_config_file_glob_prefixes "") foreach(glob_prefix IN LISTS glob_prefix) if(EXISTS "${glob_prefix}") list(APPEND qml_plugin_cmake_config_file_glob_prefixes "${glob_prefix}") endif() endforeach() if(qml_plugin_cmake_config_file_glob_prefixes) set(QT_ADDITIONAL_QML_PLUGIN_GLOB_PREFIXES ${qml_plugin_cmake_config_file_glob_prefixes}) 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-$.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() # When cross-compiling for a qemu target in our CI, we source an environment script # that sets environment variables like CC and CXX. These are parsed by CMake on initial # configuration to populate the cache vars CMAKE_${lang}_COMPILER. # If the environment variable specified not only the compiler path, but also a list of flags # to pass to the compiler, CMake parses those out into a separate CMAKE_${lang}_COMPILER_ARG1 # cache variable. In such a case, we want to ensure that the external project also sees those # flags. # Unfortunately we can't do that by simply forwarding CMAKE_${lang}_COMPILER_ARG1 to the EP # because it breaks the compiler identification try_compile call, it simply doesn't consider # the cache var. From what I could gather, it's a limitation of try_compile and the list # of variables it considers for forwarding. # To fix this case, we ensure not to pass either cache variable, and let the external project # and its compiler identification try_compile project pick up the compiler and the flags # from the environment variables instead. foreach(lang_as_env_var CC CXX OBJC OBJCXX) if(lang_as_env_var STREQUAL "CC") set(lang_as_cache_var "C") else() set(lang_as_cache_var "${lang_as_env_var}") endif() set(lang_env_value "$ENV{${lang_as_env_var}}") if(lang_env_value AND CMAKE_${lang_as_cache_var}_COMPILER AND CMAKE_${lang_as_cache_var}_COMPILER_ARG1) # The compiler environment variable is set and specifies a list of extra flags, don't # forward the compiler cache vars and rely on the environment variable to be picked up # instead. else() list(APPEND vars_to_pass_if_defined "CMAKE_${lang_as_cache_var}_COMPILER:STRING") endif() endforeach() unset(lang_as_env_var) unset(lang_as_cache_var) unset(lang_env_value) list(APPEND vars_to_pass_if_defined CMAKE_BUILD_TYPE:STRING CMAKE_CONFIGURATION_TYPES:STRING CMAKE_PREFIX_PATH:STRING QT_BUILD_CMAKE_PREFIX_PATH:STRING QT_ADDITIONAL_PACKAGES_PREFIX_PATH:STRING QT_ADDITIONAL_QML_PLUGIN_GLOB_PREFIXES:STRING QT_INTERNAL_SKIP_DEPLOYMENT:BOOL CMAKE_FIND_ROOT_PATH:STRING CMAKE_MODULE_PATH:STRING BUILD_SHARED_LIBS:BOOL CMAKE_OSX_ARCHITECTURES:STRING CMAKE_OSX_DEPLOYMENT_TARGET:STRING CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED:BOOL CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH:BOOL CMAKE_C_COMPILER_LAUNCHER:STRING CMAKE_CXX_COMPILER_LAUNCHER:STRING CMAKE_OBJC_COMPILER_LAUNCHER:STRING CMAKE_OBJCXX_COMPILER_LAUNCHER:STRING ) # QT_EXAMPLE_CMAKE_VARS_TO_PASS can be set by specific repos to pass any additional required # CMake cache variables. # One use case is passing locations of 3rd party package locations like Protobuf via _ROOT # variables. set(extra_vars_var_name "") if(QT_EXAMPLE_CMAKE_VARS_TO_PASS) set(extra_vars_var_name "QT_EXAMPLE_CMAKE_VARS_TO_PASS") endif() foreach(var_with_type IN LISTS vars_to_pass_if_defined ${extra_vars_var_name}) string(REPLACE ":" ";" key_as_list "${var_with_type}") list(GET key_as_list 0 var) if(NOT DEFINED ${var}) continue() endif() # Preserve lists string(REPLACE ";" "$" varForGenex "${${var}}") list(APPEND var_defs -D${var_with_type}=${varForGenex}) endforeach() if(QT_INTERNAL_VERBOSE_EXAMPLES) list(APPEND var_defs -DCMAKE_MESSAGE_LOG_LEVEL:STRING=DEBUG) list(APPEND var_defs -DCMAKE_AUTOGEN_VERBOSE:BOOL=TRUE) endif() set(deps "") list(REMOVE_DUPLICATES QT_EXAMPLE_DEPENDENCIES) foreach(dep IN LISTS QT_EXAMPLE_DEPENDENCIES) if(TARGET ${dep}) list(APPEND deps ${dep}) endif() endforeach() set(independent_args) cmake_policy(PUSH) if(POLICY CMP0114) set(independent_args INDEPENDENT TRUE) cmake_policy(SET CMP0114 NEW) endif() # The USES_TERMINAL_BUILD setting forces the build step to the console pool # when using Ninja. This has two benefits: # # - You see build output as it is generated instead of at the end of the # build step. # - Only one task can use the console pool at a time, so it effectively # serializes all example build steps, thereby preventing CPU # over-commitment. # # If the loss of interactivity is not so important, one can allow CPU # over-commitment for Ninja builds. This may result in better throughput, # but is not allowed by default because it can make a machine almost # unusable while a compilation is running. set(terminal_args USES_TERMINAL_BUILD TRUE) if(CMAKE_GENERATOR MATCHES "Ninja") option(QT_BUILD_EXAMPLES_WITH_CPU_OVERCOMMIT "Allow CPU over-commitment when building examples (Ninja only)" ) if(QT_BUILD_EXAMPLES_WITH_CPU_OVERCOMMIT) set(terminal_args) 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} # but can also be set to a custom location. # 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. qt_internal_get_example_install_path(example_install_path "${subdir}") set(ep_binary_dir "${CMAKE_CURRENT_BINARY_DIR}/${subdir}") set(build_command "") if(QT_INTERNAL_VERBOSE_EXAMPLES AND CMAKE_GENERATOR MATCHES "Ninja") set(build_command BUILD_COMMAND "${CMAKE_COMMAND}" --build "." -- -v) endif() 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 "${ep_binary_dir}" INSTALL_DIR "${example_install_path}" INSTALL_COMMAND "" ${build_command} TEST_COMMAND "" DEPENDS ${deps} CMAKE_CACHE_ARGS ${var_defs} -DCMAKE_INSTALL_PREFIX:STRING= -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}) ExternalProject_Add_Step(${arg_NAME} reconfigure-check DEPENDERS configure DEPENDS ${reconfigure_check_file} ${independent_args} ) # Create an apk external project step and custom target that invokes the apk target # within the external project. # Make the global apk target depend on that custom target. if(ANDROID) ExternalProject_Add_Step(${arg_NAME} apk COMMAND ${CMAKE_COMMAND} --build --target apk DEPENDEES configure EXCLUDE_FROM_MAIN YES ${terminal_args} ) ExternalProject_Add_StepTargets(${arg_NAME} apk) if(TARGET apk) add_dependencies(apk ${arg_NAME}-apk) endif() endif() cmake_policy(POP) string(TOLOWER ${PROJECT_NAME} project_name_lower) add_dependencies(examples_${project_name_lower} ${arg_NAME}) endfunction() function(qt_internal_install_example_sources subdir) set(options "") set(single_args NAME REPO_NAME) set(multi_args "") cmake_parse_arguments(PARSE_ARGV 1 arg "${options}" "${single_args}" "${multi_args}") qt_internal_get_examples_sources_install_path(example_install_path "${subdir}") # The trailing slash is important to avoid duplicate nested directory names. set(example_source_dir "${subdir}/") # Allow controlling whether sources should be part of the default install target. if(QT_INSTALL_EXAMPLES_SOURCES_BY_DEFAULT) set(exclude_from_all "") else() set(exclude_from_all "EXCLUDE_FROM_ALL") endif() # Create an install component for all example sources. Can also be part of the default # install target if EXCLUDE_FROM_ALL is not passed. install( DIRECTORY "${example_source_dir}" DESTINATION "${example_install_path}" COMPONENT "examples_sources" USE_SOURCE_PERMISSIONS ${exclude_from_all} ) # Also create a specific install component just for this repo's examples. install( DIRECTORY "${example_source_dir}" DESTINATION "${example_install_path}" COMPONENT "examples_sources_${arg_REPO_NAME}" USE_SOURCE_PERMISSIONS EXCLUDE_FROM_ALL ) # Also create a specific install component just for the current example's sources. install( DIRECTORY "${example_source_dir}" DESTINATION "${example_install_path}" COMPONENT "examples_sources_${arg_NAME}" USE_SOURCE_PERMISSIONS EXCLUDE_FROM_ALL ) endfunction()