diff options
Diffstat (limited to 'cmake/QtBuild.cmake')
-rw-r--r-- | cmake/QtBuild.cmake | 1202 |
1 files changed, 1202 insertions, 0 deletions
diff --git a/cmake/QtBuild.cmake b/cmake/QtBuild.cmake new file mode 100644 index 0000000000..84769a4eb8 --- /dev/null +++ b/cmake/QtBuild.cmake @@ -0,0 +1,1202 @@ +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]") + +set(INSTALL_CMAKE_NAMESPACE "Qt${PROJECT_VERSION_MAJOR}" CACHE STRING "CMake namespace [Qt${PROJECT_VERSION_MAJOR}]") + +set(QT_CMAKE_EXPORT_NAMESPACE "Qt${PROJECT_VERSION_MAJOR}" CACHE STRING "CMake namespace used when exporting targets [Qt${PROJECT_VERSION_MAJOR}]") +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. +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_DEFAULT_PLATFORM_DEFINITION_DIR mkspecs/win32-msvc) + elseif(CLANG) + set(QT_DEFAULT_PLATFORM_DEFINITION_DIR mkspecs/win32-clang) + endif() +elseif(LINUX) + if(GCC) + set(QT_DEFAULT_PLATFORM_DEFINITION_DIR mkspecs/linux-g++) + elseif(CLANG) + set(QT_DEFAULT_PLATFORM_DEFINITION_DIR mkspecs/linux-clang) + endif() +elseif(APPLE) + set(QT_DEFAULT_PLATFORM_DEFINITION_DIR mkspecs/macx-clang) +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() + +macro(qt_internal_set_known_qt_modules) + set(KNOWN_QT_MODULES ${ARGN} CACHE INTERNAL "Known Qt modules" FORCE) +endmacro() + +# Reset: +qt_internal_set_known_qt_modules("") + +# 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() + + +# Functions and macros: + +# 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) + 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() + + set(nolink_target "${target}_nolink") + if(NOT TARGET "${nolink_target}") + add_library("${nolink_target}" INTERFACE IMPORTED) + 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>) + 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() + + get_target_property(mocPath "${QT_CMAKE_EXPORT_NAMESPACE}::moc" LOCATION) + get_filename_component(binDirectory "${mocPath}" DIRECTORY) + # We could put this into the cache, but on the other hand there's no real need to + # pollute the app's cache with this. For the first qtbase build, the variable is + # set in global scope. + set(QT_SYNCQT "${binDirectory}/syncqt.pl" CACHE FILEPATH "syncqt script") +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 (GCC OR CLANG) + if(APPLE) + set(no_undefined_flag "-Wl,-undefined,error") + elseif(LINUX) + 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) + if(APPLE) + set(gc_sections_flag "-Wl,-dead_strip") + elseif(LINUX OR BSD OR SOLARIS OR WIN32) + 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 "Qt5Core" (based on major Qt version) +# * foo_upper with the value "CORE" +# * foo_lower with the value "core" +# * foo_include_dir with the module's include directory in the binary tree +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) + set("${result}_upper" "${upper}" PARENT_SCOPE) + set("${result}_lower" "${lower}" PARENT_SCOPE) + set("${result}_include_dir" "${PROJECT_BINARY_DIR}/include/${module}" 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") +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) + +# This function checks which autotools should be used: AUTOMOC/UIC/RCC +function(qt_autogen_tools target) + qt_parse_all_arguments(arg "qt_autogen_tools" "" "" "${__default_private_args}" ${ARGN}) + + set_property(TARGET "${target}" PROPERTY INTERFACE_QT_MAJOR_VERSION ${PROJECT_VERSION_MAJOR}) + set_property(TARGET "${target}" APPEND PROPERTY + COMPATIBLE_INTERFACE_STRING QT_MAJOR_VERSION + ) + + list(APPEND autogen_tools "moc" "uic" "rcc") + if (arg_DISABLE_AUTOGEN_TOOLS) + foreach(disable_tool ${arg_DISABLE_AUTOGEN_TOOLS}) + list(REMOVE_ITEM autogen_tools "${disable_tool}") + endforeach() + endif() + + foreach(autogen_tool ${autogen_tools}) + string(TOUPPER "${autogen_tool}" captitalAutogenTool) + + set_target_properties("${target}" + PROPERTIES + AUTO${captitalAutogenTool} ON + AUTO${captitalAutogenTool}_EXECUTABLE "$<TARGET_FILE:Qt::${autogen_tool}>") + set_property(TARGET ${target} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS Qt::${autogen_tool}) + endforeach() + + set_directory_properties(PROPERTIES + QT_VERSION_MAJOR ${PROJECT_VERSION_MAJOR} + QT_VERSION_MINOR ${PROJECT_VERSION_MINOR}) +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) + if (NOT TARGET "${target}") + message(FATAL_ERROR "Trying to extend non-existing target \"${target}\".") + endif() + qt_parse_all_arguments(arg "extend_target" "" "" + "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}") + endif() + endforeach() + + 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() + target_include_directories("${target}" PUBLIC ${arg_PUBLIC_INCLUDE_DIRECTORIES} PRIVATE ${arg_INCLUDE_DIRECTORIES}) + target_compile_definitions("${target}" PUBLIC ${arg_PUBLIC_DEFINES} PRIVATE ${arg_DEFINES}) + target_link_libraries("${target}" PUBLIC ${arg_PUBLIC_LIBRARIES} PRIVATE ${arg_LIBRARIES}) + target_compile_options("${target}" PUBLIC ${arg_PUBLIC_COMPILE_OPTIONS} PRIVATE ${arg_COMPILE_OPTIONS}) + target_link_options("${target}" PUBLIC ${arg_PUBLIC_LINK_OPTIONS} PRIVATE ${arg_LINK_OPTIONS}) + set_target_properties("${target}" PROPERTIES AUTOMOC_MOC_OPTIONS "${arg_MOC_OPTIONS}") + 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() +endfunction() + + +function(qt_install_injections module) + 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 + separate_arguments(injections UNIX_COMMAND "${injections}") + foreach(injection ${injections}) + string(REPLACE ":" ";" injection ${injection}) + list(GET injection 0 file) + list(GET injection 1 destination) + string(REGEX REPLACE "^\\^" "" destination "${destination}") + list(REMOVE_AT injection 0 1) + set(fwd_hdrs ${injection}) + get_filename_component(destinationdir ${destination} DIRECTORY) + get_filename_component(destinationname ${destination} NAME) + install(FILES ${PROJECT_BINARY_DIR}/${file} DESTINATION ${INSTALL_INCLUDEDIR}/${module}/${destinationdir} RENAME ${destinationname} OPTIONAL) + foreach(fwd_hdr ${fwd_hdrs}) + file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${fwd_hdr}" CONTENT "#include \"${destinationname}\"\n") + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${fwd_hdr}" DESTINATION ${INSTALL_INCLUDEDIR}/${module}/${destinationdir} 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() + + +# 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" "CONFIG_MODULE_NAME" + "${__default_private_args};${__default_public_args}" ${ARGN}) + + if(NOT DEFINED arg_CONFIG_MODULE_NAME) + set(arg_CONFIG_MODULE_NAME "${module_lower}") + endif() + + qt_internal_set_known_qt_modules("${KNOWN_QT_MODULES}" "${target}") + + ### Define Targets: + if(${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: + set(target_private "${target}Private") + add_library("${target_private}" INTERFACE) + qt_internal_add_target_aliases("${target_private}") + + # Module headers: + if(${arg_NO_MODULE_HEADERS}) + set_target_properties("${target}" PROPERTIES MODULE_HAS_HEADERS OFF) + else() + qt_ensure_sync_qt() + execute_process(COMMAND "${HOST_PERL}" -w "${QT_SYNCQT}" -quiet -module "${module}" -version "${PROJECT_VERSION}" -outdir "${PROJECT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}") + + set_target_properties("${target}" PROPERTIES 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}") + qt_install_injections("${module}" ${module_headers_injections}) + endif() + + set_target_properties("${target}" PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${INSTALL_LIBDIR}" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${INSTALL_BINDIR}" + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + OUTPUT_NAME "${INSTALL_CMAKE_NAMESPACE}${target}") + + qt_internal_library_deprecation_level(deprecation_define) + + qt_autogen_tools("${target}" + DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} + ) + + extend_target("${target}" + SOURCES ${arg_SOURCES} + PUBLIC_INCLUDE_DIRECTORIES + $<BUILD_INTERFACE:${module_include_dir}> + $<INSTALL_INTERFACE:include/${module}> + ${arg_PUBLIC_INCLUDE_DIRECTORIES} + INCLUDE_DIRECTORIES + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}" + $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include> + "${module_include_dir}/${PROJECT_VERSION}" + "${module_include_dir}/${PROJECT_VERSION}/${module}" + ${arg_INCLUDE_DIRECTORIES} + PUBLIC_DEFINES + ${arg_PUBLIC_DEFINES} + QT_${module_upper}_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_upper}_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} + 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} + ) + + 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() + + install(TARGETS "${target}" "${target_private}" EXPORT "${INSTALL_CMAKE_NAMESPACE}${target}Targets" + LIBRARY DESTINATION ${INSTALL_LIBDIR} + ARCHIVE DESTINATION ${INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${INSTALL_INCLUDEDIR}/${module} + PRIVATE_HEADER DESTINATION ${INSTALL_INCLUDEDIR}/${module}/${PROJECT_VERSION}/${module}/private + ) + + set(config_install_dir "${INSTALL_LIBDIR}/cmake/${INSTALL_CMAKE_NAMESPACE}${target}") + install(EXPORT "${INSTALL_CMAKE_NAMESPACE}${target}Targets" NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}:: DESTINATION ${config_install_dir}) + + 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" + "${CMAKE_CURRENT_BINARY_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake" + @ONLY) + list(APPEND extra_cmake_files "${CMAKE_CURRENT_BINARY_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake") + list(APPEND extra_cmake_includes "${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake") + endif() + + ### 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}") + + # When a public module depends on private, also make its private depend on the other's private + set(qt_libs_private "") + foreach(it ${KNOWN_QT_MODULES}) + list(FIND arg_LIBRARIES "Qt::${it}Private" pos) + if(pos GREATER -1) + list(APPEND qt_libs_private "Qt::${it}Private") + endif() + endforeach() + + target_link_libraries("${target_private}" INTERFACE "${target}" "${qt_libs_private}") + target_include_directories("${target_private}" INTERFACE + $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}> + $<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}> + $<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}/${module}> + $<INSTALL_INTERFACE:include/${module}/${PROJECT_VERSION}> + $<INSTALL_INTERFACE:include/${module}/${PROJECT_VERSION}/${module}> + ) + + set(target_deps) + foreach(lib IN LISTS arg_PUBLIC_LIBRARIES qt_libs_private) + if ("${lib}" MATCHES "^Qt::(.*)") + set(lib "${CMAKE_MATCH_1}") + if (lib STREQUAL Platform OR lib STREQUAL GlobalConfig) + list(APPEND target_deps "Qt5\;${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() + + configure_package_config_file( + "${QT_CMAKE_DIR}/QtModuleConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" + INSTALL_DESTINATION "${config_install_dir}" + ) + write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion + ) + + install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" + ${extra_cmake_files} + DESTINATION "${config_install_dir}" + COMPONENT Devel + ) +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() + + +# 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_parse_all_arguments(arg "add_qt_plugin" "STATIC" + "TYPE;OUTPUT_DIRECTORY;INSTALL_DIRECTORY;ARCHIVE_INSTALL_DIRECTORY" + "${__default_private_args};${__default_public_args}" ${ARGN}) + + qt_internal_check_directory_or_type(OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" "${arg_TYPE}" + "${CMAKE_BINARY_DIR}/${INSTALL_PLUGINSDIR}/${arg_TYPE}" output_directory) + qt_internal_check_directory_or_type(INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}" "${arg_TYPE}" + "${INSTALL_PLUGINSDIR}/${arg_TYPE}" install_directory) + qt_internal_check_directory_or_type(ARCHIVE_INSTALL_DIRECTORY + "${arg_ARCHIVE_INSTALL_DIRECTORY}" "${arg_TYPE}" + "${INSTALL_LIBDIR}/${arg_TYPE}" archive_install_directory) + + if(arg_STATIC) + add_library("${target}" STATIC) + else() + add_library("${target}") + 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_internal_library_deprecation_level(deprecation_define) + + qt_autogen_tools("${target}" + DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} + ) + + set(static_plugin_define "") + if (arg_STATIC OR NOT QT_BUILD_SHARED_LIBS) + set(static_plugin_define "QT_STATICPLUGIN") + endif() + + extend_target("${target}" + SOURCES ${arg_SOURCES} + INCLUDE_DIRECTORIES + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}" + ${arg_INCLUDE_DIRECTORIES} + PUBLIC_INCLUDE_DIRECTORIES ${arg_PUBLIC_INCLUDE_DIRECTORIES} + LIBRARIES ${arg_LIBRARIES} + PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES} + 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_upper}_LIB ### FIXME: use QT_BUILD_ADDON for Add-ons or remove if we don't have add-ons anymore + "${deprecation_define}" + "${static_plugin_define}" + QT_PLUGIN + PUBLIC_DEFINES + QT_${module_upper}_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} + ) + + install(TARGETS "${target}" EXPORT "${target}Targets" + LIBRARY DESTINATION "${install_directory}" + ARCHIVE DESTINATION "${archive_install_directory}") + install(EXPORT "${target}Targets" NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}:: DESTINATION ${INSTALL_LIBDIR}/cmake) + + ### 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() + + +# 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" "GUI;BOOTSTRAP;NO_INSTALL" "OUTPUT_DIRECTORY;INSTALL_DIRECTORY" "EXE_FLAGS;${__default_private_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("${name}" + DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} + ) + + set(extra_libraries "") + if(NOT arg_BOOTSTRAP) + set(extra_libraries "Qt::Core") + endif() + + extend_target("${name}" + SOURCES ${arg_SOURCES} + INCLUDE_DIRECTORIES + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}" + ${arg_INCLUDE_DIRECTORIES} + DEFINES ${arg_DEFINES} + LIBRARIES ${arg_LIBRARIES} ${extra_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} + ) + set_target_properties("${name}" PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" + WIN32_EXECUTABLE "${arg_GUI}" + MACOSX_BUNDLE "${arg_GUI}" + ) + + if(NOT arg_NO_INSTALL) + 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" "" "${__default_private_args}" ${ARGN}) + set(path "${CMAKE_CURRENT_BINARY_DIR}") + + add_qt_executable("${name}" + NO_INSTALL + OUTPUT_DIRECTORY "${path}" + SOURCES "${arg_SOURCES}" + INCLUDE_DIRECTORIES + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}" + "${arg_INCLUDE_DIRECTORIES}" + DEFINES "${arg_DEFINES}" + LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::Core ${QT_CMAKE_EXPORT_NAMESPACE}::Test ${arg_LIBRARIES} + COMPILE_OPTIONS ${arg_COMPILE_OPTIONS} + LINK_OPTIONS ${arg_LINK_OPTIONS} + MOC_OPTIONS ${arg_MOC_OPTIONS} + DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} + ) + + add_test(NAME "${name}" COMMAND "${name}" WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + + set_tests_properties("${name}" PROPERTIES RUN_SERIAL "${arg_RUN_SERIAL}") + set_property(TEST "${name}" APPEND PROPERTY ENVIRONMENT "PATH=${path}${QT_PATH_SEPARATOR}${CMAKE_CURRENT_BINARY_DIR}${QT_PATH_SEPARATOR}$ENV{PATH}") + set_property(TEST "${name}" APPEND PROPERTY ENVIRONMENT "QT_PLUGIN_PATH=${PROJECT_BINARY_DIR}/${INSTALL_PLUGINSDIR}") +endfunction() + + +# This function creates an executable for use as helper program with tests. Some +# tests launch separate programs to test certainly input/output behavior. +function(add_qt_test_helper name) + add_qt_executable("${name}" NO_INSTALL OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.." ${ARGN}) +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) + set01(_build_tools "x${HOST_QT_TOOLS_DIRECTORY}" STREQUAL "x") + if (NOT _build_tools) + message("Searching for ${name}.") + find_program("_PROG_${name}" "${name}" PATHS "${HOST_QT_TOOLS_DIRECTORY}" NO_DEFAULT_PATH) + if (_PROG_${name} STREQUAL "_PROG_${name}-NOTFOUND") + message(FATAL_ERROR "The name \"${name}\" was not found in the " + "HOST_QT_TOOLS_DIRECTORY (\"${HOST_QT_TOOLS_DIRECTORY}\").") + else() + message(STATUS "${name} was found at ${_PROG_${name}}.") + add_executable("${name}" IMPORTED GLOBAL) + set_target_properties("${name}" PROPERTIES IMPORTED_LOCATION "${_PROG_${name}}") + qt_internal_add_target_aliases("${name}") + endif() + return() + endif() + + qt_parse_all_arguments(arg "add_qt_tool" "BOOTSTRAP;NO_INSTALL" "" "${__default_private_args}" ${ARGN}) + + set(disable_autogen_tools "${arg_DISABLE_AUTOGEN_TOOLS}") + 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() + + set(bootstrap "") + if(arg_BOOTSTRAP) + set(bootstrap BOOTSTRAP) + endif() + + set(no_install "") + if(arg_NO_INSTALL) + set(no_install NO_INSTALL) + endif() + + add_qt_executable("${name}" OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${INSTALL_BINDIR}" + ${bootstrap} + ${no_install} + SOURCES ${arg_SOURCES} + INCLUDE_DIRECTORIES + ${arg_INCLUDE_DIRECTORIES} + DEFINES ${arg_DEFINES} + LIBRARIES ${corelib} ${arg_LIBRARIES} + 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}") + + if(NOT arg_NO_INSTALL) + install(TARGETS "${name}" EXPORT "Qt${PROJECT_VERSION_MAJOR}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() + + + +function(add_qt_resource target resourceName) + qt_parse_all_arguments(rcc "add_qt_resource" "" "PREFIX;LANG;BASE" "FILES" ${ARGN}) + + # Generate .qrc file: + + # <RCC><qresource ...> + set(qrcContents "<RCC>\n <qresource") + if (rcc_PREFIX) + string(APPEND qrcContents " prefix=\"${rcc_PREFIX}\"") + endif() + if (rcc_LANG) + string(APPEND qrcContents " lang=\"${rcc_LANG}\"") + endif() + string(APPEND qrcContents ">\n") + + foreach(file ${rcc_FILES}) + if(rcc_BASE) + set(based_file "${rcc_BASE}/${file}") + else() + set(based_file "${file}") + endif() + get_property(alias SOURCE ${based_file} PROPERTY alias) + if (NOT alias) + set(alias "${file}") + endif() + ### FIXME: escape file paths to be XML conform + # <file ...>...</file> + string(APPEND qrcContents " <file alias=\"${alias}\">") + string(APPEND qrcContents "${CMAKE_CURRENT_SOURCE_DIR}/${based_file}</file>\n") + endforeach() + + # </qresource></RCC> + string(APPEND qrcContents " </qresource>\n</RCC>\n") + + set(generatedResourceFile "${CMAKE_CURRENT_BINARY_DIR}/${resourceName}.qrc") + file(GENERATE OUTPUT "${generatedResourceFile}" CONTENT "${qrcContents}") + + # Process .qrc file: + + set(generatedSourceCode "${CMAKE_CURRENT_BINARY_DIR}/qrc_${resourceName}.cpp") + add_custom_command(OUTPUT "${generatedSourceCode}" + COMMAND "${QT_CMAKE_EXPORT_NAMESPACE}::rcc" + ARGS --name "${resourceName}" + --output "${generatedSourceCode}" "${generatedResourceFile}" + DEPENDS ${files} + COMMENT "RCC ${resourceName}" + VERBATIM) + target_sources(${target} PRIVATE "${generatedSourceCode}") +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}") + else() + if(QT_CMAKE_DEBUG_EXTEND_TARGET) + message("add_qt_simd_part(${target} SIMD ${arg_SIMD} ...): Skipped") + endif() + endif() +endfunction() + +# From Qt5CoreMacros +# 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() + + + set(header_file "${CMAKE_CURRENT_BINARY_DIR}/${file_name}.h") + set(source_file "${CMAKE_CURRENT_BINARY_DIR}/${file_name}.cpp") + + add_custom_command(OUTPUT "${header_file}" "${source_file}" + COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::qdbusxml2cpp ${arg_FLAGS} "${option}" "${header_file}:${source_file}" "${infile}" + DEPENDS "${infile}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + VERBATIM) + + target_sources("${target}" PRIVATE "${header_file}" "${source_file}") +endfunction() + + +function(qt_generate_forwarding_headers target) + qt_parse_all_arguments(arg "qt_generate_forwarding_headers" + "PRIVATE" "SOURCE;DESTINATION" "CLASSES" ${ARGN}) + qt_internal_module_info(module "${target}") + + if (NOT arg_DESTINATION) + get_filename_component(arg_DESTINATION "${arg_SOURCE}" NAME) + endif() + + if (arg_PRIVATE) + set(main_fwd "${module_include_dir}/${PROJECT_VERSION}/${module}/private/${arg_DESTINATION}") + else() + set(main_fwd "${module_include_dir}/${arg_DESTINATION}") + endif() + + get_filename_component(main_fwd_dir "${main_fwd}" DIRECTORY) + file(RELATIVE_PATH relpath "${main_fwd_dir}" "${CMAKE_CURRENT_BINARY_DIR}/${arg_SOURCE}") + set(main_contents "#include \"${relpath}\"") + file(GENERATE OUTPUT "${main_fwd}" CONTENT "${main_contents}") + + foreach(class_fwd ${arg_CLASSES}) + set(class_fwd_contents "#include \"${fwd_hdr}\"") + message("Generating forwarding header: ${class_fwd} -> ${relpath}.") + file(GENERATE OUTPUT "${module_include_dir}/${class_fwd}" CONTENT "${class_fwd_contents}") + endforeach() +endfunction() + + +function(add_qt_docs qdocFile) + # TODO +endfunction() |