diff options
Diffstat (limited to 'cmake/QtBuildInternals')
3 files changed, 538 insertions, 0 deletions
diff --git a/cmake/QtBuildInternals/QtBuildInternalsAndroid.cmake b/cmake/QtBuildInternals/QtBuildInternalsAndroid.cmake new file mode 100644 index 0000000000..9830cf9871 --- /dev/null +++ b/cmake/QtBuildInternals/QtBuildInternalsAndroid.cmake @@ -0,0 +1,217 @@ +# +# Android specific functions/macros/properties required for building Qt Modules +# + +define_property(TARGET + PROPERTY + QT_ANDROID_MODULE_INSTALL_DIR + BRIEF_DOCS + "Recorded install location for a Qt Module." + FULL_DOCS + "Recorded install location for a Qt Module. Used by qt_android_dependencies()." +) + + +define_property(TARGET + PROPERTY + QT_ANDROID_JAR_DEPENDENCIES + BRIEF_DOCS + "Qt Module Jar dependencies list." + FULL_DOCS + "Qt Module Jar dependencies list." +) + +define_property(TARGET + PROPERTY + QT_ANDROID_BUNDLED_JAR_DEPENDENCIES + BRIEF_DOCS + "Qt Module Jars that should be bundled with it during packing." + FULL_DOCS + "Qt Module Jars that should be bundled with it during packing." +) + +define_property(TARGET + PROPERTY + QT_ANDROID_LIB_DEPENDENCIES + BRIEF_DOCS + "Qt Module C++ libraries that should be bundled with it during packing." + FULL_DOCS + "Qt Module C++ libraries that should be bundled with it during packing." +) + +define_property(TARGET + PROPERTY + QT_ANDROID_LIB_DEPENDENCY_REPLACEMENTS + BRIEF_DOCS + "Qt Module C++ libraries that can replace libraries declared with the QT_ANDROID_LIB_DEPENDENCIES property." + FULL_DOCS + "Qt Module C++ libraries that can replace libraries declared with the QT_ANDROID_LIB_DEPENDENCIES property." +) + +define_property(TARGET + PROPERTY + QT_ANDROID_BUNDLED_FILES + BRIEF_DOCS + "Qt Module files that need to be bundled during packing." + FULL_DOCS + "Qt Module files that need to be bundled during packing." +) + +define_property(TARGET + PROPERTY + QT_ANDROID_PERMISSIONS + BRIEF_DOCS + "Qt Module android permission list." + FULL_DOCS + "Qt Module android permission list." +) +# Generate Qt Module -android-dependencies.xml required by the +# androiddeploytoolqt to successfully copy all the plugins and other dependent +# items into tha APK +function(qt_android_dependencies target) + get_target_property(target_type "${target}" TYPE) + if(target_type STREQUAL "INTERFACE_LIBRARY") + return() + endif() + + get_target_property(arg_JAR_DEPENDENCIES ${target} QT_ANDROID_JAR_DEPENDENCIES) + get_target_property(arg_BUNDLED_JAR_DEPENDENCIES ${target} QT_ANDROID_BUNDLED_JAR_DEPENDENCIES) + get_target_property(arg_LIB_DEPENDENCIES ${target} QT_ANDROID_LIB_DEPENDENCIES) + get_target_property(arg_LIB_DEPENDENCY_REPLACEMENTS ${target} QT_ANDROID_LIB_DEPENDENCY_REPLACEMENTS) + get_target_property(arg_BUNDLED_FILES ${target} QT_ANDROID_BUNDLED_FILES) + get_target_property(arg_PERMISSIONS ${target} QT_ANDROID_PERMISSIONS) + get_target_property(module_plugins ${target} MODULE_PLUGIN_TYPES) + + if ((NOT module_plugins) + AND (NOT arg_JAR_DEPENDENCIES) + AND (NOT arg_LIB_DEPENDENCY_REPLACEMENTS) + AND (NOT arg_LIB_DEPENDENCIES) + AND (NOT arg_BUNDLED_JAR_DEPENDENCIES) + AND (NOT arg_PERMISSIONS) + AND (NOT arg_BUNDLED_FILES)) + # None of the values were set, so there's nothing to do + return() + endif() + + + get_target_property(target_output_name ${target} OUTPUT_NAME) + if (NOT target_output_name) + set(target_name ${target}) + else() + set(target_name ${target_output_name}) + endif() + + # mimic qmake's section and string splitting from + # mkspecs/feature/qt_android_deps.prf + macro(section string delimiter first second) + string(FIND ${string} ${delimiter} delimiter_location) + if (NOT ${delimiter_location} EQUAL -1) + string(SUBSTRING ${string} 0 ${delimiter_location} ${first}) + math(EXPR delimiter_location "${delimiter_location} + 1") + string(SUBSTRING ${string} ${delimiter_location} -1 ${second}) + else() + set(${first} ${string}) + set(${second} "") + endif() + endmacro() + + get_target_property(target_bin_dir ${target} BINARY_DIR) + set(dependency_file "${target_bin_dir}/${target_name}_${CMAKE_ANDROID_ARCH_ABI}-android-dependencies.xml") + + set(file_contents "<rules><dependencies>\n") + string(APPEND file_contents "<lib name=\"${target_name}_${CMAKE_ANDROID_ARCH_ABI}\"><depends>\n") + + # Jar Dependencies + if(arg_JAR_DEPENDENCIES) + foreach(jar_dependency IN LISTS arg_JAR_DEPENDENCIES) + section(${jar_dependency} ":" jar_file init_class) + if (init_class) + set(init_class "initClass=\"${init_class}\"") + endif() + file(TO_NATIVE_PATH ${jar_file} jar_file_native) + string(APPEND file_contents "<jar file=\"${jar_file_native}\" ${init_class} />\n") + endforeach() + endif() + + # Bundled Jar Dependencies + if(arg_BUNDLED_JAR_DEPENDENCIES) + foreach(jar_bundle IN LISTS arg_BUNDLED_JAR_DEPENDENCIES) + section(${jar_bundle} ":" bundle_file init_calss) + if (init_class) + set(init_class "initClass=\"${init_class}\"") + endif() + file(TO_NATIVE_PATH ${jar_bundle} jar_bundle_native) + string(APPEND file_contents "<jar bundling=\"1\" file=\"${jar_bundle_native}\" ${init_class} />\n") + endforeach() + endif() + + # Lib Dependencies + if(arg_LIB_DEPENDENCIES) + foreach(lib IN LISTS arg_LIB_DEPENDENCIES) + string(REPLACE ".so" "_${CMAKE_ANDROID_ARCH_ABI}.so" lib ${lib}) + section(${lib} ":" lib_file lib_extends) + if (lib_extends) + set(lib_extends "extends=\"${lib_extends}\"") + endif() + file(TO_NATIVE_PATH ${lib_file} lib_file_native) + string(APPEND file_contents "<lib file=\"${lib_file_native}\" ${lib_extends} />\n") + endforeach() + endif() + + # Lib Dependencies Replacements + if(arg_LIB_DEPENDENCY_REPLACEMENTS) + foreach(lib IN LISTS arg_LIB_DEPENDENCY_REPLACEMENTS) + string(REPLACE ".so" "_${CMAKE_ANDROID_ARCH_ABI}.so" lib ${lib}) + section(${lib} ":" lib_file lib_replacement) + if (lib_replacement) + file(TO_NATIVE_PATH ${lib_replacement} lib_replacement_native) + set(lib_replacement "replaces=\"${lib_replacement_native}\"") + endif() + file(TO_NATIVE_PATH ${lib_file} lib_file_native) + string(APPEND file_contents "<lib file=\"${lib_file_native}\" ${lib_replacement} />\n") + endforeach() + endif() + + + # Bundled files + if(arg_BUNDLED_FILES) + foreach(bundled_file IN LISTS arg_BUNDLED_FILES) + file(TO_NATIVE_PATH ${bundled_file} file_native) + string(APPEND file_contents "<bundled file=\"${file_native}\" />\n") + endforeach() + endif() + + # Module plugins + if(module_plugins) + foreach(plugin IN LISTS module_plugins) + string(APPEND file_contents "<bundled file=\"plugins/${plugin}\" />\n") + endforeach() + endif() + + # Android Permissions + if(arg_PERMISSIONS) + foreach(permission IN LISTS arg_PERMISSIONS) + string(APPEND file_contents "<permission name=\"${permission}\" />\n") + endforeach() + endif() + + string(APPEND file_contents "</depends></lib>") + string(APPEND file_contents "</dependencies></rules>\n") + file(WRITE ${dependency_file} ${file_contents}) + + get_target_property(target_install_dir ${target} QT_ANDROID_MODULE_INSTALL_DIR) + if (NOT target_install_dir) + message(SEND_ERROR "qt_android_dependencies: Target ${target} is either not a Qt Module or has no recorded install location") + return() + endif() + + # Copy file into install directory, required by the androiddeployqt tool. + qt_install(FILES + ${dependency_file} + DESTINATION + ${target_install_dir} + COMPONENT + Devel) +endfunction() + + diff --git a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake new file mode 100644 index 0000000000..5648326ca2 --- /dev/null +++ b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake @@ -0,0 +1,291 @@ +if (CMAKE_VERSION VERSION_LESS 3.1.0) + message(FATAL_ERROR "Qt requires at least CMake version 3.1.0") +endif() + +###################################### +# +# Macros for building Qt modules +# +###################################### + +if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/QtBuildInternalsExtra.cmake") + include(${CMAKE_CURRENT_LIST_DIR}/QtBuildInternalsExtra.cmake) +endif() + +macro(qt_set_up_build_internals_paths) + # Set up the paths for the cmake modules located in the prefix dir. Prepend, so the paths are + # least important compared to the source dir ones, but more important than command line + # provided ones. + set(QT_CMAKE_MODULE_PATH "${QT_BUILD_INTERNALS_PATH}/../${QT_CMAKE_EXPORT_NAMESPACE}") + list(PREPEND CMAKE_MODULE_PATH "${QT_CMAKE_MODULE_PATH}") + + # Prepend the qtbase source cmake directory to CMAKE_MODULE_PATH, + # so that if a change is done in cmake/QtBuild.cmake, it gets automatically picked up when + # building qtdeclarative, rather than having to build qtbase first (which will copy + # QtBuild.cmake to the build dir). This is similar to qmake non-prefix builds, where the + # source qtbase/mkspecs directory is used. + if(EXISTS "${QT_SOURCE_TREE}/cmake") + list(PREPEND CMAKE_MODULE_PATH "${QT_SOURCE_TREE}/cmake") + endif() + + # If the repo has its own cmake modules, include those in the module path. + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + endif() + + # Find the cmake files when doing a standalone tests build. + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") + list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") + endif() +endmacro() + +# Set up the build internal paths unless explicitly requested not to. +if(NOT QT_BUILD_INTERNALS_SKIP_CMAKE_MODULE_PATH_ADDITION) + qt_set_up_build_internals_paths() +endif() + +# Define some constants to check for certain platforms, etc. +# Needs to be loaded before qt_repo_build() to handle require() clauses before even starting a repo +# build. +include(QtPlatformSupport) + +macro(qt_build_internals_set_up_private_api) + # Qt specific setup common for all modules: + include(QtSetup) + include(FeatureSummary) + + # Optionally include a repo specific Setup module. + include(${PROJECT_NAME}Setup OPTIONAL) + include(QtRepoSetup OPTIONAL) + + # Find Apple frameworks if needed. + qt_find_apple_system_frameworks() + + # Decide whether tools will be built. + qt_check_if_tools_will_be_built() +endmacro() + +macro(qt_enable_cmake_languages) + include(CheckLanguage) + set(__qt_required_language_list C CXX) + set(__qt_optional_language_list ) + + # https://gitlab.kitware.com/cmake/cmake/-/issues/20545 + if(APPLE) + list(APPEND __qt_optional_language_list OBJC OBJCXX) + endif() + + foreach(__qt_lang ${__qt_required_language_list}) + enable_language(${__qt_lang}) + endforeach() + + foreach(__qt_lang ${__qt_optional_language_list}) + check_language(${__qt_lang}) + if(CMAKE_${__qt_lang}_COMPILER) + enable_language(${__qt_lang}) + endif() + endforeach() +endmacro() + +macro(qt_build_repo_begin) + qt_build_internals_set_up_private_api() + qt_enable_cmake_languages() + + # Add global docs targets that will work both for per-repo builds, and super builds. + if(NOT TARGET docs) + add_custom_target(docs) + add_custom_target(prepare_docs) + add_custom_target(generate_docs) + add_custom_target(html_docs) + add_custom_target(qch_docs) + add_custom_target(install_html_docs_docs) + add_custom_target(install_qch_docs_docs) + add_custom_target(install_docs_docs) + endif() + + string(TOLOWER ${PROJECT_NAME} project_name_lower) + + set(qt_docs_target_name docs_${project_name_lower}) + set(qt_docs_prepare_target_name prepare_docs_${project_name_lower}) + set(qt_docs_generate_target_name generate_docs_${project_name_lower}) + set(qt_docs_html_target_name html_docs_${project_name_lower}) + set(qt_docs_qch_target_name qch_docs_${project_name_lower}) + set(qt_docs_install_html_target_name install_html_docs_${project_name_lower}) + set(qt_docs_install_qch_target_name install_qch_docs_${project_name_lower}) + set(qt_docs_install_target_name install_docs_${project_name_lower}) + + add_custom_target(${qt_docs_target_name}) + add_custom_target(${qt_docs_prepare_target_name}) + add_custom_target(${qt_docs_generate_target_name}) + add_custom_target(${qt_docs_qch_target_name}) + add_custom_target(${qt_docs_html_target_name}) + add_custom_target(${qt_docs_install_html_target_name}) + add_custom_target(${qt_docs_install_qch_target_name}) + add_custom_target(${qt_docs_install_target_name}) + + add_dependencies(${qt_docs_generate_target_name} ${qt_docs_prepare_target_name}) + add_dependencies(${qt_docs_html_target_name} ${qt_docs_generate_target_name}) + add_dependencies(${qt_docs_install_html_target_name} ${qt_docs_html_target_name}) + add_dependencies(${qt_docs_install_qch_target_name} ${qt_docs_qch_target_name}) + add_dependencies(${qt_docs_install_target_name} ${qt_docs_install_html_target_name} ${qt_docs_install_qch_target_name}) + + # Make global doc targets depend on the module ones. + add_dependencies(docs ${qt_docs_target_name}) + add_dependencies(prepare_docs ${qt_docs_prepare_target_name}) + add_dependencies(generate_docs ${qt_docs_generate_target_name}) + add_dependencies(html_docs ${qt_docs_qch_target_name}) + add_dependencies(qch_docs ${qt_docs_html_target_name}) + add_dependencies(install_html_docs_docs ${qt_docs_install_html_target_name}) + add_dependencies(install_qch_docs_docs ${qt_docs_install_qch_target_name}) + add_dependencies(install_docs_docs ${qt_docs_install_target_name}) +endmacro() + +macro(qt_build_repo_end) + if(NOT QT_BUILD_STANDALONE_TESTS) + # Delayed actions on some of the Qt targets: + include(QtPostProcess) + + # Install the repo-specific cmake find modules. + qt_path_join(__qt_repo_install_dir ${QT_CONFIG_INSTALL_DIR} ${INSTALL_CMAKE_NAMESPACE}) + + if(NOT PROJECT_NAME STREQUAL "QtBase") + if (EXISTS cmake) + qt_copy_or_install(DIRECTORY cmake/ + DESTINATION "${__qt_repo_install_dir}" + FILES_MATCHING PATTERN "Find*.cmake" + ) + endif() + endif() + + if(NOT QT_SUPERBUILD) + qt_print_feature_summary() + endif() + endif() + + if(NOT QT_SUPERBUILD) + qt_print_build_instructions() + endif() +endmacro() + +macro(qt_build_repo) + qt_build_repo_begin(${ARGN}) + + # If testing is enabled, try to find the qtbase Test package. + # Do this before adding src, because there might be test related conditions + # in source. + if (BUILD_TESTING AND NOT QT_BUILD_STANDALONE_TESTS) + find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS Test) + endif() + + if(NOT QT_BUILD_STANDALONE_TESTS) + if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/CMakeLists.txt") + add_subdirectory(src) + endif() + + if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tools/CMakeLists.txt") + add_subdirectory(tools) + endif() + endif() + + if (BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/CMakeLists.txt") + add_subdirectory(tests) + if(QT_NO_MAKE_TESTS) + set_property(DIRECTORY tests PROPERTY EXCLUDE_FROM_ALL TRUE) + endif() + endif() + + qt_build_repo_end() + + if (BUILD_EXAMPLES AND BUILD_SHARED_LIBS + AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/examples/CMakeLists.txt" + AND NOT QT_BUILD_STANDALONE_TESTS) + add_subdirectory(examples) + if(QT_NO_MAKE_EXAMPLES) + set_property(DIRECTORY examples PROPERTY EXCLUDE_FROM_ALL TRUE) + endif() + endif() +endmacro() + +macro(qt_set_up_standalone_tests_build) + # Remove this macro once all usages of it have been removed. + # Standalone tests are not handled via the main repo project and qt_build_tests. +endmacro() + +function(qt_get_standalone_tests_confg_files_path out_var) + set(path "${QT_CONFIG_INSTALL_DIR}/${INSTALL_CMAKE_NAMESPACE}BuildInternals/StandaloneTests") + set("${out_var}" "${path}" PARENT_SCOPE) +endfunction() + +macro(qt_build_tests) + if(QT_BUILD_STANDALONE_TESTS) + # Find location of TestsConfig.cmake. These contain the modules that need to be + # find_package'd when testing. + qt_get_standalone_tests_confg_files_path(_qt_build_tests_install_prefix) + if(QT_WILL_INSTALL) + qt_path_join(_qt_build_tests_install_prefix + ${CMAKE_INSTALL_PREFIX} ${_qt_build_tests_install_prefix}) + endif() + include("${_qt_build_tests_install_prefix}/${PROJECT_NAME}TestsConfig.cmake" OPTIONAL) + + # Of course we always need the test module as well. + find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS Test) + + # Set language standards after finding Core, because that's when the relevant + # feature variables are available, and the call in QtSetup is too early when building + # standalone tests, because Core was not find_package()'d yet. + qt_set_language_standards() + endif() + + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/auto/CMakeLists.txt") + add_subdirectory(auto) + endif() + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/benchmarks/CMakeLists.txt" AND QT_BUILD_BENCHMARKS) + add_subdirectory(benchmarks) + endif() + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/manual/CMakeLists.txt") + # add_subdirectory(manual) don't build manual tests for now, because qmake doesn't. + endif() +endmacro() + +macro(qt_examples_build_begin) + # 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. + list(APPEND CMAKE_PREFIX_PATH "${QT_BUILD_DIR}") + list(APPEND QT_EXAMPLES_CMAKE_PREFIX_PATH "${QT_BUILD_DIR}") + # Also make sure the CMake config files do not recreate the already-existing targets + set(QT_NO_CREATE_TARGETS TRUE) + set(BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ${CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "BOTH") +endmacro() + +macro(qt_examples_build_end) + # We use AUTOMOC/UIC/RCC in the examples. Make sure to not fail on a fresh Qt build, that e.g. the moc binary does not exist yet. + + # This function gets all targets below this directory + function(get_all_targets _result _dir) + get_property(_subdirs DIRECTORY "${_dir}" PROPERTY SUBDIRECTORIES) + foreach(_subdir IN LISTS _subdirs) + get_all_targets(${_result} "${_subdir}") + endforeach() + get_property(_sub_targets DIRECTORY "${_dir}" PROPERTY BUILDSYSTEM_TARGETS) + set(${_result} ${${_result}} ${_sub_targets} PARENT_SCOPE) + endfunction() + + get_all_targets(targets "${CMAKE_CURRENT_SOURCE_DIR}") + + 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() + endforeach() + + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ${BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}) +endmacro() + +if (ANDROID) + include(${CMAKE_CURRENT_LIST_DIR}/QtBuildInternalsAndroid.cmake) +endif() diff --git a/cmake/QtBuildInternals/QtStandaloneTestTemplateProject/CMakeLists.txt b/cmake/QtBuildInternals/QtStandaloneTestTemplateProject/CMakeLists.txt new file mode 100644 index 0000000000..a486d1a722 --- /dev/null +++ b/cmake/QtBuildInternals/QtStandaloneTestTemplateProject/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 3.16) +project(qt_single_test VERSION 6.0.0 LANGUAGES C CXX ASM) + +find_package(Qt6 REQUIRED COMPONENTS BuildInternals) + +# Includes QtSetup and friends for private CMake API. +qt_build_internals_set_up_private_api() + +# Find all StandaloneTestsConfig.cmake files, and include them +# This will find all Qt packages that are required for standalone tests. +# It will find more packages that needed for a certain test, but will ensure any test can +# be built. +qt_get_standalone_tests_confg_files_path(standalone_tests_config_path) +file(GLOB config_files "${standalone_tests_config_path}/*") +foreach(file ${config_files}) + include("${file}") +endforeach() + +# Get the absolute path of the passed-in project dir, relative to the current working directory +# of the calling script, rather than relative to this source directory. +# The calling script sets PWD. If not set, just use the passed-in value as-is. +if(DEFINED PWD) + get_filename_component(absolute_project_path "${QT_STANDALONE_TEST_PATH}" ABSOLUTE + BASE_DIR "${PWD}") +else() + set(absolute_project_path "${QT_STANDALONE_TEST_PATH}") +endif() + +# Add the test project path as a subdirectory project. +add_subdirectory("${absolute_project_path}" "build_dir") |