qtbase/cmake/QtBuildRepoExamplesHelpers.cmake
Alexandru Croitor cf932db57f CMake: Recompute QT_DEPLOY_PREFIX for each built example
The current deployment api implementation sets the value of
QT_DEPLOY_PREFIX based on CMAKE_INSTALL_PREFIX, if no QT_DEPLOY_PREFIX
was previously specified.

This does not work properly when multiple examples are placed in the
same subdirectory and are using deployment api.

Make sure to unset the QT_DEPLOY_PREFIX for each
qt_internal_add_example call, so that a correct prefix is computed for
each example, based on the modified CMAKE_INSTALL_PREFIX value that we
set for each example.

Task-number: QTBUG-102057
Change-Id: I931e5f2d683ab94a940e20a2bdfeaa4ac5d8c5f8
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
(cherry picked from commit c5d0e93199beea314e4e4607c8ef5f7c29162666)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2024-03-19 19:41:43 +00:00

593 lines
26 KiB
CMake

# 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})
set(CMAKE_UNITY_BUILD OFF)
# Use by qt_internal_add_example.
set(QT_EXAMPLE_BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
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)
# 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}")
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()
# 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()
# 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
CMAKE_FIND_ROOT_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
)
foreach(var_with_type IN LISTS vars_to_pass_if_defined)
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 ";" "$<SEMICOLON>" 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=<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})
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 <BINARY_DIR> --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()