d436023b6a
The first issue is that instead of arg_OUTPUT_TARGET we should use rcc_OUTPUT_TARGET (there was also a typo in the OUTPUT word). The second issue came with the fact that the object library targets that were created for resources had a "Qt6::" namespace prefix in the exported Targets files, and yet the link generator expression did not contain the prefix. This failed when building qtsvg in a static build, because the exported object library could not be found. The solution is to use the TARGET_NAME generator expression which takes care of adjusting the name of the target when exported, thus making the linking work both when building qtbase and when building qtsvg. This had the fallout, that all resource object libraries need to be associated with an export set and installed. This wasn't the case for plugins, because plugins have an export name of the form "FooTargets", whereas the export name for the resource object library is "Qt6FooTargets". Adjust the export names of plugins to be the same as for modules and resource library objects (aka contain the "Qt6 prefix"). Change-Id: I1ca28d20c51e4447e5783cc20571a68ec77f6513 Reviewed-by: Qt CMake Build Bot Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
3071 lines
121 KiB
CMake
3071 lines
121 KiB
CMake
include(CMakePackageConfigHelpers)
|
|
|
|
# Install locations:
|
|
set(INSTALL_BINDIR "bin" CACHE PATH "Executables [PREFIX/bin]")
|
|
set(INSTALL_INCLUDEDIR "include" CACHE PATH "Header files [PREFIX/include]")
|
|
set(INSTALL_LIBDIR "lib" CACHE PATH "Libraries [PREFIX/lib]")
|
|
set(INSTALL_ARCHDATADIR "." CACHE PATH "Arch-dependent data [PREFIX]")
|
|
set(INSTALL_PLUGINSDIR "${INSTALL_ARCHDATADIR}/plugins" CACHE PATH
|
|
"Plugins [ARCHDATADIR/plugins]")
|
|
|
|
set(INSTALL_TARGETS_DEFAULT_ARGS
|
|
RUNTIME DESTINATION "${INSTALL_BINDIR}"
|
|
LIBRARY DESTINATION "${INSTALL_LIBDIR}"
|
|
ARCHIVE DESTINATION "${INSTALL_LIBDIR}" COMPONENT Devel
|
|
INCLUDES DESTINATION "${INSTALL_INCLUDEDIR}"
|
|
)
|
|
|
|
if (WIN32)
|
|
set(_default_libexec "${INSTALL_ARCHDATADIR}/bin")
|
|
else()
|
|
set(_default_libexec "${INSTALL_ARCHDATADIR}/libexec")
|
|
endif()
|
|
|
|
set(INSTALL_LIBEXECDIR "${_default_libexec}" CACHE PATH
|
|
"Helper programs [ARCHDATADIR/bin on Windows, ARCHDATADIR/libexec otherwise]")
|
|
set(INSTALL_IMPORTDIR "${INSTALL_ARCHDATADIR}/imports" CACHE PATH
|
|
"QML1 imports [ARCHDATADIR/imports]")
|
|
set(INSTALL_QMLDIR "${INSTALL_ARCHDATADIR}/qml" CACHE PATH
|
|
"QML2 imports [ARCHDATADIR/qml]")
|
|
set(INSTALL_DATADIR "." CACHE PATH "Arch-independent data [PREFIX]")
|
|
set(INSTALL_DOCDIR "${INSTALL_DATADIR}/doc" CACHE PATH "Documentation [DATADIR/doc]")
|
|
set(INSTALL_TRANSLATIONSDIR "${INSTALL_DATADIR}/translations" CACHE PATH
|
|
"Translations [DATADIR/translations]")
|
|
set(INSTALL_SYSCONFDIR "etc/xdg" CACHE PATH
|
|
"Settings used by Qt programs [PREFIX/etc/xdg]")
|
|
set(INSTALL_EXAMPLESDIR "examples" CACHE PATH "Examples [PREFIX/examples]")
|
|
set(INSTALL_TESTSDIR "tests" CACHE PATH "Tests [PREFIX/tests]")
|
|
|
|
# The variables might have already been set in QtBuildInternalsExtra.cmake if the file is included
|
|
# while building a new module and not QtBase. In that case, stop overriding the value.
|
|
if(NOT INSTALL_CMAKE_NAMESPACE)
|
|
set(INSTALL_CMAKE_NAMESPACE "Qt${PROJECT_VERSION_MAJOR}"
|
|
CACHE STRING "CMake namespace [Qt${PROJECT_VERSION_MAJOR}]")
|
|
endif()
|
|
if(NOT QT_CMAKE_EXPORT_NAMESPACE)
|
|
set(QT_CMAKE_EXPORT_NAMESPACE "Qt${PROJECT_VERSION_MAJOR}"
|
|
CACHE STRING "CMake namespace used when exporting targets [Qt${PROJECT_VERSION_MAJOR}]")
|
|
endif()
|
|
|
|
set(QT_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}")
|
|
|
|
# the default RPATH to be used when installing, but only if it's not a system directory
|
|
LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir)
|
|
IF("${isSystemDir}" STREQUAL "-1")
|
|
SET(_default_install_rpath "${CMAKE_INSTALL_PREFIX}/lib")
|
|
ENDIF("${isSystemDir}" STREQUAL "-1")
|
|
|
|
# Default rpath settings: Use rpath for build tree as well as a full path for the installed binaries.
|
|
# For origin builds, one needs to override CMAKE_INSTALL_RPATH for example with $ORIGIN/../lib
|
|
SET(CMAKE_INSTALL_RPATH "${_default_install_rpath}" CACHE PATH "RPATH for installed binaries")
|
|
|
|
# add the automatically determined parts of the RPATH
|
|
# which point to directories outside the build tree to the install RPATH
|
|
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
|
|
|
# Platform define path, etc.
|
|
set(QT_QMAKE_TARGET_MKSPEC "")
|
|
if(WIN32)
|
|
set(QT_DEFAULT_PLATFORM_DEFINITIONS UNICODE _UNICODE WIN32 _ENABLE_EXTENDED_ALIGNED_STORAGE)
|
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
|
list(APPEND QT_DEFAULT_PLATFORM_DEFINITIONS WIN64 _WIN64)
|
|
endif()
|
|
if(MSVC)
|
|
set(QT_QMAKE_TARGET_MKSPEC win32-msvc)
|
|
elseif(CLANG)
|
|
set(QT_QMAKE_TARGET_MKSPEC win32-clang)
|
|
elseif(MINGW)
|
|
set(QT_QMAKE_TARGET_MKSPEC win32-g++)
|
|
list(APPEND QT_DEFAULT_PLATFORM_DEFINITIONS _WIN32_WINNT=0x0601)
|
|
endif()
|
|
elseif(LINUX)
|
|
if(GCC)
|
|
set(QT_QMAKE_TARGET_MKSPEC linux-g++)
|
|
elseif(CLANG)
|
|
set(QT_QMAKE_TARGET_MKSPEC linux-clang)
|
|
elseif(ICC)
|
|
set(QT_QMAKE_TARGET_MKSPEC linux-icc-64)
|
|
endif()
|
|
elseif(ANDROID)
|
|
if(GCC)
|
|
set(QT_QMAKE_TARGET_MKSPEC android-g++)
|
|
elseif(CLANG)
|
|
set(QT_QMAKE_TARGET_MKSPEC android-clang)
|
|
endif()
|
|
elseif(APPLE)
|
|
set(QT_QMAKE_TARGET_MKSPEC macx-clang)
|
|
elseif(EMSCRIPTEN)
|
|
set(QT_QMAKE_TARGET_MKSPEC wasm-emscripten)
|
|
endif()
|
|
|
|
# TODO: Fixme to be correct.
|
|
set(QT_QMAKE_HOST_MKSPEC "${QT_QMAKE_TARGET_MKSPEC}")
|
|
|
|
if(QT_QMAKE_TARGET_MKSPEC)
|
|
set(QT_DEFAULT_PLATFORM_DEFINITION_DIR mkspecs/${QT_QMAKE_TARGET_MKSPEC})
|
|
endif()
|
|
|
|
if(NOT DEFINED QT_DEFAULT_PLATFORM_DEFINITIONS)
|
|
set(QT_DEFAULT_PLATFORM_DEFINITIONS "")
|
|
endif()
|
|
|
|
set(QT_PLATFORM_DEFINITIONS ${QT_DEFAULT_PLATFORM_DEFINITIONS}
|
|
CACHE STRING "Qt platform specific pre-processor defines")
|
|
set(QT_PLATFORM_DEFINITION_DIR ${QT_DEFAULT_PLATFORM_DEFINITION_DIR}
|
|
CACHE PATH "Path to directory that contains qplatformdefs.h")
|
|
set(QT_NAMESPACE "" CACHE STRING "Qt Namespace")
|
|
if(QT_NAMESPACE STREQUAL "")
|
|
set(QT_HAS_NAMESPACE OFF)
|
|
else()
|
|
set(QT_HAS_NAMESPACE ON)
|
|
endif()
|
|
|
|
|
|
function(qt_internal_clear_qt_repo_known_modules)
|
|
set(QT_REPO_KNOWN_MODULES "" CACHE INTERNAL "Known current repo Qt modules" FORCE)
|
|
endfunction()
|
|
|
|
function(qt_internal_add_qt_repo_known_module)
|
|
set(QT_REPO_KNOWN_MODULES ${QT_REPO_KNOWN_MODULES} ${ARGN}
|
|
CACHE INTERNAL "Known current repo Qt modules" FORCE)
|
|
endfunction()
|
|
|
|
function(qt_internal_get_qt_repo_known_modules out_var)
|
|
set("${out_var}" "${QT_REPO_KNOWN_MODULES}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Gets the list of all known Qt modules both found and that were built as part of the
|
|
# current project.
|
|
function(qt_internal_get_qt_all_known_modules out_var)
|
|
qt_internal_get_qt_repo_known_modules(repo_known_modules)
|
|
set(known_modules ${QT_ALL_MODULES_FOUND_VIA_FIND_PACKAGE} ${repo_known_modules})
|
|
list(REMOVE_DUPLICATES known_modules)
|
|
set("${out_var}" "${known_modules}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
macro(qt_internal_set_qt_known_plugins)
|
|
set(QT_KNOWN_PLUGINS ${ARGN} CACHE INTERNAL "Known Qt plugins" FORCE)
|
|
endmacro()
|
|
|
|
# Reset:
|
|
qt_internal_clear_qt_repo_known_modules("")
|
|
qt_internal_set_qt_known_plugins("")
|
|
|
|
set(QT_KNOWN_MODULES_WITH_TOOLS "" CACHE INTERNAL "Known Qt modules with tools" FORCE)
|
|
macro(qt_internal_append_known_modules_with_tools module)
|
|
if(NOT ${module} IN_LIST QT_KNOWN_MODULES_WITH_TOOLS)
|
|
set(QT_KNOWN_MODULES_WITH_TOOLS "${QT_KNOWN_MODULES_WITH_TOOLS};${module}"
|
|
CACHE INTERNAL "Known Qt modules with tools" FORCE)
|
|
endif()
|
|
endmacro()
|
|
|
|
macro(qt_internal_append_known_module_tool module tool)
|
|
if(NOT ${tool} IN_LIST QT_KNOWN_MODULE_${module}_TOOLS)
|
|
list(APPEND QT_KNOWN_MODULE_${module}_TOOLS "${tool}")
|
|
set(QT_KNOWN_MODULE_${module}_TOOLS "${QT_KNOWN_MODULE_${module}_TOOLS}"
|
|
CACHE INTERNAL "Known Qt module ${module} tools" FORCE)
|
|
endif()
|
|
endmacro()
|
|
|
|
# Reset syncqt cache variable, to make sure it gets recomputed on reconfiguration, otherwise
|
|
# it might not get installed.
|
|
unset(QT_SYNCQT CACHE)
|
|
|
|
# For adjusting variables when running tests, we need to know what
|
|
# the correct variable is for separating entries in PATH-alike
|
|
# variables.
|
|
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
|
|
set(QT_PATH_SEPARATOR "\\;")
|
|
else()
|
|
set(QT_PATH_SEPARATOR ":")
|
|
endif()
|
|
|
|
# Compute the values of QT_BUILD_DIR, QT_INSTALL_DIR, QT_CONFIG_BUILD_DIR, QT_CONFIG_INSTALL_DIR
|
|
# taking into account whether the current build is a prefix build or a non-prefix build.
|
|
#
|
|
# These values should be prepended to file paths in commands or properties,
|
|
# in order to correctly place generated Config files, generated Targets files,
|
|
# excutables / libraries, when copying / installing files, etc.
|
|
#
|
|
# The build dir variables will always be absolute paths.
|
|
# The QT_INSTALL_DIR variable will have a relative path in a prefix build,
|
|
# which means that it can be empty, so use qt_join_path to prevent accidental absolute paths.
|
|
if(QT_WILL_INSTALL)
|
|
# In the usual prefix build case, the build dir is the current module build dir,
|
|
# and the install dir is the prefix, so we don't set it.
|
|
set(QT_BUILD_DIR "${CMAKE_BINARY_DIR}")
|
|
set(QT_INSTALL_DIR "")
|
|
else()
|
|
# When doing a non-prefix build, both the build dir and install dir are the same,
|
|
# pointing to the qtbase build dir.
|
|
set(QT_BUILD_DIR "${CMAKE_INSTALL_PREFIX}")
|
|
set(QT_INSTALL_DIR "${QT_BUILD_DIR}")
|
|
endif()
|
|
set(__config_path_part "${INSTALL_LIBDIR}/cmake")
|
|
set(QT_CONFIG_BUILD_DIR "${QT_BUILD_DIR}/${__config_path_part}")
|
|
set(QT_CONFIG_INSTALL_DIR "${QT_INSTALL_DIR}")
|
|
if(QT_CONFIG_INSTALL_DIR)
|
|
string(APPEND QT_CONFIG_INSTALL_DIR "/")
|
|
endif()
|
|
string(APPEND QT_CONFIG_INSTALL_DIR ${__config_path_part})
|
|
unset(__config_path_part)
|
|
|
|
# This is used to hold extra cmake code that should be put into QtBuildInternalsExtra.cmake file
|
|
# at the QtPostProcess stage.
|
|
set(QT_BUILD_INTERNALS_EXTRA_CMAKE_CODE "")
|
|
|
|
# Save the value of the current first project source dir.
|
|
# This will be /path/to/qtbase for qtbase both in a super-build and a non super-build.
|
|
# This will be /path/to/qtbase/tests when building standalone tests.
|
|
set(QT_TOP_LEVEL_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
|
|
|
# Functions and macros:
|
|
|
|
# qt_remove_args can remove arguments from an existing list of function
|
|
# arguments in order to pass a filtered list of arguments to a different function.
|
|
# Parameters:
|
|
# out_var: result of remove all arguments specified by ARGS_TO_REMOVE from ALL_ARGS
|
|
# ARGS_TO_REMOVE: Arguments to remove.
|
|
# ALL_ARGS: All arguments supplied to cmake_parse_arguments or
|
|
# qt_parse_all_arguments
|
|
# from which ARGS_TO_REMOVE should be removed from. We require all the
|
|
# arguments or we can't properly identify the range of the arguments detailed
|
|
# in ARGS_TO_REMOVE.
|
|
# ARGS: Arguments passed into the function, usually ${ARGV}
|
|
#
|
|
# E.g.:
|
|
# We want to forward all arguments from foo to bar, execpt ZZZ since it will
|
|
# trigger an error in bar.
|
|
#
|
|
# foo(target BAR .... ZZZ .... WWW ...)
|
|
# bar(target BAR.... WWW...)
|
|
#
|
|
# function(foo target)
|
|
# qt_parse_all_arguments(arg "" "" "BAR;ZZZ;WWW ${ARGV})
|
|
# qt_remove_args(forward_args
|
|
# ARGS_TO_REMOVE ${target} ZZZ
|
|
# ALL_ARGS ${target} BAR ZZZ WWW
|
|
# ARGS ${ARGV}
|
|
# )
|
|
# bar(${target} ${forward_args})
|
|
# endfunction()
|
|
#
|
|
function(qt_remove_args out_var)
|
|
cmake_parse_arguments(arg "" "" "ARGS_TO_REMOVE;ALL_ARGS;ARGS" ${ARGN})
|
|
set(result ${arg_ARGS})
|
|
foreach(arg IN LISTS arg_ARGS_TO_REMOVE)
|
|
# find arg
|
|
list(FIND result ${arg} find_result)
|
|
if (NOT find_result EQUAL -1)
|
|
# remove arg
|
|
list(REMOVE_AT result ${find_result})
|
|
list(LENGTH result result_len)
|
|
list(GET result ${find_result} arg_current)
|
|
# remove values until we hit another arg
|
|
while(NOT ${arg_current} IN_LIST arg_ALL_ARGS AND find_result LESS result_len)
|
|
list(REMOVE_AT result ${find_result})
|
|
list(GET result ${find_result} arg_current)
|
|
list(LENGTH result result_len)
|
|
endwhile()
|
|
endif()
|
|
endforeach()
|
|
set(${out_var} "${result}" PARENT_SCOPE)
|
|
endfunction()
|
|
# Wraps install() command. In a prefix build, simply passes along arguments to install().
|
|
# In a non-prefix build, handles association of targets to export names, and also calls export().
|
|
function(qt_install)
|
|
set(flags)
|
|
set(options EXPORT DESTINATION NAMESPACE)
|
|
set(multiopts TARGETS)
|
|
cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN})
|
|
|
|
if(arg_TARGETS)
|
|
set(is_install_targets TRUE)
|
|
endif()
|
|
|
|
# In a prefix build, always invoke install() without modification.
|
|
# In a non-prefix build, pass install(TARGETS) commands to allow
|
|
# association of targets to export names, so we can later use the export names
|
|
# in export() commands.
|
|
if(QT_WILL_INSTALL OR is_install_targets)
|
|
install(${ARGV})
|
|
endif()
|
|
|
|
# Exit early if this is a prefix build.
|
|
if(QT_WILL_INSTALL)
|
|
return()
|
|
endif()
|
|
|
|
# In a non-prefix build, when install(EXPORT) is called,
|
|
# also call export(EXPORT) to generate build tree target files.
|
|
if(NOT is_install_targets AND arg_EXPORT)
|
|
set(namespace_option "")
|
|
if(arg_NAMESPACE)
|
|
set(namespace_option NAMESPACE ${arg_NAMESPACE})
|
|
endif()
|
|
export(EXPORT ${arg_EXPORT}
|
|
${namespace_option}
|
|
FILE "${arg_DESTINATION}/${arg_EXPORT}.cmake")
|
|
endif()
|
|
endfunction()
|
|
|
|
# Copies files using file(COPY) signature in non-prefix builds.
|
|
function(qt_non_prefix_copy)
|
|
if(NOT QT_WILL_INSTALL)
|
|
file(${ARGV})
|
|
endif()
|
|
endfunction()
|
|
|
|
# Use case is installing files in a prefix build, or copying them to the correct build dir
|
|
# in a non-prefix build.
|
|
# Pass along arguments as you would pass them to install().
|
|
# Only supports FILES, PROGRAMS and DIRECTORY signature, and without fancy things
|
|
# like OPTIONAL or RENAME or COMPONENT.
|
|
function(qt_copy_or_install)
|
|
set(flags FILES PROGRAMS DIRECTORY)
|
|
set(options)
|
|
set(multiopts)
|
|
cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN})
|
|
|
|
# Remember which option has to be passed to the install command.
|
|
set(argv_copy ${ARGV})
|
|
if(arg_FILES)
|
|
set(install_option "FILES")
|
|
elseif(arg_PROGRAMS)
|
|
set(install_option "PROGRAMS")
|
|
elseif(arg_DIRECTORY)
|
|
set(install_option "DIRECTORY")
|
|
endif()
|
|
|
|
list(REMOVE_AT argv_copy 0)
|
|
qt_install(${install_option} ${argv_copy})
|
|
qt_non_prefix_copy(COPY ${argv_copy})
|
|
endfunction()
|
|
|
|
# Hacky way to remove the install target in non-prefix builds.
|
|
# We need to associate targets with export names, and that is only possible to do with the
|
|
# install(TARGETS) command. But in a non-prefix build, we don't want to install anything.
|
|
# To make sure that developers don't accidentally run make install, replace the generated
|
|
# cmake_install.cmake file with an empty file. To do this, always create a new temporary file
|
|
# at CMake configuration step, and use it as an input to a custom command that replaces the
|
|
# cmake_install.cmake file with an empty one. This means we will always replace the file on
|
|
# every reconfiguration, but not when doing null builds.
|
|
function(remove_install_target)
|
|
set(file_in "${CMAKE_BINARY_DIR}/.remove_cmake_install_in.txt")
|
|
set(file_generated "${CMAKE_BINARY_DIR}/.remove_cmake_install_generated.txt")
|
|
set(cmake_install_file "${CMAKE_BINARY_DIR}/cmake_install.cmake")
|
|
file(WRITE ${file_in} "")
|
|
|
|
add_custom_command(OUTPUT ${file_generated}
|
|
COMMAND ${CMAKE_COMMAND} -E copy ${file_in} ${file_generated}
|
|
COMMAND ${CMAKE_COMMAND} -E remove ${cmake_install_file}
|
|
COMMAND ${CMAKE_COMMAND} -E touch ${cmake_install_file}
|
|
COMMENT "Removing cmake_install.cmake"
|
|
MAIN_DEPENDENCY ${file_in})
|
|
|
|
add_custom_target(remove_cmake_install ALL DEPENDS ${file_generated})
|
|
endfunction()
|
|
|
|
function(qt_set_up_nonprefix_build)
|
|
if(NOT QT_WILL_INSTALL)
|
|
remove_install_target()
|
|
endif()
|
|
endfunction()
|
|
|
|
function(qt_is_imported_target target out_var)
|
|
if(NOT TARGET "${target}")
|
|
set(target "${QT_CMAKE_EXPORT_NAMESPACE}::${target}")
|
|
endif()
|
|
if(NOT TARGET "${target}")
|
|
message(FATAL_ERROR "Invalid target given to qt_is_imported_target: ${target}")
|
|
endif()
|
|
get_target_property(is_imported "${target}" IMPORTED)
|
|
set(${out_var} "${is_imported}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Generates module .pri files for consumption by qmake
|
|
function(qt_generate_module_pri_file target target_path pri_files_var)
|
|
set(flags INTERNAL_MODULE HEADER_MODULE)
|
|
set(options)
|
|
set(multiopts QMAKE_MODULE_CONFIG)
|
|
cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN})
|
|
|
|
qt_internal_module_info(module "${target}")
|
|
set(pri_files)
|
|
|
|
set(property_prefix)
|
|
if(arg_HEADER_MODULE)
|
|
set(property_prefix "interface_")
|
|
endif()
|
|
|
|
get_target_property(enabled_features "${target}"
|
|
"${property_prefix}QT_ENABLED_PUBLIC_FEATURES")
|
|
get_target_property(disabled_features "${target}"
|
|
"${property_prefix}QT_DISABLED_PUBLIC_FEATURES")
|
|
get_target_property(enabled_private_features "${target}"
|
|
"${property_prefix}QT_ENABLED_PRIVATE_FEATURES")
|
|
get_target_property(disabled_private_features "${target}"
|
|
"${property_prefix}QT_DISABLED_PRIVATE_FEATURES")
|
|
|
|
foreach(var enabled_features disabled_features enabled_private_features disabled_private_features)
|
|
if(${var} STREQUAL "${var}-NOTFOUND")
|
|
set(${var} "")
|
|
else()
|
|
string (REPLACE ";" " " ${var} "${${var}}")
|
|
endif()
|
|
endforeach()
|
|
|
|
if(arg_QMAKE_MODULE_CONFIG)
|
|
string(REPLACE ";" " " module_config "${arg_QMAKE_MODULE_CONFIG}")
|
|
set(module_config "\nQT.${module_lower}.CONFIG = ${module_config}")
|
|
else()
|
|
set(module_config "")
|
|
endif()
|
|
|
|
if (NOT ${arg_INTERNAL_MODULE})
|
|
qt_path_join(pri_file_name "${target_path}" "qt_lib_${module_lower}.pri")
|
|
list(APPEND pri_files "${pri_file_name}")
|
|
|
|
file(GENERATE
|
|
OUTPUT "${pri_file_name}"
|
|
CONTENT
|
|
"QT.${module_lower}.VERSION = ${PROJECT_VERSION}
|
|
QT.${module_lower}.name = ${module}
|
|
QT.${module_lower}.module = ${module_versioned}
|
|
QT.${module_lower}.libs = $$QT_MODULE_LIB_BASE
|
|
QT.${module_lower}.includes = $$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/${module}
|
|
QT.${module_lower}.frameworks =
|
|
QT.${module_lower}.bins = $$QT_MODULE_BIN_BASE
|
|
QT.${module_lower}.depends =
|
|
QT.${module_lower}.uses =
|
|
QT.${module_lower}.module_config = v2
|
|
QT.${module_lower}.DEFINES = QT_${module_define}_LIB
|
|
QT.${module_lower}.enabled_features = ${enabled_features}
|
|
QT.${module_lower}.disabled_features = ${disabled_features}${module_config}
|
|
QT_MODULES += ${module_lower}
|
|
"
|
|
)
|
|
endif()
|
|
|
|
qt_path_join(private_pri_file "${target_path}" "qt_lib_${module_lower}_private.pri")
|
|
list(APPEND pri_files "${private_pri_file}")
|
|
|
|
file(GENERATE
|
|
OUTPUT "${private_pri_file}"
|
|
CONTENT
|
|
"QT.${module_lower}_private.VERSION = ${PROJECT_VERSION}
|
|
QT.${module_lower}_private.name = ${module}
|
|
QT.${module_lower}_private.module =
|
|
QT.${module_lower}_private.libs = $$QT_MODULE_LIB_BASE
|
|
QT.${module_lower}_private.includes = $$QT_MODULE_INCLUDE_BASE/${module}/${PROJECT_VERSION} $$QT_MODULE_INCLUDE_BASE/${module}/${PROJECT_VERSION}/${module}
|
|
QT.${module_lower}_private.frameworks =
|
|
QT.${module_lower}_private.depends = ${module_lower}
|
|
QT.${module_lower}_private.uses =
|
|
QT.${module_lower}_private.module_config = v2
|
|
QT.${module_lower}_private.enabled_features = ${enabled_private_features}
|
|
QT.${module_lower}_private.disabled_features = ${disabled_private_features}
|
|
"
|
|
)
|
|
|
|
set("${pri_files_var}" "${pri_files}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
function(qt_generate_global_config_pri_file)
|
|
qt_path_join(qconfig_pri_target_path ${PROJECT_BINARY_DIR} mkspecs)
|
|
qt_path_join(qconfig_pri_target_path "${qconfig_pri_target_path}" "qconfig.pri")
|
|
|
|
get_target_property(enabled_features GlobalConfig INTERFACE_QT_ENABLED_PUBLIC_FEATURES)
|
|
get_target_property(disabled_features GlobalConfig INTERFACE_QT_DISABLED_PUBLIC_FEATURES)
|
|
|
|
# configure2cmake skips the "static" feature, so emulate it here for qmake support:
|
|
if(QT_BUILD_SHARED_LIBS OR BUILD_SHARED_LIBS)
|
|
list(APPEND enabled_features shared)
|
|
list(APPEND disabled_features static)
|
|
set(qt_build_config_type "shared")
|
|
else()
|
|
list(APPEND enabled_features static)
|
|
list(APPEND disabled_features shared)
|
|
set(qt_build_config_type "static")
|
|
endif()
|
|
|
|
# configure2cmake skips the "rpath" feature, so emulate it here for qmake support:
|
|
if(CMAKE_SKIP_RPATH)
|
|
list(APPEND disabled_features rpath)
|
|
elseif(LINUX OR APPLE)
|
|
list(APPEND enabled_features rpath)
|
|
endif()
|
|
|
|
string (REPLACE ";" " " enabled_features "${enabled_features}")
|
|
string (REPLACE ";" " " disabled_features "${disabled_features}")
|
|
|
|
# Add some required CONFIG entries.
|
|
set(config_entries "")
|
|
if(CMAKE_BUILD_TYPE STREQUAL Debug)
|
|
list(APPEND config_entries "debug")
|
|
elseif(CMAKE_BUILD_TYPE STREQUAL Release)
|
|
list(APPEND config_entries "release")
|
|
endif()
|
|
list(APPEND config_entries "${qt_build_config_type}")
|
|
string (REPLACE ";" " " config_entries "${config_entries}")
|
|
|
|
file(GENERATE
|
|
OUTPUT "${qconfig_pri_target_path}"
|
|
CONTENT
|
|
"QT_ARCH = ${TEST_architecture_arch}
|
|
QT_BUILDABI = ${TEST_buildAbi}
|
|
QT.global.enabled_features = ${enabled_features}
|
|
QT.global.disabled_features = ${disabled_features}
|
|
QT_VERSION = ${PROJECT_VERSION}
|
|
QT_MAJOR_VERSION = ${PROJECT_VERSION_MAJOR}
|
|
QT_MINOR_VERSION = ${PROJECT_VERSION_MINOR}
|
|
QT_PATCH_VERSION = ${PROJECT_VERSION_PATCH}
|
|
CONFIG -= link_prl # we do not create prl files right now
|
|
CONFIG += ${config_entries}
|
|
"
|
|
)
|
|
qt_install(FILES "${qconfig_pri_target_path}" DESTINATION mkspecs)
|
|
endfunction()
|
|
|
|
# Takes a list of path components and joins them into one path separated by forward slashes "/",
|
|
# and saves the path in out_var.
|
|
function(qt_path_join out_var)
|
|
# Remove output variable.
|
|
set(argv ${ARGV})
|
|
list(REMOVE_AT argv 0)
|
|
|
|
# Join the path components.
|
|
string(JOIN "/" path ${argv})
|
|
set(${out_var} ${path} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
function(qt_internal_export_modern_cmake_config_targets_file)
|
|
cmake_parse_arguments(__arg "" "EXPORT_NAME_PREFIX;CONFIG_INSTALL_DIR" "TARGETS" ${ARGN})
|
|
|
|
set(export_name "${__arg_EXPORT_NAME_PREFIX}VersionlessTargets")
|
|
foreach(target ${__arg_TARGETS})
|
|
if (TARGET "${target}Versionless")
|
|
continue()
|
|
endif()
|
|
|
|
add_library("${target}Versionless" INTERFACE)
|
|
target_link_libraries("${target}Versionless" INTERFACE "${target}")
|
|
set_target_properties("${target}Versionless" PROPERTIES EXPORT_NAME "${target}")
|
|
qt_install(TARGETS "${target}Versionless" EXPORT ${export_name})
|
|
endforeach()
|
|
qt_install(EXPORT ${export_name} NAMESPACE Qt:: DESTINATION "${__arg_CONFIG_INSTALL_DIR}")
|
|
endfunction()
|
|
|
|
# Print all variables defined in the current scope.
|
|
macro(qt_debug_print_variables)
|
|
cmake_parse_arguments(__arg "DEDUP" "" "MATCH;IGNORE" ${ARGN})
|
|
message("Known Variables:")
|
|
get_cmake_property(__variableNames VARIABLES)
|
|
list (SORT __variableNames)
|
|
if (__arg_DEDUP)
|
|
list(REMOVE_DUPLICATES __variableNames)
|
|
endif()
|
|
|
|
foreach(__var ${__variableNames})
|
|
set(__ignore OFF)
|
|
foreach(__i ${__arg_IGNORE})
|
|
if(__var MATCHES "${__i}")
|
|
set(__ignore ON)
|
|
break()
|
|
endif()
|
|
endforeach()
|
|
|
|
if (__ignore)
|
|
continue()
|
|
endif()
|
|
|
|
set(__show OFF)
|
|
foreach(__i ${__arg_MATCH})
|
|
if(__var MATCHES "${__i}")
|
|
set(__show ON)
|
|
break()
|
|
endif()
|
|
endforeach()
|
|
|
|
if (__show)
|
|
message(" ${__var}=${${__var}}.")
|
|
endif()
|
|
endforeach()
|
|
endmacro()
|
|
|
|
|
|
macro(assert)
|
|
if (${ARGN})
|
|
else()
|
|
message(FATAL_ERROR "ASSERT: ${ARGN}.")
|
|
endif()
|
|
endmacro()
|
|
|
|
|
|
function(qt_create_nolink_target target dependee_target)
|
|
if(NOT TARGET "${target}")
|
|
message(FATAL_ERROR "${target} does not exist when trying to build a nolink target.")
|
|
endif()
|
|
get_target_property(type "${target}" TYPE)
|
|
if(type STREQUAL EXECUTABLE)
|
|
message(FATAL_ERROR "${target} must be a library of some kind.")
|
|
endif()
|
|
if(type STREQUAL OBJECT_LIBRARY)
|
|
message(FATAL_ERROR "${target} must not be an object library.")
|
|
endif()
|
|
|
|
# Strip off the namespace prefix, so from Vulkan::Vulkan to Vulkan, and then append _nolink.
|
|
string(REGEX REPLACE "^.*::" "" non_prefixed_target ${target})
|
|
set(nolink_target "${non_prefixed_target}_nolink")
|
|
|
|
# Create the nolink interface target, assign the properties from the original target,
|
|
# associate the nolink target with the same export which contains
|
|
# the target that uses the _nolink target.
|
|
# Also create a namespaced alias of the form {$target}::${target}_nolink which is used by
|
|
# our modules.
|
|
if(NOT TARGET "${nolink_target}")
|
|
add_library("${nolink_target}" INTERFACE)
|
|
set(prefixed_nolink_target "${target}_nolink")
|
|
set_target_properties("${nolink_target}" PROPERTIES
|
|
INTERFACE_INCLUDE_DIRECTORIES
|
|
$<TARGET_PROPERTY:${target},INTERFACE_INCLUDE_DIRECTORIES>
|
|
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES
|
|
$<TARGET_PROPERTY:${target},INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>
|
|
INTERFACE_COMPILE_DEFINITIONS
|
|
$<TARGET_PROPERTY:${target},INTERFACE_COMPILE_DEFINITIONS>
|
|
INTERFACE_COMPILE_OPTIONS
|
|
$<TARGET_PROPERTY:${target},INTERFACE_COMPILE_OPTIONS>
|
|
INTERFACE_COMPILE_FEATURES
|
|
$<TARGET_PROPERTY:${target},INTERFACE_COMPILE_FEATURES>)
|
|
|
|
add_library(${prefixed_nolink_target} ALIAS ${nolink_target})
|
|
|
|
set(export_name "${INSTALL_CMAKE_NAMESPACE}${dependee_target}Targets")
|
|
qt_install(TARGETS ${nolink_target} EXPORT ${export_name})
|
|
endif()
|
|
endfunction()
|
|
|
|
function(qt_ensure_perl)
|
|
if(DEFINED HOST_PERL)
|
|
return()
|
|
endif()
|
|
find_program(HOST_PERL "perl" DOC "Perl binary")
|
|
if (NOT HOST_PERL)
|
|
message(FATAL_ERROR "Perl needs to be available to build Qt.")
|
|
endif()
|
|
endfunction()
|
|
|
|
|
|
function(qt_ensure_sync_qt)
|
|
qt_ensure_perl()
|
|
if(DEFINED QT_SYNCQT)
|
|
return()
|
|
endif()
|
|
|
|
# When building qtbase, use the source syncqt, otherwise use the installed one.
|
|
set(SYNCQT_FROM_SOURCE "${QtBase_SOURCE_DIR}/bin/syncqt.pl")
|
|
if(EXISTS "${SYNCQT_FROM_SOURCE}")
|
|
set(QT_SYNCQT "${SYNCQT_FROM_SOURCE}" CACHE FILEPATH "syncqt script")
|
|
message(STATUS "Using source syncqt found at: ${QT_SYNCQT}")
|
|
|
|
qt_path_join(syncqt_install_dir ${QT_INSTALL_DIR} ${INSTALL_LIBEXECDIR})
|
|
qt_copy_or_install(PROGRAMS "${SYNCQT_FROM_SOURCE}"
|
|
DESTINATION "${syncqt_install_dir}")
|
|
else()
|
|
get_filename_component(syncqt_absolute_path
|
|
"${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBEXECDIR}/syncqt.pl"
|
|
ABSOLUTE)
|
|
set(QT_SYNCQT "${syncqt_absolute_path}" CACHE FILEPATH "syncqt script")
|
|
message(STATUS "Using installed syncqt found at: ${QT_SYNCQT}")
|
|
endif()
|
|
endfunction()
|
|
|
|
# A version of cmake_parse_arguments that makes sure all arguments are processed and errors out
|
|
# with a message about ${type} having received unknown arguments.
|
|
macro(qt_parse_all_arguments result type flags options multiopts)
|
|
cmake_parse_arguments(${result} "${flags}" "${options}" "${multiopts}" ${ARGN})
|
|
if(DEFINED ${result}_UNPARSED_ARGUMENTS)
|
|
message(FATAL_ERROR "Unknown arguments were passed to ${type} (${${result}_UNPARSED_ARGUMENTS}).")
|
|
endif()
|
|
endmacro()
|
|
|
|
|
|
function(qt_internal_add_link_flags_no_undefined target)
|
|
if (NOT QT_BUILD_SHARED_LIBS)
|
|
return()
|
|
endif()
|
|
if (GCC OR CLANG)
|
|
if(APPLE)
|
|
set(no_undefined_flag "-Wl,-undefined,error")
|
|
elseif(LINUX OR MINGW OR ANDROID)
|
|
set(no_undefined_flag "-Wl,--no-undefined")
|
|
else()
|
|
message(FATAL_ERROR "Platform linker doesn't support erroring upon encountering undefined symbols. Target:\"${target}\".")
|
|
endif()
|
|
target_link_options("${target}" PRIVATE "${no_undefined_flag}")
|
|
endif()
|
|
endfunction()
|
|
|
|
function(qt_internal_add_link_flags_gc_sections target visibility)
|
|
set(possible_visibilities PRIVATE INTERFACE PUBLIC)
|
|
list(FIND possible_visibilities "${visibility}" known_visibility)
|
|
if (known_visibility EQUAL "-1")
|
|
message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.")
|
|
endif()
|
|
|
|
if ((GCC OR CLANG) AND NOT EMSCRIPTEN)
|
|
if(APPLE)
|
|
set(gc_sections_flag "-Wl,-dead_strip")
|
|
elseif(LINUX OR BSD OR SOLARIS OR WIN32 OR ANDROID)
|
|
set(gc_sections_flag "-Wl,--gc-sections")
|
|
else()
|
|
message(FATAL_ERROR "Platform linker doesn't support gc sections. Target:\"${target}\".")
|
|
endif()
|
|
target_link_options("${target}" ${visibility} "${gc_sections_flag}")
|
|
endif()
|
|
endfunction()
|
|
|
|
function(qt_internal_add_linker_version_script target)
|
|
qt_parse_all_arguments(arg "qt_internal_add_linker" "INTERNAL" "" "PRIVATE_HEADERS" ${ARGN})
|
|
|
|
if (TEST_ld_version_script)
|
|
if (arg_INTERNAL)
|
|
set(contents "Qt_${PROJECT_VERSION_MAJOR}_PRIVATE_API { *; };")
|
|
else()
|
|
set(contents "Qt_${PROJECT_VERSION_MAJOR}_PRIVATE_API {\n qt_private_api_tag*;\n")
|
|
foreach(ph ${arg_PRIVATE_HEADERS})
|
|
string(APPEND contents " @FILE:${ph}@\n")
|
|
endforeach()
|
|
string(APPEND contents "};\n")
|
|
set(current "Qt_${PROJECT_VERSION_MAJOR}")
|
|
if (QT_NAMESPACE STREQUAL "")
|
|
set(tag_symbol "qt_version_tag")
|
|
else()
|
|
set(tag_symbol "qt_version_tag_${QT_NAMESPACE}")
|
|
endif()
|
|
string(APPEND contents "${current} { *; };\n")
|
|
|
|
foreach(minor_version RANGE ${PROJECT_VERSION_MINOR})
|
|
set(previous "${current}")
|
|
set(current "Qt_${PROJECT_VERSION_MAJOR}.${minor_version}")
|
|
if (minor_version EQUAL ${PROJECT_VERSION_MINOR})
|
|
string(APPEND contents "${current} { ${tag_symbol}; } ${previous};\n")
|
|
else()
|
|
string(APPEND contents "${current} {} ${previous};\n")
|
|
endif()
|
|
endforeach()
|
|
|
|
set(infile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version.in")
|
|
set(outfile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version")
|
|
|
|
file(GENERATE OUTPUT "${infile}" CONTENT "${contents}")
|
|
|
|
qt_ensure_perl()
|
|
|
|
add_custom_command(TARGET "${target}" PRE_LINK
|
|
COMMAND "${HOST_PERL}" "${PROJECT_SOURCE_DIR}/mkspecs/features/data/unix/findclasslist.pl" < "${infile}" > "${outfile}"
|
|
BYPRODUCTS "${outfile}" DEPENDS "${infile}"
|
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
COMMENT "Generating version linker script"
|
|
)
|
|
target_link_options("${target}" PRIVATE "-Wl,--version-script,${outfile}")
|
|
endif()
|
|
endif()
|
|
endfunction()
|
|
|
|
|
|
# Get a set of Qt module related values based on the target name.
|
|
# When doing qt_internal_module_info(foo Core) this method will set
|
|
# the following variables in the caller's scope:
|
|
# * foo with the value "QtCore"
|
|
# * foo_versioned with the value "Qt6Core" (based on major Qt version)
|
|
# * foo_upper with the value "CORE"
|
|
# * foo_lower with the value "core"
|
|
# * foo_repo_include_dir with the module's include directory
|
|
# e.g for QtQuick it would be qtdeclarative_build_dir/include for a prefix build or
|
|
# qtbase_build_dir/include for a non-prefix build
|
|
# * foo_include_dir with the module's include directory
|
|
# e.g for QtQuick it would be qtdeclarative_build_dir/include/QtQuick for a prefix build or
|
|
# qtbase_build_dir/include/QtQuick for a non-prefix build
|
|
# * foo_define same as foo_uper but with - replaced as _
|
|
function(qt_internal_module_info result target)
|
|
set(module "Qt${target}")
|
|
set("${result}" "${module}" PARENT_SCOPE)
|
|
set("${result}_versioned" "Qt${PROJECT_VERSION_MAJOR}${target}" PARENT_SCOPE)
|
|
string(TOUPPER "${target}" upper)
|
|
string(TOLOWER "${target}" lower)# * foo_upper with the value "CORE"
|
|
string(REPLACE "-" "_" define "${upper}")
|
|
string(REPLACE "." "_" define "${define}")
|
|
set("${result}_upper" "${upper}" PARENT_SCOPE)
|
|
set("${result}_lower" "${lower}" PARENT_SCOPE)
|
|
set("${result}_repo_include_dir" "${QT_BUILD_DIR}/include" PARENT_SCOPE)
|
|
set("${result}_include_dir" "${QT_BUILD_DIR}/include/${module}" PARENT_SCOPE)
|
|
set("${result}_define" "${define}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
|
|
set(__default_private_args "SOURCES;LIBRARIES;INCLUDE_DIRECTORIES;DEFINES;DBUS_ADAPTOR_BASENAME;DBUS_ADAPTOR_FLAGS;DBUS_ADAPTOR_SOURCES;DBUS_INTERFACE_BASENAME;DBUS_INTERFACE_FLAGS;DBUS_INTERFACE_SOURCES;FEATURE_DEPENDENCIES;COMPILE_OPTIONS;LINK_OPTIONS;MOC_OPTIONS;DISABLE_AUTOGEN_TOOLS;ENABLE_AUTOGEN_TOOLS;PLUGIN_TYPES")
|
|
|
|
set(__default_public_args "PUBLIC_LIBRARIES;PUBLIC_INCLUDE_DIRECTORIES;PUBLIC_DEFINES;PUBLIC_COMPILE_OPTIONS;PUBLIC_LINK_OPTIONS")
|
|
|
|
|
|
option(QT_CMAKE_DEBUG_EXTEND_TARGET "Debug extend_target calls in Qt's build system" OFF)
|
|
|
|
# Initial autogen setup for a target to specify certain CMake properties which are common
|
|
# to all autogen tools. Also enable AUTOMOC by default.
|
|
function(qt_autogen_tools_initial_setup target)
|
|
set_property(TARGET "${target}" PROPERTY INTERFACE_QT_MAJOR_VERSION ${PROJECT_VERSION_MAJOR})
|
|
set_property(TARGET "${target}" APPEND PROPERTY COMPATIBLE_INTERFACE_STRING QT_MAJOR_VERSION)
|
|
|
|
set_directory_properties(PROPERTIES
|
|
QT_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}
|
|
QT_VERSION_MINOR ${PROJECT_VERSION_MINOR})
|
|
|
|
qt_enable_autogen_tool(${target} "moc" ON)
|
|
endfunction()
|
|
|
|
# Enables or disables an autogen tool like moc, uic or rcc on ${target}.
|
|
function(qt_enable_autogen_tool target tool enable)
|
|
string(TOUPPER "${tool}" captitalAutogenTool)
|
|
|
|
get_target_property(tool_enabled ${target} AUTO${captitalAutogenTool})
|
|
get_target_property(autogen_target_depends ${target} AUTOGEN_TARGET_DEPENDS)
|
|
|
|
if(NOT autogen_target_depends)
|
|
set(autogen_target_depends "")
|
|
endif()
|
|
set(tool_executable "$<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::${tool}>")
|
|
set(tool_target_name ${QT_CMAKE_EXPORT_NAMESPACE}::${tool})
|
|
|
|
if(enable)
|
|
list(APPEND autogen_target_depends ${tool_target_name})
|
|
else()
|
|
list(REMOVE_ITEM autogen_target_depends ${tool_target_name})
|
|
endif()
|
|
|
|
# f66c1db16c050c9d685a44a38ad7c5cf9f6fcc96 in qtbase introduced a new macro
|
|
# that the moc scanner has to look for. Inform the CMake moc scanner about it.
|
|
if(tool STREQUAL "moc" AND enable)
|
|
set_target_properties("${target}" PROPERTIES
|
|
AUTOMOC_MACRO_NAMES "Q_OBJECT;Q_GADGET;Q_NAMESPACE;Q_NAMESPACE_EXPORT")
|
|
endif()
|
|
|
|
set_target_properties("${target}"
|
|
PROPERTIES
|
|
AUTO${captitalAutogenTool} "${enable}"
|
|
AUTO${captitalAutogenTool}_EXECUTABLE "${tool_executable}"
|
|
AUTOGEN_TARGET_DEPENDS "${autogen_target_depends}"
|
|
)
|
|
endfunction()
|
|
|
|
# This function adds or removes additional AUTOGEN tools to a target: AUTOMOC/UIC/RCC
|
|
function(qt_autogen_tools target)
|
|
qt_parse_all_arguments(arg "qt_autogen_tools" "" "" "${__default_private_args}" ${ARGN})
|
|
|
|
if (arg_ENABLE_AUTOGEN_TOOLS)
|
|
foreach(tool ${arg_ENABLE_AUTOGEN_TOOLS})
|
|
qt_enable_autogen_tool(${target} ${tool} ON)
|
|
endforeach()
|
|
endif()
|
|
|
|
if (arg_DISABLE_AUTOGEN_TOOLS)
|
|
foreach(tool ${arg_DISABLE_AUTOGEN_TOOLS})
|
|
qt_enable_autogen_tool(${target} ${tool} OFF)
|
|
endforeach()
|
|
endif()
|
|
endfunction()
|
|
|
|
# This function stores the list of Qt modules a library depend on,
|
|
# along with their version info, for usage in ${target}Depends.cmake file
|
|
function(qt_register_target_dependencies target public_libs private_libs)
|
|
get_target_property(target_deps "${target}" _qt_target_deps)
|
|
if(NOT target_deps)
|
|
set(target_deps "")
|
|
endif()
|
|
|
|
foreach(lib IN LISTS public_libs private_libs)
|
|
if ("${lib}" MATCHES "^Qt::(.*)")
|
|
set(lib "${CMAKE_MATCH_1}")
|
|
if (lib STREQUAL Platform
|
|
OR lib STREQUAL GlobalConfig
|
|
OR lib STREQUAL GlobalConfigPrivate
|
|
OR lib STREQUAL PlatformModuleInternal
|
|
OR lib STREQUAL PlatformPluginInternal
|
|
OR lib STREQUAL PlatformToolInternal)
|
|
list(APPEND target_deps "Qt6\;${PROJECT_VERSION}")
|
|
elseif ("${lib}" MATCHES "(.*)Private")
|
|
list(APPEND target_deps "${INSTALL_CMAKE_NAMESPACE}${CMAKE_MATCH_1}\;${PROJECT_VERSION}")
|
|
else()
|
|
list(APPEND target_deps "${INSTALL_CMAKE_NAMESPACE}${lib}\;${PROJECT_VERSION}")
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
|
|
set_target_properties("${target}" PROPERTIES _qt_target_deps "${target_deps}")
|
|
endfunction()
|
|
|
|
# This function can be used to add sources/libraries/etc. to the specified CMake target
|
|
# if the provided CONDITION evaluates to true.
|
|
function(extend_target target)
|
|
# Don't try to extend_target when cross compiling an imported host target (like a tool).
|
|
qt_is_imported_target("${target}" is_imported)
|
|
if(is_imported)
|
|
return()
|
|
endif()
|
|
|
|
if (NOT TARGET "${target}")
|
|
message(FATAL_ERROR "Trying to extend non-existing target \"${target}\".")
|
|
endif()
|
|
qt_parse_all_arguments(arg "extend_target" "HEADER_MODULE" ""
|
|
"CONDITION;${__default_public_args};${__default_private_args};COMPILE_FLAGS" ${ARGN})
|
|
if ("x${arg_CONDITION}" STREQUAL x)
|
|
set(arg_CONDITION ON)
|
|
endif()
|
|
|
|
qt_evaluate_config_expression(result ${arg_CONDITION})
|
|
if (${result})
|
|
if(QT_CMAKE_DEBUG_EXTEND_TARGET)
|
|
message("extend_target(${target} CONDITION ${arg_CONDITION} ...): Evaluated")
|
|
endif()
|
|
set(dbus_sources "")
|
|
foreach(adaptor ${arg_DBUS_ADAPTOR_SOURCES})
|
|
qt_create_qdbusxml2cpp_command("${target}" "${adaptor}" ADAPTOR BASENAME "${arg_DBUS_ADAPTOR_BASENAME}" FLAGS "${arg_DBUS_ADAPTOR_FLAGS}")
|
|
list(APPEND dbus_sources "${sources}")
|
|
endforeach()
|
|
|
|
foreach(interface ${arg_DBUS_INTERFACE_SOURCES})
|
|
qt_create_qdbusxml2cpp_command("${target}" "${interface}" INTERFACE BASENAME "${arg_DBUS_INTERFACE_BASENAME}" FLAGS "${arg_DBUS_INTERFACE_FLAGS}")
|
|
list(APPEND dbus_sources "${sources}")
|
|
endforeach()
|
|
|
|
foreach(lib ${arg_PUBLIC_LIBRARIES} ${arg_LIBRARIES})
|
|
string(REGEX REPLACE "_nolink$" "" base_lib "${lib}")
|
|
if(NOT base_lib STREQUAL lib)
|
|
qt_create_nolink_target("${base_lib}" ${target})
|
|
endif()
|
|
endforeach()
|
|
|
|
# Find dependencies to internal libraries
|
|
get_target_property(target_deps "${target}" _qt_target_deps)
|
|
if(NOT target_deps)
|
|
set(target_deps "")
|
|
endif()
|
|
|
|
foreach(lib ${arg_LIBRARIES})
|
|
if (TARGET "${lib}")
|
|
get_target_property(_is_exported "${lib}" INTERFACE_QT_EXPORTED_LIBRARY)
|
|
if("${_is_exported}")
|
|
list(APPEND target_deps "${lib}\;${PROJECT_VERSION}")
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
# Set-up the target
|
|
target_sources("${target}" PRIVATE ${arg_SOURCES} ${dbus_sources})
|
|
if (arg_COMPILE_FLAGS)
|
|
set_source_files_properties(${arg_SOURCES} PROPERTIES COMPILE_FLAGS "${arg_COMPILE_FLAGS}")
|
|
endif()
|
|
|
|
set(public_visibility_option "PUBLIC")
|
|
set(private_visibility_option "PRIVATE")
|
|
if(arg_HEADER_MODULE)
|
|
set(public_visibility_option "INTERFACE")
|
|
set(private_visibility_option "INTERFACE")
|
|
endif()
|
|
target_include_directories("${target}"
|
|
${public_visibility_option} ${arg_PUBLIC_INCLUDE_DIRECTORIES}
|
|
${private_visibility_option} ${arg_INCLUDE_DIRECTORIES})
|
|
target_compile_definitions("${target}"
|
|
${public_visibility_option} ${arg_PUBLIC_DEFINES}
|
|
${private_visibility_option} ${arg_DEFINES})
|
|
target_link_libraries("${target}"
|
|
${public_visibility_option} ${arg_PUBLIC_LIBRARIES}
|
|
${private_visibility_option} ${arg_LIBRARIES})
|
|
target_compile_options("${target}"
|
|
${public_visibility_option} ${arg_PUBLIC_COMPILE_OPTIONS}
|
|
${private_visibility_option} ${arg_COMPILE_OPTIONS})
|
|
target_link_options("${target}"
|
|
${public_visibility_option} ${arg_PUBLIC_LINK_OPTIONS}
|
|
${private_visibility_option} ${arg_LINK_OPTIONS})
|
|
|
|
if(NOT arg_HEADER_MODULE)
|
|
set_target_properties("${target}" PROPERTIES
|
|
AUTOMOC_MOC_OPTIONS "${arg_MOC_OPTIONS}"
|
|
_qt_target_deps "${target_deps}"
|
|
)
|
|
endif()
|
|
|
|
# When computing the private library dependencies, we need to check not only the known
|
|
# modules added by this repo's qt_build_repo(), but also all module dependencies that
|
|
# were found via find_package().
|
|
qt_internal_get_qt_all_known_modules(known_modules)
|
|
|
|
# When a public module depends on a private module (Gui on CorePrivate)
|
|
# make its private module depend on the other private module (GuiPrivate will depend on
|
|
# CorePrivate).
|
|
set(qt_libs_private "")
|
|
foreach(it ${known_modules})
|
|
list(FIND arg_LIBRARIES "Qt::${it}Private" pos)
|
|
if(pos GREATER -1)
|
|
list(APPEND qt_libs_private "Qt::${it}Private")
|
|
endif()
|
|
endforeach()
|
|
|
|
set(target_private "${target}Private")
|
|
if(TARGET "${target_private}")
|
|
target_link_libraries("${target_private}" INTERFACE "${target}" "${qt_libs_private}")
|
|
endif()
|
|
qt_register_target_dependencies("${target}"
|
|
"${arg_PUBLIC_LIBRARIES}"
|
|
"${qt_libs_private};${arg_LIBRARIES}")
|
|
|
|
|
|
qt_autogen_tools(${target}
|
|
ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
|
|
DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS})
|
|
|
|
else()
|
|
if(QT_CMAKE_DEBUG_EXTEND_TARGET)
|
|
message("extend_target(${target} CONDITION ${arg_CONDITION} ...): Skipped")
|
|
endif()
|
|
endif()
|
|
endfunction()
|
|
|
|
|
|
function(qt_internal_library_deprecation_level result)
|
|
if(WIN32)
|
|
# On Windows, due to the way DLLs work, we need to export all functions,
|
|
# including the inlines
|
|
set("${result}" "QT_DISABLE_DEPRECATED_BEFORE=0x040800" PARENT_SCOPE)
|
|
else()
|
|
# On other platforms, Qt's own compilation goes needs to compile the Qt 5.0 API
|
|
set("${result}" "QT_DISABLE_DEPRECATED_BEFORE=0x050000" PARENT_SCOPE)
|
|
endif()
|
|
set("${result}" "QT_DEPRECATED_WARNINGS_SINCE=0x060000" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
|
|
function(qt_install_injections module build_dir install_dir)
|
|
set(injections ${ARGN})
|
|
# examples:
|
|
# SYNCQT.INJECTIONS = src/corelib/global/qconfig.h:qconfig.h:QtConfig src/corelib/global/qconfig_p.h:5.12.0/QtCore/private/qconfig_p.h
|
|
# SYNCQT.INJECTIONS = src/gui/vulkan/qvulkanfunctions.h:^qvulkanfunctions.h:QVulkanFunctions:QVulkanDeviceFunctions src/gui/vulkan/qvulkanfunctions_p.h:^5.12.0/QtGui/private/qvulkanfunctions_p.h
|
|
# The are 3 parts to the assignment, divded by colons ':'.
|
|
# The first part contains a path to a generated file in a build folder.
|
|
# The second part contains the file name that the forwarding header should have, which points
|
|
# to the file in the first part.
|
|
# The third part contains multiple UpperCaseFileNames that should be forwarding headers to the
|
|
# header specified in the second part.
|
|
separate_arguments(injections UNIX_COMMAND "${injections}")
|
|
foreach(injection ${injections})
|
|
string(REPLACE ":" ";" injection ${injection})
|
|
# Part 1.
|
|
list(GET injection 0 file)
|
|
# Part 2.
|
|
list(GET injection 1 destination)
|
|
string(REGEX REPLACE "^\\^" "" destination "${destination}")
|
|
list(REMOVE_AT injection 0 1)
|
|
# Part 3.
|
|
set(fwd_hdrs ${injection})
|
|
get_filename_component(destinationdir ${destination} DIRECTORY)
|
|
get_filename_component(destinationname ${destination} NAME)
|
|
get_filename_component(original_file_name ${file} NAME)
|
|
|
|
# This describes a concrete example for easier comprehension:
|
|
# A file 'qtqml-config.h' is generated by qt_internal_feature_write_file into
|
|
# ${qtdeclarative_build_dir}/src/{module}/qtqml-config.h (part 1).
|
|
#
|
|
# Generate a lower case forwarding header (part 2) 'qtqml-config.h' at the following
|
|
# location:
|
|
# ${some_prefix}/include/${module}/qtqml-config.h.
|
|
#
|
|
# Inside this file, we #include the originally generated file,
|
|
# ${qtdeclarative_build_dir}/src/{module}/qtqml-config.h.
|
|
#
|
|
# ${some_prefix}'s value depends on the build type.
|
|
# If doing a prefix build, it should point to
|
|
# ${current_repo_build_dir} which is ${qtdeclarative_build_dir}.
|
|
# If doing a non-prefix build, it should point to
|
|
# ${qtbase_build_dir}.
|
|
#
|
|
# In the code below, ${some_prefix} == ${build_dir}.
|
|
set(lower_case_forwarding_header_path "${build_dir}/${INSTALL_INCLUDEDIR}/${module}")
|
|
if(destinationdir)
|
|
string(APPEND lower_case_forwarding_header_path "/${destinationdir}")
|
|
endif()
|
|
set(current_repo_build_dir "${PROJECT_BINARY_DIR}")
|
|
|
|
file(RELATIVE_PATH relpath
|
|
"${lower_case_forwarding_header_path}"
|
|
"${current_repo_build_dir}/${file}")
|
|
set(main_contents "#include \"${relpath}\"")
|
|
file(GENERATE OUTPUT "${lower_case_forwarding_header_path}/${original_file_name}"
|
|
CONTENT "${main_contents}")
|
|
|
|
# Copy the actual injected (generated) header file (not the just created forwarding one)
|
|
# to its install location when doing a prefix build. In an non-prefix build, the qt_install
|
|
# will be a no-op.
|
|
qt_path_join(install_destination
|
|
${install_dir} ${INSTALL_INCLUDEDIR} ${module} ${destinationdir})
|
|
qt_install(FILES ${current_repo_build_dir}/${file}
|
|
DESTINATION ${install_destination}
|
|
RENAME ${destinationname} OPTIONAL)
|
|
|
|
# Generate UpperCaseNamed forwarding headers (part 3).
|
|
foreach(fwd_hdr ${fwd_hdrs})
|
|
set(upper_case_forwarding_header_path "${INSTALL_INCLUDEDIR}/${module}")
|
|
if(destinationdir)
|
|
string(APPEND upper_case_forwarding_header_path "/${destinationdir}")
|
|
endif()
|
|
|
|
# Generate upper case forwarding header like QVulkanFunctions or QtConfig.
|
|
file(GENERATE OUTPUT "${build_dir}/${upper_case_forwarding_header_path}/${fwd_hdr}"
|
|
CONTENT "#include \"${destinationname}\"\n")
|
|
|
|
# Install the forwarding header.
|
|
qt_path_join(install_destination
|
|
${install_dir} ${upper_case_forwarding_header_path})
|
|
qt_install(FILES "${build_dir}/${upper_case_forwarding_header_path}/${fwd_hdr}"
|
|
DESTINATION ${install_destination} OPTIONAL)
|
|
endforeach()
|
|
endforeach()
|
|
endfunction()
|
|
|
|
|
|
function(qt_read_headers_pri target resultVarPrefix)
|
|
qt_internal_module_info(module "${target}")
|
|
file(STRINGS "${module_include_dir}/headers.pri" headers_pri_contents)
|
|
foreach(line ${headers_pri_contents})
|
|
if("${line}" MATCHES "SYNCQT.HEADER_FILES = (.*)")
|
|
set(public_module_headers "${CMAKE_MATCH_1}")
|
|
separate_arguments(public_module_headers UNIX_COMMAND "${public_module_headers}")
|
|
elseif("${line}" MATCHES "SYNCQT.PRIVATE_HEADER_FILES = (.*)")
|
|
set(private_module_headers "${CMAKE_MATCH_1}")
|
|
separate_arguments(private_module_headers UNIX_COMMAND "${private_module_headers}")
|
|
elseif("${line}" MATCHES "SYNCQT.GENERATED_HEADER_FILES = (.*)")
|
|
set(generated_module_headers "${CMAKE_MATCH_1}")
|
|
separate_arguments(generated_module_headers UNIX_COMMAND "${generated_module_headers}")
|
|
foreach(generated_header ${generated_module_headers})
|
|
list(APPEND public_module_headers "${module_include_dir}/${generated_header}")
|
|
endforeach()
|
|
elseif("${line}" MATCHES "SYNCQT.INJECTIONS = (.*)")
|
|
set(injections "${CMAKE_MATCH_1}")
|
|
elseif("${line}" MATCHES "SYNCQT.([A-Z_]+)_HEADER_FILES = (.+)")
|
|
set(prefix "${CMAKE_MATCH_1}")
|
|
string(TOLOWER "${prefix}" prefix)
|
|
set(entries "${CMAKE_MATCH_2}")
|
|
separate_arguments(entries UNIX_COMMAND "${entries}")
|
|
set("${resultVarPrefix}_${prefix}" "${entries}" PARENT_SCOPE)
|
|
endif()
|
|
endforeach()
|
|
set(${resultVarPrefix}_public "${public_module_headers}" PARENT_SCOPE)
|
|
set(${resultVarPrefix}_private "${private_module_headers}" PARENT_SCOPE)
|
|
set(${resultVarPrefix}_injections "${injections}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
|
|
# Add Qt::target and Qt6::target as aliases for the target
|
|
function(qt_internal_add_target_aliases target)
|
|
get_target_property(type "${target}" TYPE)
|
|
if (type STREQUAL EXECUTABLE)
|
|
add_executable("Qt::${target}" ALIAS "${target}")
|
|
add_executable("Qt${PROJECT_VERSION_MAJOR}::${target}" ALIAS "${target}")
|
|
else()
|
|
add_library("Qt::${target}" ALIAS "${target}")
|
|
add_library("Qt${PROJECT_VERSION_MAJOR}::${target}" ALIAS "${target}")
|
|
endif()
|
|
endfunction()
|
|
|
|
# Sets the exceptions flags for the given target
|
|
function(qt_internal_set_no_exceptions_flags target)
|
|
target_compile_definitions("${target}" PRIVATE "QT_NO_EXCEPTIONS")
|
|
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
|
target_compile_options("${target}" PRIVATE "/wd4530" "/wd4577")
|
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
|
target_compile_options("${target}" PRIVATE "-fno-exceptions")
|
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
|
|
target_compile_options("${target}" PRIVATE "-fno-exceptions")
|
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
|
target_compile_options("${target}" PRIVATE "-fno-exceptions")
|
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
|
|
target_compile_options("${target}" PRIVATE "-fno-exceptions")
|
|
endif()
|
|
endfunction()
|
|
|
|
# This is the main entry function for creating a Qt module, that typically
|
|
# consists of a library, public header files, private header files and configurable
|
|
# features.
|
|
#
|
|
# A CMake target with the specified target parameter is created. If the current source
|
|
# directory has a configure.cmake file, then that is also processed for feature definition
|
|
# and testing. Any features defined as well as any features coming from dependencies to
|
|
# this module are imported into the scope of the calling feature.
|
|
#
|
|
# Target is without leading "Qt". So e.g. the "QtCore" module has the target "Core".
|
|
function(add_qt_module target)
|
|
qt_internal_module_info(module "${target}")
|
|
|
|
# Process arguments:
|
|
qt_parse_all_arguments(arg "add_qt_module"
|
|
"NO_MODULE_HEADERS;STATIC;DISABLE_TOOLS_EXPORT;EXCEPTIONS;INTERNAL_MODULE;NO_SYNC_QT;NO_PRIVATE_MODULE;HEADER_MODULE"
|
|
"CONFIG_MODULE_NAME"
|
|
"${__default_private_args};${__default_public_args};QMAKE_MODULE_CONFIG;EXTRA_CMAKE_FILES;EXTRA_CMAKE_INCLUDES" ${ARGN})
|
|
|
|
if(NOT DEFINED arg_CONFIG_MODULE_NAME)
|
|
set(arg_CONFIG_MODULE_NAME "${module_lower}")
|
|
endif()
|
|
|
|
qt_internal_add_qt_repo_known_module("${target}")
|
|
|
|
### Define Targets:
|
|
if(${arg_HEADER_MODULE})
|
|
add_library("${target}" INTERFACE)
|
|
elseif(${arg_STATIC})
|
|
add_library("${target}" STATIC)
|
|
elseif(${QT_BUILD_SHARED_LIBS})
|
|
add_library("${target}" SHARED)
|
|
else()
|
|
add_library("${target}" STATIC)
|
|
endif()
|
|
qt_internal_add_target_aliases("${target}")
|
|
|
|
# Add _private target to link against the private headers:
|
|
if(NOT ${arg_NO_PRIVATE_MODULE})
|
|
set(target_private "${target}Private")
|
|
add_library("${target_private}" INTERFACE)
|
|
qt_internal_add_target_aliases("${target_private}")
|
|
endif()
|
|
|
|
# Module headers:
|
|
if(${arg_NO_MODULE_HEADERS} OR ${arg_NO_SYNC_QT})
|
|
set_target_properties("${target}" PROPERTIES INTERFACE_MODULE_HAS_HEADERS OFF)
|
|
else()
|
|
# Use QT_BUILD_DIR for the syncqt call.
|
|
# So we either write the generated files into the qtbase non-prefix build root, or the
|
|
# module specific build root.
|
|
qt_ensure_sync_qt()
|
|
set(syncqt_full_command "${HOST_PERL}" -w "${QT_SYNCQT}"
|
|
-quiet
|
|
-check-includes
|
|
-module "${module}"
|
|
-version "${PROJECT_VERSION}"
|
|
-outdir "${QT_BUILD_DIR}"
|
|
-builddir "${PROJECT_BINARY_DIR}"
|
|
"${PROJECT_SOURCE_DIR}")
|
|
execute_process(COMMAND ${syncqt_full_command})
|
|
|
|
set_target_properties("${target}" PROPERTIES INTERFACE_MODULE_HAS_HEADERS ON)
|
|
|
|
### FIXME: Can we replace headers.pri?
|
|
qt_read_headers_pri("${target}" "module_headers")
|
|
set_property(TARGET "${target}" APPEND PROPERTY PUBLIC_HEADER "${module_headers_public}")
|
|
set_property(TARGET "${target}" APPEND PROPERTY PUBLIC_HEADER "${module_include_dir}/${module}Depends")
|
|
set_property(TARGET "${target}" APPEND PROPERTY PRIVATE_HEADER "${module_headers_private}")
|
|
if(module_headers_qpa)
|
|
qt_install(FILES ${module_headers_qpa} DESTINATION ${INSTALL_INCLUDEDIR}/${module}/${PROJECT_VERSION}/${module}/qpa)
|
|
endif()
|
|
endif()
|
|
|
|
if(NOT arg_HEADER_MODULE)
|
|
# Plugin types associated to a module
|
|
if(NOT "x${arg_PLUGIN_TYPES}" STREQUAL "x")
|
|
set_target_properties("${target}" PROPERTIES MODULE_PLUGIN_TYPES "${arg_PLUGIN_TYPES}")
|
|
endif()
|
|
|
|
set_target_properties("${target}" PROPERTIES
|
|
LIBRARY_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}"
|
|
RUNTIME_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}"
|
|
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${QT_BUILD_DIR}/${INSTALL_BINDIR}"
|
|
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${QT_BUILD_DIR}/${INSTALL_BINDIR}"
|
|
ARCHIVE_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}"
|
|
VERSION ${PROJECT_VERSION}
|
|
SOVERSION ${PROJECT_VERSION_MAJOR}
|
|
OUTPUT_NAME "${INSTALL_CMAKE_NAMESPACE}${target}"
|
|
)
|
|
endif()
|
|
|
|
qt_internal_library_deprecation_level(deprecation_define)
|
|
|
|
if(NOT arg_HEADER_MODULE)
|
|
qt_autogen_tools_initial_setup(${target})
|
|
endif()
|
|
|
|
set(private_includes
|
|
"${CMAKE_CURRENT_SOURCE_DIR}"
|
|
"${CMAKE_CURRENT_BINARY_DIR}"
|
|
"${module_include_dir}/${PROJECT_VERSION}"
|
|
"${module_include_dir}/${PROJECT_VERSION}/${module}"
|
|
${arg_INCLUDE_DIRECTORIES}
|
|
)
|
|
|
|
set(public_includes
|
|
# For the syncqt headers
|
|
"$<BUILD_INTERFACE:${module_repo_include_dir}>"
|
|
"$<BUILD_INTERFACE:${module_include_dir}>"
|
|
)
|
|
|
|
if(NOT arg_NO_MODULE_HEADERS)
|
|
# For the syncqt headers
|
|
list(APPEND public_includes "$<INSTALL_INTERFACE:include/${module}>")
|
|
endif()
|
|
list(APPEND public_includes ${arg_PUBLIC_INCLUDE_DIRECTORIES})
|
|
|
|
set(header_module)
|
|
if(arg_HEADER_MODULE)
|
|
set(header_module "HEADER_MODULE")
|
|
endif()
|
|
|
|
extend_target("${target}"
|
|
${header_module}
|
|
SOURCES ${arg_SOURCES}
|
|
INCLUDE_DIRECTORIES
|
|
${private_includes}
|
|
PUBLIC_INCLUDE_DIRECTORIES
|
|
${public_includes}
|
|
PUBLIC_DEFINES
|
|
${arg_PUBLIC_DEFINES}
|
|
QT_${module_define}_LIB
|
|
DEFINES
|
|
${arg_DEFINES}
|
|
QT_NO_CAST_TO_ASCII QT_ASCII_CAST_WARNINGS
|
|
QT_MOC_COMPAT #we don't need warnings from calling moc code in our generated code
|
|
QT_USE_QSTRINGBUILDER
|
|
QT_DEPRECATED_WARNINGS
|
|
QT_BUILDING_QT
|
|
QT_BUILD_${module_define}_LIB ### FIXME: use QT_BUILD_ADDON for Add-ons or remove if we don't have add-ons anymore
|
|
"${deprecation_define}"
|
|
PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES}
|
|
LIBRARIES ${arg_LIBRARIES} Qt::PlatformModuleInternal
|
|
FEATURE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES}
|
|
DBUS_ADAPTOR_SOURCES ${arg_DBUS_ADAPTOR_SOURCES}
|
|
DBUS_ADAPTOR_FLAGS ${arg_DBUS_ADAPTOR_FLAGS}
|
|
DBUS_INTERFACE_SOURCES ${arg_DBUS_INTERFACE_SOURCES}
|
|
DBUS_INTERFACE_FLAGS ${arg_DBUS_INTERFACE_FLAGS}
|
|
COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
|
|
PUBLIC_COMPILE_OPTIONS ${arg_PUBLIC_COMPILE_OPTIONS}
|
|
LINK_OPTIONS ${arg_LINK_OPTIONS}
|
|
PUBLIC_LINK_OPTIONS ${arg_PUBLIC_LINK_OPTIONS}
|
|
MOC_OPTIONS ${arg_MOC_OPTIONS}
|
|
ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
|
|
DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
|
|
)
|
|
|
|
if(NOT ${arg_EXCEPTIONS} AND NOT ${arg_HEADER_MODULE})
|
|
qt_internal_set_no_exceptions_flags("${target}")
|
|
endif()
|
|
|
|
set(configureFile "${CMAKE_CURRENT_SOURCE_DIR}/configure.cmake")
|
|
if(EXISTS "${configureFile}")
|
|
qt_feature_module_begin(
|
|
LIBRARY "${target}"
|
|
PUBLIC_FILE "qt${arg_CONFIG_MODULE_NAME}-config.h"
|
|
PRIVATE_FILE "qt${arg_CONFIG_MODULE_NAME}-config_p.h"
|
|
PUBLIC_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES}
|
|
PRIVATE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES}
|
|
)
|
|
include(${configureFile})
|
|
qt_feature_module_end("${target}")
|
|
|
|
set_property(TARGET "${target}" APPEND PROPERTY PUBLIC_HEADER "${CMAKE_CURRENT_BINARY_DIR}/qt${arg_CONFIG_MODULE_NAME}-config.h")
|
|
set_property(TARGET "${target}" APPEND PROPERTY PRIVATE_HEADER "${CMAKE_CURRENT_BINARY_DIR}/qt${arg_CONFIG_MODULE_NAME}-config_p.h")
|
|
endif()
|
|
|
|
if(DEFINED module_headers_private)
|
|
qt_internal_add_linker_version_script("${target}" PRIVATE_HEADERS ${module_headers_private})
|
|
else()
|
|
qt_internal_add_linker_version_script("${target}")
|
|
endif()
|
|
|
|
# Handle injections. Aka create forwarding headers for certain headers that have been
|
|
# automatically generated in the build dir (for example qconfig.h, qtcore-config.h,
|
|
# qvulkanfunctions.h, etc)
|
|
# module_headers_injections come from the qt_read_headers_pri() call.
|
|
# extra_library_injections come from the qt_feature_module_end() call.
|
|
set(final_injections "")
|
|
if(module_headers_injections)
|
|
string(APPEND final_injections "${module_headers_injections} ")
|
|
endif()
|
|
if(extra_library_injections)
|
|
string(APPEND final_injections "${extra_library_injections} ")
|
|
endif()
|
|
|
|
if(final_injections)
|
|
qt_install_injections("${module}" "${QT_BUILD_DIR}" "${QT_INSTALL_DIR}" ${final_injections})
|
|
endif()
|
|
|
|
# Handle creation of cmake files for consumers of find_package().
|
|
set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}")
|
|
qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix})
|
|
qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix})
|
|
|
|
set(extra_cmake_files)
|
|
set(extra_cmake_includes)
|
|
if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}Macros.cmake")
|
|
list(APPEND extra_cmake_files "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}Macros.cmake")
|
|
list(APPEND extra_cmake_includes "${INSTALL_CMAKE_NAMESPACE}${target}Macros.cmake")
|
|
endif()
|
|
if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake.in")
|
|
configure_file("${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake.in"
|
|
"${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake"
|
|
@ONLY)
|
|
list(APPEND extra_cmake_files "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake")
|
|
list(APPEND extra_cmake_includes "${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake")
|
|
endif()
|
|
|
|
foreach(cmake_file IN LISTS arg_EXTRA_CMAKE_FILES)
|
|
get_filename_component(basename ${cmake_file} NAME)
|
|
file(COPY ${cmake_file} DESTINATION ${config_build_dir})
|
|
list(APPEND extra_cmake_files "${config_build_dir}/${basename}")
|
|
endforeach()
|
|
list(APPEND extra_cmake_includes ${arg_EXTRA_CMAKE_INCLUDES})
|
|
|
|
set(extra_cmake_code "")
|
|
|
|
if(target STREQUAL Core)
|
|
# Propagate non-build related variables that are needed for consuming Qt packages.
|
|
# Do this in CoreConfig instead of Qt6Config, so that consumers can also use
|
|
# find_package(Qt6Core) instead of find_package(Qt6 COMPONENTS Core)
|
|
string(APPEND extra_cmake_code "
|
|
set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})")
|
|
endif()
|
|
|
|
configure_package_config_file(
|
|
"${QT_CMAKE_DIR}/QtModuleConfig.cmake.in"
|
|
"${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
|
|
INSTALL_DESTINATION "${config_install_dir}"
|
|
)
|
|
write_basic_package_version_file(
|
|
"${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
|
|
VERSION ${PROJECT_VERSION}
|
|
COMPATIBILITY AnyNewerVersion
|
|
)
|
|
qt_install(FILES
|
|
"${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
|
|
"${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
|
|
${extra_cmake_files}
|
|
DESTINATION "${config_install_dir}"
|
|
COMPONENT Devel
|
|
)
|
|
|
|
file(COPY ${extra_cmake_files} DESTINATION "${config_build_dir}")
|
|
set(exported_targets ${target})
|
|
if(NOT ${arg_NO_PRIVATE_MODULE})
|
|
list(APPEND exported_targets ${target_private})
|
|
endif()
|
|
set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets")
|
|
qt_install(TARGETS ${exported_targets}
|
|
EXPORT ${export_name}
|
|
RUNTIME DESTINATION ${INSTALL_BINDIR}
|
|
LIBRARY DESTINATION ${INSTALL_LIBDIR}
|
|
ARCHIVE DESTINATION ${INSTALL_LIBDIR}
|
|
PUBLIC_HEADER DESTINATION ${INSTALL_INCLUDEDIR}/${module}
|
|
PRIVATE_HEADER DESTINATION ${INSTALL_INCLUDEDIR}/${module}/${PROJECT_VERSION}/${module}/private
|
|
)
|
|
|
|
if (ANDROID)
|
|
# Record install library location so it can be accessed by
|
|
# qt_android_dependencies without having to specify it again.
|
|
set_target_properties(${target} PROPERTIES
|
|
QT_ANDROID_MODULE_INSTALL_DIR ${INSTALL_LIBDIR})
|
|
endif()
|
|
|
|
qt_install(EXPORT ${export_name}
|
|
NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}::
|
|
DESTINATION ${config_install_dir})
|
|
|
|
qt_internal_export_modern_cmake_config_targets_file(
|
|
TARGETS ${exported_targets}
|
|
EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target}
|
|
CONFIG_INSTALL_DIR "${config_install_dir}")
|
|
|
|
if (${arg_INTERNAL_MODULE})
|
|
set(arg_INTERNAL_MODULE "INTERNAL_MODULE")
|
|
else()
|
|
unset(arg_INTERNAL_MODULE)
|
|
endif()
|
|
|
|
qt_path_join(pri_target_path ${PROJECT_BINARY_DIR} mkspecs/modules)
|
|
qt_generate_module_pri_file("${target}" "${pri_target_path}" module_pri_files
|
|
${arg_INTERNAL_MODULE}
|
|
${header_module}
|
|
QMAKE_MODULE_CONFIG
|
|
${arg_QMAKE_MODULE_CONFIG}
|
|
)
|
|
qt_install(FILES "${module_pri_files}" DESTINATION mkspecs/modules)
|
|
|
|
### fixme: cmake is missing a built-in variable for this. We want to apply it only to modules and plugins
|
|
# that belong to Qt.
|
|
if(NOT arg_HEADER_MODULE)
|
|
qt_internal_add_link_flags_no_undefined("${target}")
|
|
endif()
|
|
|
|
set(interface_includes
|
|
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>"
|
|
"$<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}>"
|
|
"$<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}/${module}>"
|
|
)
|
|
|
|
if(NOT arg_NO_MODULE_HEADERS)
|
|
list(APPEND interface_includes
|
|
"$<INSTALL_INTERFACE:include/${module}/${PROJECT_VERSION}>"
|
|
"$<INSTALL_INTERFACE:include/${module}/${PROJECT_VERSION}/${module}>"
|
|
)
|
|
endif()
|
|
|
|
|
|
if(NOT ${arg_NO_PRIVATE_MODULE})
|
|
target_include_directories("${target_private}" INTERFACE ${interface_includes})
|
|
endif()
|
|
|
|
if(NOT ${arg_DISABLE_TOOLS_EXPORT})
|
|
qt_export_tools(${target})
|
|
endif()
|
|
endfunction()
|
|
|
|
function(qt_export_tools module_name)
|
|
# If no tools were defined belonging to this module, don't create a config and targets file.
|
|
# Guards against the case when doing a cross-build and the function is called manually and not
|
|
# by add_qt_module.
|
|
|
|
if(NOT "${module_name}" IN_LIST QT_KNOWN_MODULES_WITH_TOOLS OR CMAKE_CROSSCOMPILING)
|
|
return()
|
|
endif()
|
|
|
|
# The tools target name. For example: CoreTools
|
|
set(target "${module_name}Tools")
|
|
|
|
set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}")
|
|
qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix})
|
|
qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix})
|
|
|
|
# Add the extra cmake statements to make the tool targets global, so it doesn't matter where
|
|
# find_package is called.
|
|
# Also assemble a list of tool targets to expose in the config file for informational purposes.
|
|
set(extra_cmake_statements "")
|
|
set(tool_targets "")
|
|
foreach(tool_name ${QT_KNOWN_MODULE_${module_name}_TOOLS})
|
|
set(extra_cmake_statements "${extra_cmake_statements}
|
|
if (NOT QT_NO_CREATE_TARGETS)
|
|
get_property(is_global TARGET ${INSTALL_CMAKE_NAMESPACE}::${tool_name} PROPERTY IMPORTED_GLOBAL)
|
|
if(NOT is_global)
|
|
set_property(TARGET ${INSTALL_CMAKE_NAMESPACE}::${tool_name} PROPERTY IMPORTED_GLOBAL TRUE)
|
|
endif()
|
|
endif()
|
|
")
|
|
list(APPEND tool_targets "${QT_CMAKE_EXPORT_NAMESPACE}::${tool_name}")
|
|
endforeach()
|
|
|
|
string(APPEND extra_cmake_statements
|
|
"set(${QT_CMAKE_EXPORT_NAMESPACE}${module_name}Tools_TARGETS \"${tool_targets}\")")
|
|
|
|
configure_package_config_file(
|
|
"${QT_CMAKE_DIR}/QtModuleToolsConfig.cmake.in"
|
|
"${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
|
|
INSTALL_DESTINATION "${config_install_dir}"
|
|
)
|
|
write_basic_package_version_file(
|
|
"${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
|
|
VERSION ${PROJECT_VERSION}
|
|
COMPATIBILITY AnyNewerVersion
|
|
)
|
|
|
|
qt_install(FILES
|
|
"${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
|
|
"${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
|
|
DESTINATION "${config_install_dir}"
|
|
COMPONENT Devel
|
|
)
|
|
|
|
set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets")
|
|
qt_install(EXPORT "${export_name}"
|
|
NAMESPACE "${QT_CMAKE_EXPORT_NAMESPACE}::"
|
|
DESTINATION "${config_install_dir}")
|
|
|
|
|
|
qt_internal_export_modern_cmake_config_targets_file(TARGETS ${QT_KNOWN_MODULE_${module_name}_TOOLS}
|
|
EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target}
|
|
CONFIG_INSTALL_DIR ${config_install_dir})
|
|
endfunction()
|
|
|
|
function(qt_internal_check_directory_or_type name dir type default result_var)
|
|
if ("x${dir}" STREQUAL x)
|
|
if("x${type}" STREQUAL x)
|
|
message(FATAL_ERROR "add_qt_plugin called without setting either TYPE or ${name}.")
|
|
endif()
|
|
set(${result_var} "${default}" PARENT_SCOPE)
|
|
else()
|
|
set(${result_var} "${dir}" PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
# Utility function to find the module to which a plug-in belongs.
|
|
# This will set the QT_MODULE target property on the plug-in - e.g. "Gui", "Sql"...
|
|
function(qt_get_module_for_plugin target target_type)
|
|
qt_internal_get_qt_all_known_modules(known_modules)
|
|
foreach(qt_module ${known_modules})
|
|
get_target_property(module_type "${QT_CMAKE_EXPORT_NAMESPACE}::${qt_module}" TYPE)
|
|
# Assuming interface libraries can't have plugins. Otherwise we'll need to fix the property
|
|
# name, because the current one would be invalid for interface libraries.
|
|
if(module_type STREQUAL "INTERFACE_LIBRARY")
|
|
continue()
|
|
endif()
|
|
|
|
get_target_property(plugin_types
|
|
"${QT_CMAKE_EXPORT_NAMESPACE}::${qt_module}"
|
|
MODULE_PLUGIN_TYPES)
|
|
if(plugin_types)
|
|
foreach(plugin_type ${plugin_types})
|
|
if("${target_type}" STREQUAL "${plugin_type}")
|
|
set_target_properties("${target}" PROPERTIES QT_MODULE "${qt_module}")
|
|
return()
|
|
endif()
|
|
endforeach()
|
|
endif()
|
|
endforeach()
|
|
message(AUTHOR_WARNING "The plug-in '${target}' does not belong to any Qt module.")
|
|
endfunction()
|
|
|
|
|
|
# Collection of add_qt_plugin arguments so they can be shared across different
|
|
# plugin type wrappers
|
|
set(__add_qt_plugin_optional_args
|
|
"STATIC;EXCEPTIONS"
|
|
)
|
|
set(__add_qt_plugin_single_args
|
|
"TYPE;CLASS_NAME;OUTPUT_DIRECTORY;INSTALL_DIRECTORY;ARCHIVE_INSTALL_DIRECTORY;QML_TARGET_PATH"
|
|
)
|
|
set(__add_qt_plugin_multi_args
|
|
"${__default_private_args};${__default_public_args};DEFAULT_IF"
|
|
)
|
|
# This is the main entry point for defining Qt plugins.
|
|
# A CMake target is created with the given target. The TYPE parameter is needed to place the
|
|
# plugin into the correct plugins/ sub-directory.
|
|
function(add_qt_plugin target)
|
|
qt_internal_module_info(module "${target}")
|
|
|
|
qt_internal_set_qt_known_plugins("${QT_KNOWN_PLUGINS}" "${target}")
|
|
|
|
qt_parse_all_arguments(arg "add_qt_plugin"
|
|
"${__add_qt_plugin_optional_args}"
|
|
"${__add_qt_plugin_single_args}"
|
|
"${__add_qt_plugin_multi_args}"
|
|
"${ARGN}"
|
|
)
|
|
|
|
set(output_directory_default "${QT_BUILD_DIR}/${INSTALL_PLUGINSDIR}/${arg_TYPE}")
|
|
set(install_directory_default "${INSTALL_PLUGINSDIR}/${arg_TYPE}")
|
|
set(archive_install_directory_default "${INSTALL_LIBDIR}/${arg_TYPE}")
|
|
|
|
if (arg_QML_TARGET_PATH)
|
|
set(target_path "${arg_QML_TARGET_PATH}")
|
|
set(output_directory_default "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/${target_path}")
|
|
set(install_directory_default "${INSTALL_QMLDIR}/${target_path}")
|
|
set(archive_install_directory_default "${INSTALL_QMLDIR}/${target_path}")
|
|
endif()
|
|
|
|
if ("x${arg_CLASS_NAME}" STREQUAL "x" AND NOT "${arg_TYPE}" STREQUAL "qml_plugin")
|
|
message(AUTHOR_WARNING "add_qt_plugin called without setting CLASS_NAME.")
|
|
endif()
|
|
|
|
qt_internal_check_directory_or_type(OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" "${arg_TYPE}"
|
|
"${output_directory_default}" output_directory)
|
|
qt_internal_check_directory_or_type(INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}" "${arg_TYPE}"
|
|
"${install_directory_default}" install_directory)
|
|
qt_internal_check_directory_or_type(ARCHIVE_INSTALL_DIRECTORY
|
|
"${arg_ARCHIVE_INSTALL_DIRECTORY}" "${arg_TYPE}"
|
|
"${archive_install_directory_default}" archive_install_directory)
|
|
|
|
if(arg_STATIC OR NOT BUILD_SHARED_LIBS)
|
|
add_library("${target}" STATIC)
|
|
else()
|
|
add_library("${target}" MODULE)
|
|
if(APPLE)
|
|
# CMake defaults to using .so extensions for loadable modules, aka plugins,
|
|
# but Qt plugins are actually suffixed with .dylib.
|
|
set_property(TARGET "${target}" PROPERTY SUFFIX ".dylib")
|
|
endif()
|
|
endif()
|
|
qt_internal_add_target_aliases("${target}")
|
|
|
|
set_target_properties("${target}" PROPERTIES
|
|
LIBRARY_OUTPUT_DIRECTORY "${output_directory}"
|
|
RUNTIME_OUTPUT_DIRECTORY "${output_directory}"
|
|
ARCHIVE_OUTPUT_DIRECTORY "${output_directory}"
|
|
QT_PLUGIN_CLASS_NAME "${arg_CLASS_NAME}")
|
|
|
|
qt_internal_library_deprecation_level(deprecation_define)
|
|
|
|
qt_autogen_tools_initial_setup(${target})
|
|
|
|
set(static_plugin_define "")
|
|
if (arg_STATIC OR NOT QT_BUILD_SHARED_LIBS)
|
|
set(static_plugin_define "QT_STATICPLUGIN")
|
|
endif()
|
|
|
|
# Save the Qt module in the plug-in's properties
|
|
if(NOT arg_TYPE STREQUAL "qml_plugin")
|
|
qt_get_module_for_plugin("${target}" "${arg_TYPE}")
|
|
get_target_property(qt_module "${target}" QT_MODULE)
|
|
endif()
|
|
|
|
# Add the plug-in to the list of plug-ins of this module
|
|
if(TARGET "${qt_module}")
|
|
set_property(TARGET "${qt_module}" APPEND PROPERTY QT_PLUGINS "${target}")
|
|
endif()
|
|
|
|
set(_default_plugin 1)
|
|
if (DEFINED arg_DEFAULT_IF)
|
|
if (NOT ${arg_DEFAULT_IF})
|
|
set(_default_plugin 0)
|
|
endif()
|
|
endif()
|
|
|
|
set_property(TARGET "${target}" PROPERTY QT_DEFAULT_PLUGIN "${_default_plugin}")
|
|
set_property(TARGET "${target}" APPEND PROPERTY EXPORT_PROPERTIES "QT_PLUGIN_CLASS_NAME;QT_MODULE;QT_DEFAULT_PLUGIN")
|
|
|
|
set(private_includes
|
|
"${CMAKE_CURRENT_SOURCE_DIR}"
|
|
"${CMAKE_CURRENT_BINARY_DIR}"
|
|
# For the syncqt headers
|
|
"$<BUILD_INTERFACE:${module_repo_include_dir}>"
|
|
${arg_INCLUDE_DIRECTORIES}
|
|
)
|
|
|
|
set(public_includes
|
|
${arg_PUBLIC_INCLUDE_DIRECTORIES}
|
|
)
|
|
|
|
extend_target("${target}"
|
|
SOURCES ${arg_SOURCES}
|
|
INCLUDE_DIRECTORIES
|
|
${private_includes}
|
|
PUBLIC_INCLUDE_DIRECTORIES
|
|
${public_includes}
|
|
LIBRARIES ${arg_LIBRARIES} Qt::PlatformPluginInternal
|
|
PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES}
|
|
DEFINES
|
|
${arg_DEFINES}
|
|
QT_DEPRECATED_WARNINGS
|
|
"${deprecation_define}"
|
|
"${static_plugin_define}"
|
|
QT_PLUGIN
|
|
PUBLIC_DEFINES
|
|
QT_${module_define}_LIB
|
|
${arg_PUBLIC_DEFINES}
|
|
FEATURE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES}
|
|
DBUS_ADAPTOR_SOURCES "${arg_DBUS_ADAPTOR_SOURCES}"
|
|
DBUS_ADAPTOR_FLAGS "${arg_DBUS_ADAPTOR_FLAGS}"
|
|
DBUS_INTERFACE_SOURCES "${arg_DBUS_INTERFACE_SOURCES}"
|
|
DBUS_INTERFACE_FLAGS "${arg_DBUS_INTERFACE_FLAGS}"
|
|
COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
|
|
PUBLIC_COMPILE_OPTIONS ${arg_PUBLIC_COMPILE_OPTIONS}
|
|
LINK_OPTIONS ${arg_LINK_OPTIONS}
|
|
PUBLIC_LINK_OPTIONS ${arg_PUBLIC_LINK_OPTIONS}
|
|
MOC_OPTIONS ${arg_MOC_OPTIONS}
|
|
ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
|
|
DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
|
|
)
|
|
if(NOT ${arg_EXCEPTIONS})
|
|
qt_internal_set_no_exceptions_flags("${target}")
|
|
endif()
|
|
|
|
|
|
set(qt_libs_private "")
|
|
qt_internal_get_qt_all_known_modules(known_modules)
|
|
foreach(it ${known_modules})
|
|
list(FIND arg_LIBRARIES "Qt::${it}Private" pos)
|
|
if(pos GREATER -1)
|
|
list(APPEND qt_libs_private "Qt::${it}Private")
|
|
endif()
|
|
endforeach()
|
|
|
|
qt_register_target_dependencies("${target}" "${arg_PUBLIC_LIBRARIES}" "${qt_libs_private}")
|
|
|
|
# Handle creation of cmake files for consumers of find_package().
|
|
# If we are part of a Qt module, the plugin cmake files are installed as part of that module.
|
|
if(qt_module)
|
|
set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${qt_module}")
|
|
else()
|
|
set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}")
|
|
endif()
|
|
|
|
qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix})
|
|
qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix})
|
|
|
|
configure_package_config_file(
|
|
"${QT_CMAKE_DIR}/QtPluginConfig.cmake.in"
|
|
"${config_build_dir}/${target}Config.cmake"
|
|
INSTALL_DESTINATION "${config_install_dir}"
|
|
)
|
|
write_basic_package_version_file(
|
|
"${config_build_dir}/${target}ConfigVersion.cmake"
|
|
VERSION ${PROJECT_VERSION}
|
|
COMPATIBILITY AnyNewerVersion
|
|
)
|
|
|
|
qt_install(FILES
|
|
"${config_build_dir}/${target}Config.cmake"
|
|
"${config_build_dir}/${target}ConfigVersion.cmake"
|
|
DESTINATION "${config_install_dir}"
|
|
COMPONENT Devel
|
|
)
|
|
|
|
# Make the export name of plugins be consistent with modules, so that
|
|
# add_qt_resource adds its additional targets to the same export set in a static Qt build.
|
|
set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets")
|
|
qt_install(TARGETS "${target}"
|
|
EXPORT ${export_name}
|
|
RUNTIME DESTINATION "${install_directory}"
|
|
LIBRARY DESTINATION "${install_directory}"
|
|
ARCHIVE DESTINATION "${archive_install_directory}"
|
|
)
|
|
qt_install(EXPORT ${export_name}
|
|
NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}::
|
|
DESTINATION "${config_install_dir}"
|
|
)
|
|
|
|
### fixme: cmake is missing a built-in variable for this. We want to apply it only to modules and plugins
|
|
# that belong to Qt.
|
|
qt_internal_add_link_flags_no_undefined("${target}")
|
|
|
|
qt_internal_add_linker_version_script(${target})
|
|
endfunction()
|
|
|
|
# Generate custom ${target}_qmltypes target for Qml Plugins
|
|
function(qt_add_qmltypes_target target)
|
|
|
|
# Do nothing when cross compiling
|
|
if (CMAKE_CROSSCOMPILING)
|
|
return()
|
|
endif()
|
|
|
|
qt_parse_all_arguments(arg "qt_generate_qmltypes"
|
|
""
|
|
"TARGET_PATH;IMPORT_VERSION;IMPORT_NAME;QML_PLUGINDUMP_DEPENDENCIES"
|
|
""
|
|
${ARGN})
|
|
|
|
# scan repos for qml repositories
|
|
foreach(repo IN LISTS QT_REPOS)
|
|
if (IS_DIRECTORY "${repo}/qml")
|
|
list(APPEND import_paths "${repo}/qml")
|
|
endif()
|
|
endforeach()
|
|
list(REMOVE_DUPLICATES import_paths)
|
|
if (UNIX)
|
|
list(JOIN import_paths ":" import_paths_env)
|
|
else()
|
|
list(JOIN import_paths "\;" import_paths_env)
|
|
endif()
|
|
|
|
if(NOT arg_IMPORT_NAME)
|
|
string(REGEX REPLACE "\\.\\d+$" "" import_name ${arg_TARGET_PATH})
|
|
else()
|
|
set(import_name ${arg_IMPORT_NAME})
|
|
endif()
|
|
|
|
if(NOT arg_IMPORT_VERSION)
|
|
message(FATAL_ERROR "Import version parameter was not specified. Specify the import version using the IMPORT_VERSION.")
|
|
endif()
|
|
|
|
get_target_property(source_dir ${target} SOURCE_DIR)
|
|
|
|
# qml1_target check is no longer required
|
|
set(qmltypes_command_args "-nonrelocatable")
|
|
if (NOT arg_QML_PLUGINDUMP_DEPENDENCIES AND EXISTS "${source_dir}/dependencies.json")
|
|
list(APPEND qmltypes_command_args "-dependencies" "${source_dir}/dependencies.json")
|
|
elseif(arg_QML_PLUGINDUMP_DEPENDENCIES)
|
|
list(APPEND qmltypes_command_args "-dependencies" "${arg_QML_PLUGINDUMP_DEPENDENCIES}")
|
|
endif()
|
|
|
|
string(REPLACE "/" "." import_name_arg ${import_name})
|
|
|
|
list(APPEND qmltypes_command_args "${import_name_arg}" "${arg_IMPORT_VERSION}")
|
|
|
|
set(qml_plugindump_target ${QT_CMAKE_EXPORT_NAMESPACE}::qmlplugindump)
|
|
|
|
# Manually set dependency on plugindump target since CMake will not add
|
|
# this rule because it's not the main executable argument to the COMMAND
|
|
# parameter.
|
|
add_custom_target(
|
|
"${target}_qmltypes"
|
|
DEPENDS ${qml_plugindump_target}
|
|
COMMAND ${CMAKE_COMMAND} -E env "QML2_IMPORTPATH=${import_paths_env}"
|
|
$<TARGET_FILE:${qml_plugindump_target}> ${qmltypes_command_args} > "${source_dir}/plugins.qmltypes"
|
|
)
|
|
endfunction()
|
|
|
|
# Create a custom target that will ensure all js and qml files are processed
|
|
# by the qmlcachegen tool during build. The generated jsc/qmlc files will
|
|
# also be added to list of files to be installed.
|
|
#
|
|
# TARGET_PATH: QML target path
|
|
# QML_FILES: List of QML Files
|
|
#
|
|
# Note: This will only run on non static builds.
|
|
#
|
|
function(add_qmlcachegen_target target)
|
|
if (NOT QT_BUILD_SHARED_LIBS)
|
|
# Do nothing for static builds since the QML files are embedded into
|
|
# the executable.
|
|
return()
|
|
endif()
|
|
|
|
if (NOT TARGET ${QT_CMAKE_EXPORT_NAMESPACE}::qmlcachegen)
|
|
message(FATAL_ERROR "Could not locate qmlcachegen tool. \
|
|
Please add QmlTools to your find_package command."
|
|
)
|
|
endif()
|
|
|
|
qt_parse_all_arguments(arg "add_qmlcachegen_target"
|
|
"" "TARGET_PATH" "QML_FILES" ${ARGN}
|
|
)
|
|
|
|
set(cache_dir "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/${arg_TARGET_PATH}")
|
|
|
|
foreach(qml_file IN LISTS arg_QML_FILES)
|
|
if("${qml_file}" MATCHES "\.m?js$" OR "${qml_file}" MATCHES "\.qml$")
|
|
if(NOT IS_ABSOLUTE ${qml_file})
|
|
get_filename_component(qml_file ${qml_file} ABSOLUTE)
|
|
endif()
|
|
file(RELATIVE_PATH qmlc_file "${CMAKE_CURRENT_SOURCE_DIR}" "${qml_file}")
|
|
set(qmlc_file "${cache_dir}/${qmlc_file}c")
|
|
list(APPEND qmlc_files ${qmlc_file})
|
|
add_custom_command(OUTPUT "${qmlc_file}"
|
|
DEPENDS
|
|
${qml_file}
|
|
COMMAND
|
|
${QT_CMAKE_EXPORT_NAMESPACE}::qmlcachegen -o ${qmlc_file} ${qml_file}
|
|
COMMENT
|
|
"Generating QML Cache for ${qml_file}"
|
|
)
|
|
endif()
|
|
endforeach()
|
|
|
|
if(qmlc_files)
|
|
set(qmlcachegen_target "${target}_qmlcachegen")
|
|
# Add custom target which depends on all the qmlc files and then add
|
|
# that target as a dependency of ${target}. This will guarantee
|
|
# that the qmlc file get generated.
|
|
add_custom_target(${qmlcachegen_target}
|
|
DEPENDS ${qmlc_files}
|
|
)
|
|
|
|
add_dependencies(${target} ${qmlcachegen_target})
|
|
|
|
if (QT_WILL_INSTALL)
|
|
# Only install on non-prefix builds, since the file does not exist
|
|
# at configuration time. Furthermore, the cached qml files are
|
|
# generated in the destination location for non-prefix builds.
|
|
qt_copy_or_install(
|
|
FILES ${qmlc_files}
|
|
DESTINATION ${INSTALL_QMLDIR}/${arg_TARGET_PATH}
|
|
)
|
|
endif()
|
|
endif()
|
|
|
|
endfunction()
|
|
|
|
function(qt_install_qml_files target)
|
|
|
|
qt_parse_all_arguments(arg "qt_install_qml_files"
|
|
"" "" "FILES" ${ARGN}
|
|
)
|
|
|
|
if (NOT arg_FILES)
|
|
message(FATAL_ERROR "No files specified for qt_install_qml_files. Please specify them using the FILES parameter.")
|
|
endif()
|
|
|
|
get_target_property(target_path ${target} QT_QML_MODULE_TARGET_PATH)
|
|
if (NOT target_path)
|
|
message(FATAL_ERROR "Target ${target} is not a qml module.")
|
|
endif()
|
|
|
|
qt_path_join(qml_module_install_dir ${QT_INSTALL_DIR} "${INSTALL_QMLDIR}/${target_path}")
|
|
qt_copy_or_install(FILES ${arg_FILES}
|
|
DESTINATION ${qml_module_install_dir}
|
|
)
|
|
|
|
endfunction()
|
|
|
|
|
|
function(add_qt_resource target resourceName)
|
|
# Don't try to add resources when cross compiling, and the target is actually a host target
|
|
# (like a tool).
|
|
qt_is_imported_target("${target}" is_imported)
|
|
if(is_imported)
|
|
return()
|
|
endif()
|
|
|
|
qt_parse_all_arguments(arg "add_qt_resource" "" "PREFIX;LANG;BASE" "FILES" ${ARGN})
|
|
|
|
QT6_PROCESS_RESOURCE(${target} ${resourceName}
|
|
PREFIX "${arg_PREFIX}"
|
|
LANG "${arg_LANG}"
|
|
BASE "${arg_BASE}"
|
|
FILES ${arg_FILES}
|
|
OUTPUT_TARGET out_target
|
|
)
|
|
|
|
if (out_target)
|
|
qt_install(TARGETS "${out_target}"
|
|
EXPORT "${INSTALL_CMAKE_NAMESPACE}${target}Targets"
|
|
DESTINATION ${INSTALL_LIBDIR}
|
|
)
|
|
endif()
|
|
|
|
endfunction()
|
|
|
|
|
|
# This function creates a CMake target for qml modules. It will also make
|
|
# sure that if no C++ source are present, that qml files show up in the project
|
|
# in an IDE. Finally, it will also create a custom ${target}_qmltypes which
|
|
# can be used to generate the respective plugin.qmltypes file.
|
|
#
|
|
# CPP_PLUGIN: Whether this qml module has any c++ source files.
|
|
# URI: Module's uri.
|
|
# TARGET_PATH: Expected installation path for the Qml Module. Equivalent
|
|
# to the module's URI where '.' is replaced with '/'. Use this to override the
|
|
# default substitution pattern.
|
|
# VERSION: Version of the qml module
|
|
# QML_PLUGINDUMP_DEPENDENCIES: Path to a dependencies.json file to be consumed
|
|
# with the ${target}_qmltypes target (optional)
|
|
#
|
|
function(add_qml_module target)
|
|
|
|
set(qml_module_optional_args
|
|
CPP_PLUGIN
|
|
)
|
|
|
|
set(qml_module_single_args
|
|
URI
|
|
TARGET_PATH
|
|
VERSION
|
|
QML_PLUGINDUMP_DEPENDENCIES
|
|
)
|
|
|
|
qt_parse_all_arguments(arg "add_qml_module"
|
|
"${__add_qt_plugin_optional_args};${qml_module_optional_args}"
|
|
"${__add_qt_plugin_single_args};${qml_module_single_args}"
|
|
"${__add_qt_plugin_multi_args}" ${ARGN})
|
|
|
|
if (NOT arg_URI)
|
|
message(FATAL_ERROR "add_qml_module called without specifying the module's uri. Please specify one using the URI parameter.")
|
|
endif()
|
|
|
|
set(target_path ${arg_TARGET_PATH})
|
|
|
|
if (NOT arg_VERSION)
|
|
message(FATAL_ERROR "add_qml_module called without specifying the module's import version. Please specify one using the VERSION parameter.")
|
|
endif()
|
|
|
|
if (NOT arg_TARGET_PATH)
|
|
string(REPLACE "." "/" arg_TARGET_PATH ${arg_URI})
|
|
endif()
|
|
|
|
qt_remove_args(plugin_args
|
|
ARGS_TO_REMOVE
|
|
${target}
|
|
${qml_module_multi_args}
|
|
${qml_module_single_args}
|
|
ALL_ARGS
|
|
${__add_qt_plugin_optional_args}
|
|
${__add_qt_plugin_single_args}
|
|
${qml_module_single_args}
|
|
${__add_qt_plugin_multi_args}
|
|
${qml_module_multi_args}
|
|
ARGS
|
|
${ARGV}
|
|
)
|
|
|
|
# If we have no sources, but qml files, create a custom target so the
|
|
# qml file will be visibile in an IDE.
|
|
if (NOT arg_CPP_PLUGIN)
|
|
add_custom_target(${target}
|
|
SOURCES ${arg_QML_FILES}
|
|
)
|
|
else()
|
|
add_qt_plugin(${target}
|
|
TYPE
|
|
qml_plugin
|
|
QML_TARGET_PATH
|
|
"${arg_TARGET_PATH}"
|
|
${plugin_args}
|
|
)
|
|
endif()
|
|
|
|
# Set target properties
|
|
set_target_properties(${target}
|
|
PROPERTIES
|
|
QT_QML_MODULE_TARGET_PATH ${arg_TARGET_PATH}
|
|
QT_QML_MODULE_URI ${arg_URI}
|
|
QT_RESOURCE_PREFIX "/qt-project.org/imports/${arg_TARGET_PATH}"
|
|
QT_QML_MODULE_VERSION ${arg_VERSION}
|
|
)
|
|
|
|
qt_add_qmltypes_target(${target}
|
|
TARGET_PATH "${arg_TARGET_PATH}"
|
|
IMPORT_VERSION "${arg_VERSION}"
|
|
IMPORT_NAME "${arg_URI}"
|
|
QML_PLUGINDUMP_DEPENDENCIES "${arg_QML_PLUGINDUMP_DEPENDENCIES}")
|
|
|
|
qt_path_join(qml_module_install_dir ${QT_INSTALL_DIR} "${INSTALL_QMLDIR}/${arg_TARGET_PATH}")
|
|
set(plugin_types "${CMAKE_CURRENT_SOURCE_DIR}/plugins.qmltypes")
|
|
if (EXISTS ${plugin_types})
|
|
qt_copy_or_install(FILES ${plugin_types}
|
|
DESTINATION "${qml_module_install_dir}"
|
|
)
|
|
|
|
if(QT_WILL_INSTALL)
|
|
# plugin.qmltypes when present should also be copied to the
|
|
# cmake binary dir when doing prefix builds
|
|
file(COPY ${plugin_types}
|
|
DESTINATION "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/${arg_TARGET_PATH}"
|
|
)
|
|
endif()
|
|
endif()
|
|
|
|
if (NOT QT_BUILD_SHARED_LIBS)
|
|
# only embed qmldir on static builds. Some qml modules may request
|
|
# their qml files to be embedded into their binary
|
|
string(REPLACE "." "_" qmldir_resource_name ${arg_TARGET_PATH})
|
|
string(REPLACE "/" "_" qmldir_resource_name ${qmldir_resource_name})
|
|
set(qmldir_resource_name "${qmldir_resource_name}_qmldir")
|
|
get_target_property(target_resource_prefix ${target} QT_RESOURCE_PREFIX)
|
|
set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
|
|
PROPERTIES QT_RESOURCE_ALIAS "qmldir"
|
|
)
|
|
add_qt_resource(${target} ${qmldir_resource_name}
|
|
PREFIX ${target_resource_prefix}
|
|
FILES "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
|
|
)
|
|
endif()
|
|
|
|
qt_copy_or_install(
|
|
FILES
|
|
"${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
|
|
DESTINATION
|
|
"${qml_module_install_dir}"
|
|
)
|
|
|
|
if(QT_WILL_INSTALL)
|
|
# qmldir should also be copied to the cmake binary dir when doing
|
|
# prefix builds
|
|
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
|
|
DESTINATION "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/${arg_TARGET_PATH}"
|
|
)
|
|
endif()
|
|
|
|
endfunction()
|
|
|
|
# Collection of add_qt_executable arguments so they can be shared across add_qt_executable
|
|
# and add_qt_test_helper.
|
|
set(__add_qt_executable_optional_args
|
|
"GUI;BOOTSTRAP;NO_QT;NO_INSTALL;EXCEPTIONS"
|
|
)
|
|
set(__add_qt_executable_single_args
|
|
"OUTPUT_DIRECTORY;INSTALL_DIRECTORY"
|
|
)
|
|
set(__add_qt_executable_multi_args
|
|
"EXE_FLAGS;${__default_private_args};${__default_public_args}"
|
|
)
|
|
|
|
# This function creates a CMake target for a generic console or GUI binary.
|
|
# Please consider to use a more specific version target like the one created
|
|
# by add_qt_test or add_qt_tool below.
|
|
function(add_qt_executable name)
|
|
qt_parse_all_arguments(arg "add_qt_executable"
|
|
"${__add_qt_executable_optional_args}"
|
|
"${__add_qt_executable_single_args}"
|
|
"${__add_qt_executable_multi_args}"
|
|
${ARGN})
|
|
|
|
if ("x${arg_OUTPUT_DIRECTORY}" STREQUAL "x")
|
|
set(arg_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${INSTALL_BINDIR}")
|
|
endif()
|
|
|
|
get_filename_component(arg_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}"
|
|
ABSOLUTE BASE_DIR "${CMAKE_BINARY_DIR}")
|
|
|
|
if ("x${arg_INSTALL_DIRECTORY}" STREQUAL "x")
|
|
set(arg_INSTALL_DIRECTORY "${INSTALL_BINDIR}")
|
|
endif()
|
|
|
|
add_executable("${name}" ${arg_EXE_FLAGS})
|
|
|
|
qt_autogen_tools_initial_setup(${name})
|
|
|
|
set(extra_libraries "")
|
|
if(NOT arg_BOOTSTRAP AND NOT arg_NO_QT)
|
|
set(extra_libraries "Qt::Core")
|
|
endif()
|
|
|
|
set(private_includes
|
|
"${CMAKE_CURRENT_SOURCE_DIR}"
|
|
"${CMAKE_CURRENT_BINARY_DIR}"
|
|
${arg_INCLUDE_DIRECTORIES}
|
|
)
|
|
|
|
extend_target("${name}"
|
|
SOURCES ${arg_SOURCES}
|
|
INCLUDE_DIRECTORIES ${private_includes}
|
|
DEFINES ${arg_DEFINES}
|
|
LIBRARIES ${arg_LIBRARIES}
|
|
PUBLIC_LIBRARIES ${extra_libraries} ${arg_PUBLIC_LIBRARIES}
|
|
DBUS_ADAPTOR_SOURCES "${arg_DBUS_ADAPTOR_SOURCES}"
|
|
DBUS_ADAPTOR_FLAGS "${arg_DBUS_ADAPTOR_FLAGS}"
|
|
DBUS_INTERFACE_SOURCES "${arg_DBUS_INTERFACE_SOURCES}"
|
|
DBUS_INTERFACE_FLAGS "${arg_DBUS_INTERFACE_FLAGS}"
|
|
COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
|
|
LINK_OPTIONS ${arg_LINK_OPTIONS}
|
|
MOC_OPTIONS ${arg_MOC_OPTIONS}
|
|
ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
|
|
DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
|
|
)
|
|
set_target_properties("${name}" PROPERTIES
|
|
RUNTIME_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}"
|
|
WIN32_EXECUTABLE "${arg_GUI}"
|
|
MACOSX_BUNDLE "${arg_GUI}"
|
|
)
|
|
if(NOT ${arg_EXCEPTIONS})
|
|
qt_internal_set_no_exceptions_flags("${name}")
|
|
endif()
|
|
|
|
|
|
if(NOT arg_NO_INSTALL)
|
|
qt_install(TARGETS "${name}"
|
|
RUNTIME DESTINATION "${arg_INSTALL_DIRECTORY}"
|
|
BUNDLE DESTINATION "${arg_INSTALL_DIRECTORY}")
|
|
endif()
|
|
endfunction()
|
|
|
|
|
|
# This function creates a CMake test target with the specified name for use with CTest.
|
|
function(add_qt_test name)
|
|
qt_parse_all_arguments(arg "add_qt_test"
|
|
"RUN_SERIAL;EXCEPTIONS;GUI;QMLTEST"
|
|
"QML_IMPORTPATH;OUTPUT_DIRECTORY" "TESTDATA;${__default_private_args};${__default_public_args}" ${ARGN})
|
|
|
|
if (NOT arg_OUTPUT_DIRECTORY)
|
|
set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
|
endif()
|
|
|
|
if (${arg_EXCEPTIONS})
|
|
set(exceptions_text "EXCEPTIONS")
|
|
endif()
|
|
|
|
if (${arg_GUI})
|
|
set(gui_text "GUI")
|
|
endif()
|
|
|
|
# Handle cases where we have a qml test without source files
|
|
if (arg_SOURCES)
|
|
set(private_includes
|
|
"${CMAKE_CURRENT_SOURCE_DIR}"
|
|
"${CMAKE_CURRENT_BINARY_DIR}"
|
|
"$<BUILD_INTERFACE:${QT_BUILD_DIR}/include>"
|
|
${arg_INCLUDE_DIRECTORIES}
|
|
)
|
|
|
|
add_qt_executable("${name}"
|
|
${exceptions_text}
|
|
${gui_text}
|
|
NO_INSTALL
|
|
OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}"
|
|
SOURCES "${arg_SOURCES}"
|
|
INCLUDE_DIRECTORIES
|
|
${private_includes}
|
|
DEFINES
|
|
QT_TESTCASE_BUILDDIR="${CMAKE_CURRENT_BINARY_DIR}"
|
|
QT_TESTCASE_SOURCEDIR="${CMAKE_CURRENT_SOURCE_DIR}"
|
|
${arg_DEFINES}
|
|
PUBLIC_LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::Core ${QT_CMAKE_EXPORT_NAMESPACE}::Test ${arg_PUBLIC_LIBRARIES}
|
|
LIBRARIES ${arg_LIBRARIES}
|
|
COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
|
|
LINK_OPTIONS ${arg_LINK_OPTIONS}
|
|
MOC_OPTIONS ${arg_MOC_OPTIONS}
|
|
ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
|
|
DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
|
|
)
|
|
|
|
# Tests should not be bundles on macOS even if arg_GUI is true, because some tests make
|
|
# assumptions about the location of helper processes, and those paths would be different
|
|
# if a test is built as a bundle.
|
|
set_property(TARGET "${name}" PROPERTY MACOSX_BUNDLE FALSE)
|
|
|
|
# QMLTest specifics
|
|
|
|
extend_target("${name}" CONDITION arg_QMLTEST
|
|
PUBLIC_LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::QuickTest
|
|
)
|
|
|
|
extend_target("${name}" CONDITION arg_QMLTEST AND NOT ANDROID
|
|
DEFINES
|
|
QUICK_TEST_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
|
|
)
|
|
|
|
extend_target("${name}" CONDITION arg_QMLTEST AND ANDROID
|
|
DEFINES
|
|
QUICK_TEST_SOURCE_DIR=":/"
|
|
)
|
|
endif()
|
|
|
|
if (arg_QML_IMPORTPATH)
|
|
set(extra_test_args "-import" "${arg_QML_IMPORTPATH}")
|
|
endif()
|
|
|
|
# Generate a label in the form tests/auto/foo/bar/tst_baz
|
|
# and use it also for XML output
|
|
file(RELATIVE_PATH label "${PROJECT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${name}")
|
|
|
|
if(arg_QMLTEST AND NOT arg_SOURCES)
|
|
set(test_working_dir "${CMAKE_CURRENT_SOURCE_DIR}")
|
|
set(test_executable ${QT_CMAKE_EXPORT_NAMESPACE}::qmltestrunner)
|
|
else()
|
|
set(test_working_dir "${CMAKE_CURRENT_BINARY_DIR}")
|
|
set(test_executable "${name}")
|
|
endif()
|
|
|
|
add_test(NAME "${name}" COMMAND ${test_executable} ${extra_test_args} -o ${name}.xml,xml -o -,txt WORKING_DIRECTORY "${test_working_dir}")
|
|
set_tests_properties("${name}" PROPERTIES RUN_SERIAL "${arg_RUN_SERIAL}" LABELS "${label}")
|
|
set_property(TEST "${name}" APPEND PROPERTY ENVIRONMENT "PATH=${path}${QT_PATH_SEPARATOR}${CMAKE_CURRENT_BINARY_DIR}${QT_PATH_SEPARATOR}$ENV{PATH}")
|
|
|
|
# Add the install prefix to list of plugin paths when doing a prefix build
|
|
if(NOT QT_INSTALL_DIR)
|
|
list(APPEND plugin_paths "${CMAKE_INSTALL_PREFIX}/${INSTALL_PLUGINSDIR}")
|
|
endif()
|
|
#TODO: Collect all paths from known repositories when performing a super
|
|
# build.
|
|
list(APPEND plugin_paths "${PROJECT_BINARY_DIR}/${INSTALL_PLUGINSDIR}")
|
|
list(JOIN plugin_paths "${QT_PATH_SEPARATOR}" plugin_paths_joined)
|
|
set_property(TEST "${name}" APPEND PROPERTY ENVIRONMENT "QT_PLUGIN_PATH=${plugin_paths_joined}")
|
|
|
|
if(ANDROID OR IOS OR WINRT)
|
|
set(builtin_testdata TRUE)
|
|
endif()
|
|
|
|
if(builtin_testdata)
|
|
# Safe guard against qml only tests, no source files == no target
|
|
if (TARGET "${name}")
|
|
target_compile_definitions("${name}" PRIVATE BUILTIN_TESTDATA)
|
|
|
|
foreach(testdata IN LISTS arg_TESTDATA)
|
|
list(APPEND builtin_files ${testdata})
|
|
endforeach()
|
|
|
|
set(blacklist_path "BLACKLIST")
|
|
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${blacklist_path}")
|
|
list(APPEND builtin_files ${blacklist_path})
|
|
endif()
|
|
|
|
list(REMOVE_DUPLICATES builtin_files)
|
|
|
|
# Skip Qt quick compiler when embedding test resources
|
|
foreach(file IN LISTS builtin_files)
|
|
set_source_files_properties(${file}
|
|
PROPERTIES QT_SKIP_QUICKCOMPILER TRUE
|
|
)
|
|
endforeach()
|
|
|
|
if (builtin_files)
|
|
add_qt_resource(${name} "testdata"
|
|
PREFIX "/"
|
|
FILES ${builtin_files}
|
|
BASE ${CMAKE_CURRENT_SOURCE_DIR})
|
|
endif()
|
|
endif()
|
|
else()
|
|
# Install test data
|
|
file(RELATIVE_PATH relative_path_to_test_project
|
|
"${QT_TOP_LEVEL_SOURCE_DIR}"
|
|
"${CMAKE_CURRENT_SOURCE_DIR}")
|
|
qt_path_join(testdata_install_dir ${QT_INSTALL_DIR}
|
|
"${relative_path_to_test_project}")
|
|
foreach(testdata IN LISTS arg_TESTDATA)
|
|
set(testdata "${CMAKE_CURRENT_SOURCE_DIR}/${testdata}")
|
|
if (IS_DIRECTORY "${testdata}")
|
|
qt_copy_or_install(
|
|
DIRECTORY "${testdata}"
|
|
DESTINATION "${testdata_install_dir}")
|
|
else()
|
|
qt_copy_or_install(
|
|
FILES "${testdata}"
|
|
DESTINATION "${testdata_install_dir}")
|
|
endif()
|
|
endforeach()
|
|
endif()
|
|
|
|
endfunction()
|
|
|
|
|
|
# This function creates an executable for use as a helper program with tests. Some
|
|
# tests launch separate programs to test certain input/output behavior.
|
|
# Specify OVERRIDE_OUTPUT_DIRECTORY if you dont' want to place the helper in the parent directory,
|
|
# in which case you should specify OUTPUT_DIRECTORY "/foo/bar" manually.
|
|
function(add_qt_test_helper name)
|
|
|
|
set(add_qt_test_helper_optional_args
|
|
"OVERRIDE_OUTPUT_DIRECTORY"
|
|
)
|
|
|
|
qt_parse_all_arguments(arg "add_qt_test_helper"
|
|
"${add_qt_test_helper_optional_args};${__add_qt_executable_optional_args}"
|
|
"${__add_qt_executable_single_args}"
|
|
"${__add_qt_executable_multi_args}"
|
|
${ARGN})
|
|
|
|
qt_remove_args(forward_args
|
|
ARGS_TO_REMOVE
|
|
"${name}"
|
|
${add_qt_test_helper_optional_args}
|
|
ALL_ARGS
|
|
${add_qt_test_helper_optional_args}
|
|
${__add_qt_executable_optional_args}
|
|
${__add_qt_executable_single_args}
|
|
${__add_qt_executable_multi_args}
|
|
ARGS
|
|
${ARGV}
|
|
)
|
|
|
|
set(extra_args_to_pass)
|
|
if(NOT arg_OVERRIDE_OUTPUT_DIRECTORY)
|
|
set(extra_args_to_pass OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/..")
|
|
endif()
|
|
|
|
add_qt_executable("${name}" NO_INSTALL ${extra_args_to_pass} ${forward_args})
|
|
endfunction()
|
|
|
|
# Sets QT_WILL_BUILD_TOOLS if tools will be built.
|
|
function(qt_check_if_tools_will_be_built)
|
|
if(NOT CMAKE_CROSSCOMPILING AND NOT QT_FORCE_FIND_TOOLS)
|
|
set(will_build_tools TRUE)
|
|
else()
|
|
set(will_build_tools FALSE)
|
|
endif()
|
|
set(QT_WILL_BUILD_TOOLS ${will_build_tools} CACHE INTERNAL "Are tools going to be built" FORCE)
|
|
endfunction()
|
|
|
|
# This function is used to define a "Qt tool", such as moc, uic or rcc.
|
|
# The BOOTSTRAP option allows building it as standalone program, otherwise
|
|
# it will be linked against QtCore.
|
|
function(add_qt_tool name)
|
|
qt_parse_all_arguments(arg "add_qt_tool" "BOOTSTRAP;NO_QT;NO_INSTALL" "TOOLS_TARGET"
|
|
"${__default_private_args}" ${ARGN})
|
|
|
|
# Handle case when a tool does not belong to a module and it can't be built either (like
|
|
# during a cross-compile).
|
|
if(NOT arg_TOOLS_TARGET AND NOT QT_WILL_BUILD_TOOLS)
|
|
message(FATAL_ERROR "The tool \"${name}\" has not been assigned to a module via"
|
|
" TOOLS_TARGET (so it can't be found) and it can't be built"
|
|
" (QT_WILL_BUILD_TOOLS is ${QT_WILL_BUILD_TOOLS}).")
|
|
endif()
|
|
|
|
set(full_name "${QT_CMAKE_EXPORT_NAMESPACE}::${name}")
|
|
if(TARGET ${full_name})
|
|
get_property(path TARGET ${full_name} PROPERTY LOCATION)
|
|
message(STATUS "Tool '${full_name}' was found at ${path}.")
|
|
return()
|
|
endif()
|
|
|
|
if(arg_TOOLS_TARGET AND NOT QT_WILL_BUILD_TOOLS)
|
|
set(tools_package_name "Qt6${arg_TOOLS_TARGET}Tools")
|
|
message(STATUS "Searching for tool '${full_name}' in package ${tools_package_name}.")
|
|
|
|
# Only search in path provided by QT_HOST_PATH. We need to do it with CMAKE_PREFIX_PATH
|
|
# instead of PATHS option, because any find_dependency call inside a Tools package would
|
|
# not get the proper prefix when using PATHS.
|
|
set(BACKUP_CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH})
|
|
set(CMAKE_PREFIX_PATH "${QT_HOST_PATH}")
|
|
|
|
# Search both with sysroots prepended as well as in the host system. When cross compiling
|
|
# the mode_package might be set to ONLY only, and the Qt6 tools packages are actually
|
|
# in the host system.
|
|
set(BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ${CMAKE_FIND_ROOT_PATH_MODE_PACKAGE})
|
|
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "BOTH")
|
|
set(BACKUP_CMAKE_SIZEOF_VOID_P "${CMAKE_SIZEOF_VOID_P}")
|
|
set(CMAKE_SIZEOF_VOID_P "")
|
|
find_package(
|
|
${tools_package_name}
|
|
${PROJECT_VERSION}
|
|
NO_PACKAGE_ROOT_PATH
|
|
NO_CMAKE_ENVIRONMENT_PATH
|
|
NO_SYSTEM_ENVIRONMENT_PATH
|
|
NO_CMAKE_PACKAGE_REGISTRY
|
|
NO_CMAKE_SYSTEM_PATH
|
|
NO_CMAKE_SYSTEM_PACKAGE_REGISTRY)
|
|
set(CMAKE_SIZEOF_VOID_P "${BACKUP_CMAKE_SIZEOF_VOID_P}")
|
|
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "${BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}")
|
|
set(CMAKE_PREFIX_PATH "${BACKUP_CMAKE_PREFIX_PATH}")
|
|
|
|
if(${${tools_package_name}_FOUND} AND TARGET ${full_name})
|
|
# Even if the tool is already visible, make sure that our modules remain associated
|
|
# with the tools.
|
|
qt_internal_append_known_modules_with_tools("${arg_TOOLS_TARGET}")
|
|
get_property(path TARGET ${full_name} PROPERTY LOCATION)
|
|
message(STATUS "${full_name} was found at ${path} using package ${tools_package_name}.")
|
|
return()
|
|
endif()
|
|
endif()
|
|
|
|
if(NOT QT_WILL_BUILD_TOOLS)
|
|
message(FATAL_ERROR "The tool \"${full_name}\" was not found in the "
|
|
"${tools_package_name} package. "
|
|
"Package found: ${${tools_package_name}_FOUND}")
|
|
else()
|
|
message(STATUS "Tool '${full_name}' will be built from source.")
|
|
endif()
|
|
|
|
set(disable_autogen_tools "${arg_DISABLE_AUTOGEN_TOOLS}")
|
|
if (arg_NO_QT)
|
|
# FIXME: Remove NO_QT again once qmake can use a "normal" Qt!
|
|
if (arg_BOOTSTRAP)
|
|
message(FATAL_ERROR "Tool can not be NO_QT and BOOTSTRAP at the same time!")
|
|
endif()
|
|
set(corelib "")
|
|
else()
|
|
if (arg_BOOTSTRAP)
|
|
set(corelib ${QT_CMAKE_EXPORT_NAMESPACE}::Bootstrap)
|
|
list(APPEND disable_autogen_tools "uic" "moc" "rcc")
|
|
else()
|
|
set(corelib ${QT_CMAKE_EXPORT_NAMESPACE}::Core)
|
|
endif()
|
|
endif()
|
|
|
|
set(bootstrap "")
|
|
if(arg_BOOTSTRAP)
|
|
set(bootstrap BOOTSTRAP)
|
|
endif()
|
|
|
|
set(no_qt "")
|
|
if(arg_NO_QT)
|
|
set(no_qt NO_QT)
|
|
endif()
|
|
|
|
set(no_install "")
|
|
if(arg_NO_INSTALL)
|
|
set(no_install NO_INSTALL)
|
|
endif()
|
|
|
|
add_qt_executable("${name}" OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}"
|
|
${bootstrap}
|
|
${no_qt}
|
|
${no_install}
|
|
SOURCES ${arg_SOURCES}
|
|
INCLUDE_DIRECTORIES
|
|
${arg_INCLUDE_DIRECTORIES}
|
|
DEFINES ${arg_DEFINES}
|
|
PUBLIC_LIBRARIES ${corelib}
|
|
LIBRARIES ${arg_LIBRARIES} Qt::PlatformToolInternal
|
|
COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
|
|
LINK_OPTIONS ${arg_LINK_OPTIONS}
|
|
MOC_OPTIONS ${arg_MOC_OPTIONS}
|
|
DISABLE_AUTOGEN_TOOLS ${disable_autogen_tools}
|
|
)
|
|
qt_internal_add_target_aliases("${name}")
|
|
|
|
set_target_properties("${name}" PROPERTIES
|
|
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${QT_BUILD_DIR}/${INSTALL_BINDIR}"
|
|
)
|
|
|
|
if(NOT arg_NO_INSTALL AND arg_TOOLS_TARGET)
|
|
# Assign a tool to an export set, and mark the module to which the tool belongs.
|
|
qt_internal_append_known_modules_with_tools("${arg_TOOLS_TARGET}")
|
|
|
|
# Also append the tool to the module list.
|
|
qt_internal_append_known_module_tool("${arg_TOOLS_TARGET}" "${name}")
|
|
|
|
qt_install(TARGETS "${name}"
|
|
EXPORT "${INSTALL_CMAKE_NAMESPACE}${arg_TOOLS_TARGET}ToolsTargets"
|
|
DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS})
|
|
endif()
|
|
endfunction()
|
|
|
|
function(qt_create_tracepoints name tracePointsFile)
|
|
#### TODO
|
|
string(TOLOWER "${name}" name)
|
|
|
|
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/qt${name}_tracepoints_p.h" CONTENT
|
|
"#include <private/qtrace_p.h>")
|
|
endfunction()
|
|
|
|
# Handle files that need special SIMD-related flags.
|
|
# This creates an object library and makes target link
|
|
# to it (privately).
|
|
function(add_qt_simd_part target)
|
|
qt_parse_all_arguments(arg "add_qt_simd_part" "" ""
|
|
"NAME;SIMD;${__default_private_args};COMPILE_FLAGS" ${ARGN})
|
|
if ("x${arg_SIMD}" STREQUAL x)
|
|
message(FATAL_ERROR "add_qt_simd_part needs a SIMD type to be set.")
|
|
endif()
|
|
|
|
set(condition "QT_FEATURE_${arg_SIMD}")
|
|
if("${arg_SIMD}" STREQUAL arch_haswell)
|
|
set(condition "TEST_subarch_avx2 AND TEST_subarch_bmi AND TEST_subarch_bmi2 AND TEST_subarch_f16c AND TEST_subarch_fma AND TEST_subarch_lzcnt AND TEST_subarch_popcnt")
|
|
elseif("${arg_SIMD}" STREQUAL avx512common)
|
|
set(condition "TEST_subarch_avx512cd")
|
|
elseif("${arg_SIMD}" STREQUAL avx512core)
|
|
set(condition "TEST_subarch_avx512cd AND TEST_subarch_avx512bw AND TEST_subarch_avx512dq AND TEST_subarch_avx512vl")
|
|
endif()
|
|
|
|
set(name "${arg_NAME}")
|
|
if("x${name}" STREQUAL x)
|
|
set(name "${target}_simd_${arg_SIMD}")
|
|
endif()
|
|
|
|
qt_evaluate_config_expression(result ${condition})
|
|
if(${result})
|
|
if(QT_CMAKE_DEBUG_EXTEND_TARGET)
|
|
message("add_qt_simd_part(${target} SIMD ${arg_SIMD} ...): Evaluated")
|
|
endif()
|
|
string(TOUPPER "QT_CFLAGS_${arg_SIMD}" simd_flags)
|
|
|
|
add_library("${name}" OBJECT)
|
|
target_sources("${name}" PRIVATE ${arg_SOURCES})
|
|
target_include_directories("${name}" PRIVATE
|
|
${arg_INCLUDE_DIRECTORIES}
|
|
$<TARGET_PROPERTY:${target},INCLUDE_DIRECTORIES>)
|
|
target_compile_options("${name}" PRIVATE
|
|
${${simd_flags}}
|
|
${arg_COMPILE_FLAGS}
|
|
$<TARGET_PROPERTY:${target},COMPILE_OPTIONS>)
|
|
target_compile_definitions("${name}" PRIVATE
|
|
$<TARGET_PROPERTY:${target},COMPILE_DEFINITIONS>)
|
|
|
|
target_link_libraries("${target}" PRIVATE "${name}")
|
|
|
|
if(NOT BUILD_SHARED_LIBS)
|
|
qt_install(
|
|
TARGETS ${name}
|
|
EXPORT "${INSTALL_CMAKE_NAMESPACE}Targets"
|
|
)
|
|
endif()
|
|
else()
|
|
if(QT_CMAKE_DEBUG_EXTEND_TARGET)
|
|
message("add_qt_simd_part(${target} SIMD ${arg_SIMD} ...): Skipped")
|
|
endif()
|
|
endif()
|
|
endfunction()
|
|
|
|
# From Qt6CoreMacros
|
|
# Function used to create the names of output files preserving relative dirs
|
|
function(qt_make_output_file infile prefix suffix source_dir binary_dir result)
|
|
get_filename_component(outfilename "${infile}" NAME_WE)
|
|
|
|
set(base_dir "${source_dir}")
|
|
string(FIND "${infile}" "${binary_dir}/" in_binary)
|
|
if (in_binary EQUAL 0)
|
|
set(base_dir "${binary_dir}")
|
|
endif()
|
|
|
|
get_filename_component(abs_infile "${infile}" ABSOLUTE BASE_DIR "${base_dir}")
|
|
file(RELATIVE_PATH rel_infile "${base_dir}" "${abs_infile}")
|
|
string(REPLACE "../" "__/" mapped_infile "${rel_infile}")
|
|
|
|
get_filename_component(abs_mapped_infile "${mapped_infile}" ABSOLUTE BASE_DIR "${binary_dir}")
|
|
get_filename_component(outpath "${abs_mapped_infile}" PATH)
|
|
|
|
file(MAKE_DIRECTORY "${outpath}")
|
|
set("${result}" "${outpath}/${prefix}${outfilename}${suffix}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
|
|
# Complete manual moc invocation with full control.
|
|
# Use AUTOMOC whenever possible.
|
|
function(qt_manual_moc result)
|
|
cmake_parse_arguments(arg "" "" "FLAGS" ${ARGN})
|
|
set(moc_files)
|
|
foreach(infile ${arg_UNPARSED_ARGUMENTS})
|
|
qt_make_output_file("${infile}" "moc_" ".cpp"
|
|
"${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" outfile)
|
|
list(APPEND moc_files "${outfile}")
|
|
|
|
set(moc_parameters_file "${outfile}_parameters$<$<BOOL:$<CONFIGURATION>>:_$<CONFIGURATION>>")
|
|
set(moc_parameters ${arg_FLAGS} -o "${outfile}" "${infile}")
|
|
string (REPLACE ";" "\n" moc_parameters "${moc_parameters}")
|
|
|
|
file(GENERATE OUTPUT "${moc_parameters_file}" CONTENT "${moc_parameters}\n")
|
|
|
|
add_custom_command(OUTPUT "${outfile}"
|
|
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::moc "@${moc_parameters_file}"
|
|
DEPENDS "${infile}" ${moc_depends} ${QT_CMAKE_EXPORT_NAMESPACE}::moc
|
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" VERBATIM)
|
|
endforeach()
|
|
set("${result}" ${moc_files} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
|
|
# helper to set up a qdbusxml2cpp rule
|
|
function(qt_create_qdbusxml2cpp_command target infile)
|
|
qt_parse_all_arguments(arg "qt_create_qdbusxml2cpp_command" "ADAPTOR;INTERFACE" "BASENAME" "FLAGS" ${ARGN})
|
|
if((arg_ADAPTOR AND arg_INTERFACE) OR (NOT arg_ADAPTOR AND NOT arg_INTERFACE))
|
|
message(FATAL_ERROR "qt_create_dbusxml2cpp_command needs either ADAPTOR or INTERFACE.")
|
|
endif()
|
|
|
|
set(option "-a")
|
|
set(type "adaptor")
|
|
if (arg_INTERFACE)
|
|
set(option "-p")
|
|
set(type "interface")
|
|
endif()
|
|
|
|
if ("${arg_BASENAME}" STREQUAL "")
|
|
get_filename_component(file_dir "${infile}" DIRECTORY)
|
|
get_filename_component(file_name "${infile}" NAME_WLE)
|
|
get_filename_component(file_ext "${infile}" LAST_EXT)
|
|
|
|
if("${file_ext}" STREQUAL ".xml")
|
|
else()
|
|
message(FATAL_ERROR "DBUS ${type} input file is not xml.")
|
|
endif()
|
|
|
|
# use last part of io.qt.something.xml!
|
|
get_filename_component(file_ext "${file_name}" LAST_EXT)
|
|
if("x${file_ext}" STREQUAL "x")
|
|
else()
|
|
string(SUBSTRING "${file_ext}" 1 -1 file_name) # cut of leading '.'
|
|
endif()
|
|
|
|
string(TOLOWER "${file_name}" file_name)
|
|
set(file_name "${file_name}_${type}")
|
|
else()
|
|
set(file_name ${arg_BASENAME})
|
|
endif()
|
|
|
|
# Use absolute file path for the source file and set the current working directory to the
|
|
# current binary directory, because setting an absolute path for the header:source combo option
|
|
# does not work. Splitting on ":" breaks inside the dbus tool when running on Windows
|
|
# due to ":" being contained in the drive path (e.g C:\foo.h:C:\foo.cpp).
|
|
get_filename_component(absolute_in_file_path "${infile}" ABSOLUTE)
|
|
|
|
set(header_file "${file_name}.h")
|
|
set(source_file "${file_name}.cpp")
|
|
|
|
add_custom_command(OUTPUT "${header_file}" "${source_file}"
|
|
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::qdbusxml2cpp ${arg_FLAGS} "${option}"
|
|
"${header_file}:${source_file}" "${absolute_in_file_path}"
|
|
DEPENDS "${absolute_in_file_path}"
|
|
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
|
VERBATIM)
|
|
|
|
target_sources("${target}" PRIVATE "${header_file}" "${source_file}")
|
|
endfunction()
|
|
|
|
function(qt_compute_injection_forwarding_header target)
|
|
qt_parse_all_arguments(arg "qt_compute_injection_forwarding_header"
|
|
"PRIVATE" "SOURCE;OUT_VAR" "" ${ARGN})
|
|
qt_internal_module_info(module "${target}")
|
|
get_filename_component(file_name "${arg_SOURCE}" NAME)
|
|
|
|
set(source_absolute_path "${CMAKE_CURRENT_BINARY_DIR}/${arg_SOURCE}")
|
|
file(RELATIVE_PATH relpath "${CMAKE_BINARY_DIR}" "${source_absolute_path}")
|
|
|
|
if (arg_PRIVATE)
|
|
set(fwd "${PROJECT_VERSION}/${module}/private/${file_name}")
|
|
else()
|
|
set(fwd "${file_name}")
|
|
endif()
|
|
|
|
string(APPEND ${arg_OUT_VAR} " ${relpath}:${fwd}")
|
|
set(${arg_OUT_VAR} ${${arg_OUT_VAR}} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
|
|
function(add_qt_docs qdocFile)
|
|
# TODO
|
|
endfunction()
|
|
|
|
macro(qt_find_package)
|
|
# Get the target names we expect to be provided by the package.
|
|
set(options CONFIG NO_MODULE MODULE REQUIRED)
|
|
set(oneValueArgs)
|
|
set(multiValueArgs PROVIDED_TARGETS COMPONENTS)
|
|
cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
# Get the version if specified.
|
|
set(package_version "")
|
|
if(${ARGC} GREATER_EQUAL 2)
|
|
if(${ARGV1} MATCHES "^[0-9\.]+$")
|
|
set(package_version "${ARGV1}")
|
|
endif()
|
|
endif()
|
|
|
|
if(arg_COMPONENTS)
|
|
# Re-append components to forward them.
|
|
list(APPEND arg_UNPARSED_ARGUMENTS "COMPONENTS;${arg_COMPONENTS}")
|
|
endif()
|
|
|
|
if(NOT (arg_CONFIG OR arg_NO_MODULE OR arg_MODULE))
|
|
# Try to find a config package first in quiet mode
|
|
set(config_package_arg ${arg_UNPARSED_ARGUMENTS})
|
|
list(APPEND config_package_arg "CONFIG;QUIET")
|
|
find_package(${config_package_arg})
|
|
|
|
# Double check that in config mode the targets become visible. Sometimes
|
|
# only the module mode creates the targets. For example with vcpkg, the sqlite
|
|
# package provides sqlite3-config.cmake, which offers multi-config targets but
|
|
# in their own way. CMake has FindSQLite3.cmake and with the original
|
|
# qt_find_package(SQLite3) call it is our intention to use the cmake package
|
|
# in module mode.
|
|
if (${ARGV0}_FOUND AND arg_PROVIDED_TARGETS)
|
|
unset(any_target_found)
|
|
foreach(expected_target ${arg_PROVIDED_TARGETS})
|
|
if (TARGET ${expected_target})
|
|
set(any_target_found TRUE)
|
|
break()
|
|
endif()
|
|
endforeach()
|
|
if(NOT any_target_found)
|
|
unset(${ARGV0}_FOUND)
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
# Ensure the options are back in the original unparsed arguments
|
|
foreach(opt IN LISTS options)
|
|
if(arg_${opt})
|
|
list(APPEND arg_UNPARSED_ARGUMENTS ${opt})
|
|
endif()
|
|
endforeach()
|
|
|
|
if (NOT ${ARGV0}_FOUND)
|
|
# Call original function without our custom arguments.
|
|
find_package(${arg_UNPARSED_ARGUMENTS})
|
|
endif()
|
|
|
|
if(${ARGV0}_FOUND AND arg_PROVIDED_TARGETS)
|
|
# If package was found, associate each target with its package name. This will be used
|
|
# later when creating Config files for Qt libraries, to generate correct find_dependency()
|
|
# calls. Also make the provided targets global, so that the properties can be read in
|
|
# all scopes.
|
|
foreach(qt_find_package_target_name ${arg_PROVIDED_TARGETS})
|
|
if(TARGET ${qt_find_package_target_name})
|
|
# Allow usage of aliased targets by setting properties on the actual target
|
|
get_target_property(aliased_target ${qt_find_package_target_name} ALIASED_TARGET)
|
|
if(aliased_target)
|
|
set(qt_find_package_target_name ${aliased_target})
|
|
endif()
|
|
|
|
set_target_properties(${qt_find_package_target_name}
|
|
PROPERTIES INTERFACE_QT_PACKAGE_NAME ${ARGV0})
|
|
if(package_version)
|
|
set_target_properties(${qt_find_package_target_name}
|
|
PROPERTIES INTERFACE_QT_PACKAGE_VERSION ${ARGV1})
|
|
endif()
|
|
|
|
if(arg_COMPONENTS)
|
|
string(REPLACE ";" " " components_as_string "${arg_COMPONENTS}")
|
|
set_property(TARGET ${qt_find_package_target_name}
|
|
PROPERTY INTERFACE_QT_PACKAGE_COMPONENTS ${components_as_string})
|
|
endif()
|
|
|
|
get_property(is_global TARGET ${qt_find_package_target_name} PROPERTY
|
|
IMPORTED_GLOBAL)
|
|
if(NOT is_global)
|
|
set_property(TARGET ${qt_find_package_target_name} PROPERTY
|
|
IMPORTED_GLOBAL TRUE)
|
|
endif()
|
|
endif()
|
|
|
|
endforeach()
|
|
endif()
|
|
endmacro()
|
|
|
|
# Creates a simple export set for the various Find* dependencies
|
|
# which are needed when creating a static build of Qt.
|
|
# This introduces a custom target property: INTERFACE_QT_EXPORTED_LIBRARY
|
|
# This target property indicates that Qt modules / plugins using this 3rd party library
|
|
# must add it to their list of dependencies when creating their own ${qtmodule}Config.cmake
|
|
function(qt_install_static_target_export target)
|
|
if(BUILD_SHARED_LIBS)
|
|
return()
|
|
endif()
|
|
|
|
qt_parse_all_arguments(arg "qt_install_3rdparty_config_files" "" "EXPORT" "" ${ARGN})
|
|
# TODO mark EXPORT as required
|
|
|
|
set_target_properties(${target}
|
|
PROPERTIES
|
|
INTERFACE_QT_EXPORTED_LIBRARY 1)
|
|
|
|
qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${arg_EXPORT})
|
|
|
|
set(export_name "${arg_EXPORT}Targets")
|
|
qt_install(
|
|
TARGETS ${target}
|
|
EXPORT ${export_name}
|
|
LIBRARY DESTINATION ${INSTALL_LIBDIR}
|
|
ARCHIVE DESTINATION ${INSTALL_LIBDIR})
|
|
|
|
qt_install(
|
|
EXPORT ${export_name}
|
|
DESTINATION "${config_install_dir}"
|
|
)
|
|
endfunction()
|
|
|
|
# Create a set of ${target}Config.cmake and ${target}Version.cmake for a
|
|
# third-party library so that it can be found by client code linking statically.
|
|
function(qt_install_3rdparty_config_files target)
|
|
if(BUILD_SHARED_LIBS)
|
|
return()
|
|
endif()
|
|
|
|
qt_parse_all_arguments(arg "qt_install_3rdparty_config_files" "" "EXPORT" "PACKAGES;ADDITIONAL_FILES" ${ARGN})
|
|
# TODO mark EXPORT as required
|
|
|
|
set(3RDPARTY_ADDITIONAL_SETUP_CODE)
|
|
foreach(package ${arg_PACKAGES})
|
|
list(APPEND 3RDPARTY_ADDITIONAL_SETUP_CODE "find_package(${package})\n")
|
|
endforeach()
|
|
|
|
set(path_suffix "${arg_EXPORT}")
|
|
qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix})
|
|
qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix})
|
|
|
|
configure_package_config_file(
|
|
"${PROJECT_SOURCE_DIR}/cmake/3rdpartyConfig.cmake.in"
|
|
"${config_build_dir}/${target}Config.cmake"
|
|
INSTALL_DESTINATION "${config_install_dir}"
|
|
)
|
|
|
|
write_basic_package_version_file(
|
|
"${config_build_dir}/${target}ConfigVersion.cmake"
|
|
VERSION ${PROJECT_VERSION}
|
|
COMPATIBILITY AnyNewerVersion
|
|
)
|
|
|
|
qt_install(FILES
|
|
"${config_build_dir}/${target}Config.cmake"
|
|
"${config_build_dir}/${target}ConfigVersion.cmake"
|
|
${arg_ADDITIONAL_FILES}
|
|
DESTINATION "${config_install_dir}"
|
|
COMPONENT Devel
|
|
)
|
|
endfunction()
|
|
|
|
# Call this function in 3rdparty find modules that ought to be installed alongside
|
|
# Qt modules and must be found when linking statically.
|
|
function(qt_install_3rdparty_library target)
|
|
qt_install_static_target_export(${target} EXPORT ${target})
|
|
qt_install_3rdparty_config_files(${target} EXPORT ${target} ${ARGN})
|
|
endfunction()
|
|
|
|
macro(qt_find_apple_system_frameworks)
|
|
if(APPLE)
|
|
find_library(FWAppKit AppKit)
|
|
find_library(FWApplicationServices ApplicationServices)
|
|
find_library(FWCarbon Carbon)
|
|
find_library(FWCoreFoundation CoreFoundation)
|
|
find_library(FWCoreServices CoreServices)
|
|
find_library(FWCoreVideo CoreVideo)
|
|
find_library(FWcups cups)
|
|
find_library(FWDiskArbitration DiskArbitration)
|
|
find_library(FWFoundation Foundation)
|
|
find_library(FWIOKit IOKit)
|
|
find_library(FWIOSurface IOSurface)
|
|
find_library(FWImageIO ImageIO)
|
|
find_library(FWMetal Metal)
|
|
find_library(FWMobileCoreServices MobileCoreServices)
|
|
find_library(FWQuartzCore QuartzCore)
|
|
find_library(FWSecurity Security)
|
|
find_library(FWSystemConfiguration SystemConfiguration)
|
|
find_library(FWUIKit UIKit)
|
|
find_library(FWWatchKit WatchKit)
|
|
endif()
|
|
endmacro()
|
|
|
|
# Match the pattern 'regex' in 'input_line', replace the match with 'replacement'
|
|
# and set that result in 'out_var' in the parent scope.
|
|
function(qt_regex_match_and_get input_line regex replacement out_var)
|
|
string(REGEX MATCH "${regex}" match "${input_line}")
|
|
if(match)
|
|
string(REGEX REPLACE "${regex}" "${replacement}" match "${input_line}")
|
|
string(STRIP ${match} match)
|
|
set(${out_var} "${match}" PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
# Match 'regex' in a list of lines. When found, set the value to 'out_var' and break early.
|
|
function(qt_qlalr_find_option_in_list input_list regex out_var)
|
|
foreach(line ${input_list})
|
|
qt_regex_match_and_get("${line}" "${regex}" "\\1" option)
|
|
if(option)
|
|
string(TOLOWER ${option} option)
|
|
set(${out_var} "${option}" PARENT_SCOPE)
|
|
return()
|
|
endif()
|
|
endforeach()
|
|
message(FATAL_ERROR "qt_qlalr_find_option_in_list: Could not extract ${out_var}")
|
|
endfunction()
|
|
|
|
# Generate a few output files using qlalr, and assign those to 'consuming_target'.
|
|
# 'input_file_list' is a list of 'foo.g' file paths.
|
|
# 'flags' are extra flags to be passed to qlalr.
|
|
function(qt_process_qlalr input_file_list consuming_target flags)
|
|
foreach(input_file ${input_file_list})
|
|
file(STRINGS ${input_file} input_file_lines)
|
|
qt_qlalr_find_option_in_list("${input_file_lines}" "^%parser(.+)" "parser")
|
|
qt_qlalr_find_option_in_list("${input_file_lines}" "^%decl(.+)" "decl")
|
|
qt_qlalr_find_option_in_list("${input_file_lines}" "^%impl(.+)" "impl")
|
|
get_filename_component(base_file_name ${input_file} NAME_WE)
|
|
|
|
set(cpp_file "${parser}.cpp")
|
|
set(private_file "${parser}_p.h")
|
|
set(decl_file "${decl}")
|
|
set(impl_file "${impl}")
|
|
add_custom_command(
|
|
OUTPUT ${cpp_file} ${private_file} ${decl_file} ${impl_file}
|
|
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::qlalr ${flags} ${input_file}
|
|
MAIN_DEPENDENCY ${input_file}
|
|
)
|
|
target_sources(${consuming_target} PRIVATE ${cpp_file} ${impl_file})
|
|
endforeach()
|
|
endfunction()
|
|
|
|
macro(qt_add_string_to_qconfig_cpp str)
|
|
string(LENGTH "${str}" length)
|
|
string(APPEND QT_CONFIG_STRS " \"${str}\\0\"\n")
|
|
string(APPEND QT_CONFIG_STR_OFFSETS " ${QT_CONFIG_STR_OFFSET},\n")
|
|
math(EXPR QT_CONFIG_STR_OFFSET "${QT_CONFIG_STR_OFFSET}+${length}+1")
|
|
endmacro()
|
|
|
|
function(qt_generate_qconfig_cpp)
|
|
set(QT_CONFIG_STR_OFFSET "0")
|
|
set(QT_CONFIG_STR_OFFSETS "")
|
|
set(QT_CONFIG_STRS "")
|
|
|
|
# Start first part.
|
|
qt_add_string_to_qconfig_cpp("doc")
|
|
qt_add_string_to_qconfig_cpp("include")
|
|
qt_add_string_to_qconfig_cpp("lib")
|
|
qt_add_string_to_qconfig_cpp("libexec")
|
|
qt_add_string_to_qconfig_cpp("bin")
|
|
qt_add_string_to_qconfig_cpp("plugins")
|
|
qt_add_string_to_qconfig_cpp("imports")
|
|
qt_add_string_to_qconfig_cpp("qml")
|
|
qt_add_string_to_qconfig_cpp(".")
|
|
qt_add_string_to_qconfig_cpp(".")
|
|
qt_add_string_to_qconfig_cpp("translations")
|
|
qt_add_string_to_qconfig_cpp("examples")
|
|
qt_add_string_to_qconfig_cpp("tests")
|
|
|
|
# Save first part.
|
|
set(QT_CONFIG_STR_OFFSETS_FIRST "${QT_CONFIG_STR_OFFSETS}")
|
|
set(QT_CONFIG_STRS_FIRST "${QT_CONFIG_STRS}")
|
|
|
|
# Start second part.
|
|
set(QT_CONFIG_STR_OFFSETS "")
|
|
set(QT_CONFIG_STRS "")
|
|
|
|
qt_add_string_to_qconfig_cpp("")
|
|
qt_add_string_to_qconfig_cpp("false")
|
|
qt_add_string_to_qconfig_cpp("bin")
|
|
qt_add_string_to_qconfig_cpp("lib")
|
|
qt_add_string_to_qconfig_cpp(".")
|
|
qt_add_string_to_qconfig_cpp("${QT_QMAKE_TARGET_MKSPEC}")
|
|
qt_add_string_to_qconfig_cpp("${QT_QMAKE_HOST_MKSPEC}")
|
|
|
|
# Save second part.
|
|
set(QT_CONFIG_STR_OFFSETS_SECOND "${QT_CONFIG_STR_OFFSETS}")
|
|
set(QT_CONFIG_STRS_SECOND "${QT_CONFIG_STRS}")
|
|
|
|
configure_file(global/qconfig.cpp.in global/qconfig.cpp @ONLY)
|
|
endfunction()
|