diff options
Diffstat (limited to 'cmake/QtTargetHelpers.cmake')
-rw-r--r-- | cmake/QtTargetHelpers.cmake | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/cmake/QtTargetHelpers.cmake b/cmake/QtTargetHelpers.cmake new file mode 100644 index 0000000000..c79ce47363 --- /dev/null +++ b/cmake/QtTargetHelpers.cmake @@ -0,0 +1,335 @@ +# This function can be used to add sources/libraries/etc. to the specified CMake target +# if the provided CONDITION evaluates to true. +function(qt_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 "qt_extend_target" "HEADER_MODULE" "PRECOMPILED_HEADER" + "CONDITION;${__default_public_args};${__default_private_args};${__default_private_module_args};COMPILE_FLAGS;NO_PCH_SOURCES" ${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("qt_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() + + get_target_property(target_type ${target} TYPE) + set(is_library FALSE) + if (${target_type} STREQUAL "STATIC_LIBRARY" OR ${target_type} STREQUAL "SHARED_LIBRARY") + set(is_library TRUE) + endif() + foreach(lib ${arg_PUBLIC_LIBRARIES} ${arg_LIBRARIES}) + # Automatically generate PCH for 'target' using dependencies + # if 'target' is a library/module! + if (${is_library}) + qt_update_precompiled_header_with_library("${target}" "${lib}") + endif() + + string(REGEX REPLACE "_nolink$" "" base_lib "${lib}") + if(NOT base_lib STREQUAL lib) + qt_create_nolink_target("${base_lib}" ${target}) + 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_property (TARGET "${target}" APPEND PROPERTY + AUTOMOC_MOC_OPTIONS "${arg_MOC_OPTIONS}" + ) + 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 ${arg_PRIVATE_MODULE_INTERFACE}) + 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}) + + qt_update_precompiled_header("${target}" "${arg_PRECOMPILED_HEADER}") + qt_update_ignore_pch_source("${target}" "${arg_NO_PCH_SOURCES}") + ## Ignore objective-c files for PCH (not supported atm) + qt_ignore_pch_obj_c_sources("${target}" "${arg_SOURCES}") + + else() + if(QT_CMAKE_DEBUG_EXTEND_TARGET) + message("qt_extend_target(${target} CONDITION ${arg_CONDITION} ...): Skipped") + endif() + 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() + +# 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() + +function(qt_get_cmake_configurations out_var) + set(possible_configs "${CMAKE_BUILD_TYPE}") + if(CMAKE_CONFIGURATION_TYPES) + set(possible_configs "${CMAKE_CONFIGURATION_TYPES}") + endif() + set(${out_var} "${possible_configs}" PARENT_SCOPE) +endfunction() + +function(qt_clone_property_for_configs target property configs) + get_target_property(value "${target}" "${property}") + foreach(config ${configs}) + string(TOUPPER "${config}" upper_config) + set_property(TARGET "${target}" PROPERTY "${property}_${upper_config}" "${value}") + endforeach() +endfunction() + +function(qt_handle_multi_config_output_dirs target) + qt_get_cmake_configurations(possible_configs) + qt_clone_property_for_configs(${target} LIBRARY_OUTPUT_DIRECTORY "${possible_configs}") + qt_clone_property_for_configs(${target} RUNTIME_OUTPUT_DIRECTORY "${possible_configs}") + qt_clone_property_for_configs(${target} ARCHIVE_OUTPUT_DIRECTORY "${possible_configs}") +endfunction() + +# Set target properties that are the same for all modules, plugins, executables +# and 3rdparty libraries. +function(qt_set_common_target_properties target) + if(FEATURE_static_runtime) + if(MSVC) + set_property(TARGET ${target} PROPERTY + MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") + elseif(MINGW) + target_link_options(${target} INTERFACE "LINKER:-static") + endif() + endif() +endfunction() + +# Set common, informational target properties. +# +# On Windows, these properties are used to generate the version information resource. +function(qt_set_target_info_properties target) + cmake_parse_arguments(arg "" "${__default_target_info_args}" "" ${ARGN}) + if("${arg_TARGET_VERSION}" STREQUAL "") + set(arg_TARGET_VERSION "${PROJECT_VERSION}.0") + endif() + if("${arg_TARGET_PRODUCT}" STREQUAL "") + set(arg_TARGET_PRODUCT "Qt6") + endif() + if("${arg_TARGET_DESCRIPTION}" STREQUAL "") + set(arg_TARGET_DESCRIPTION "C++ Application Development Framework") + endif() + if("${arg_TARGET_COMPANY}" STREQUAL "") + set(arg_TARGET_COMPANY "The Qt Company Ltd.") + endif() + if("${arg_TARGET_COPYRIGHT}" STREQUAL "") + set(arg_TARGET_COPYRIGHT "Copyright (C) 2020 The Qt Company Ltd.") + endif() + set_target_properties(${target} PROPERTIES + QT_TARGET_VERSION "${arg_TARGET_VERSION}" + QT_TARGET_COMPANY_NAME "${arg_TARGET_COMPANY}" + QT_TARGET_DESCRIPTION "${arg_TARGET_DESCRIPTION}" + QT_TARGET_COPYRIGHT "${arg_TARGET_COPYRIGHT}" + QT_TARGET_PRODUCT_NAME "${arg_TARGET_PRODUCT}") +endfunction() + +# Uses the QT_DELAYED_TARGET_* property values to set the final QT_TARGET_* properties. +# Needed when doing executable finalization at the end of a subdirectory scope +# (aka scope finalization). +function(qt_internal_set_target_info_properties_from_delayed_properties target) + set(args "") + foreach(prop ${__default_target_info_args}) + get_target_property(prop_value "${target}" "QT_DELAYED_${prop}") + list(APPEND args "${prop}" "${prop_value}") + endforeach() + qt_set_target_info_properties(${target} ${args}) +endfunction() + +# Updates the QT_DELAYED_ properties with values from the QT_ variants, in case if they were +# set in-between a qt_add_* call and before scope finalization. +function(qt_internal_update_delayed_target_info_properties target) + foreach(prop ${__default_target_info_args}) + get_target_property(prop_value "${target}" "QT_${prop}") + get_target_property(delayed_prop_value ${target} "QT_DELAYED_${prop}") + set(final_value "${delayed_prop_value}") + if(prop_value) + set(final_value "${prop_value}") + endif() + set_target_properties(${target} PROPERTIES "QT_DELAYED_${prop}" "${final_value}") + endforeach() +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 "qt_internal_add_plugin called without setting either TYPE or ${name}.") + endif() + set(${result_var} "${default}" PARENT_SCOPE) + else() + set(${result_var} "${dir}" PARENT_SCOPE) + endif() +endfunction() + +function(qt_internal_apply_win_prefix_and_suffix target) + if(WIN32) + # Table of prefix / suffixes for MSVC libraries as qmake expects them to be created. + # static - Qt6EdidSupport.lib (platform support libraries / or static QtCore, etc) + # shared - Qt6Core.dll + # shared import library - Qt6Core.lib + # module aka Qt plugin - qwindows.dll + # module import library - qwindows.lib + # + # The CMake defaults are fine for us. + + # Table of prefix / suffixes for MinGW libraries as qmake expects them to be created. + # static - libQt6EdidSupport.a (platform support libraries / or static QtCore, etc) + # shared - Qt6Core.dll + # shared import library - libQt6Core.a + # module aka Qt plugin - qwindows.dll + # module import library - libqwindows.a + # + # CMake for Windows-GNU platforms defaults the prefix to "lib". + # CMake for Windows-GNU platforms defaults the import suffix to ".dll.a". + # These CMake defaults are not ok for us. + + # This should cover both MINGW with GCC and CLANG. + if(NOT MSVC) + set_property(TARGET "${target}" PROPERTY IMPORT_SUFFIX ".a") + + get_target_property(target_type ${target} TYPE) + if(target_type STREQUAL "STATIC_LIBRARY") + set_property(TARGET "${target}" PROPERTY PREFIX "lib") + else() + set_property(TARGET "${target}" PROPERTY PREFIX "") + set_property(TARGET "${target}" PROPERTY IMPORT_PREFIX "lib") + endif() + endif() + endif() +endfunction() + +function(qt_internal_strip_target_directory_scope_token target out_var) + # In CMake versions earlier than CMake 3.18, a subdirectory scope id is appended to the + # target name if the target is referenced in a target_link_libraries command from a + # different directory scope than where the target was created. + # Strip it. + # + # For informational purposes, in CMake 3.18, the target name looks as follows: + # ::@(0x5604cb3f6b50);Threads::Threads;::@ + # This case doesn't have to be stripped (at least for now), because when we iterate over + # link libraries, the tokens appear as separate target names. + # + # Example: Threads::Threads::@<0x5604cb3f6b50> + # Output: Threads::Threads + string(REGEX REPLACE "::@<.+>$" "" target "${target}") + set("${out_var}" "${target}" 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_is_versionless_target "TRUE") + set_property(TARGET "${target}Versionless" + APPEND PROPERTY EXPORT_PROPERTIES _qt_is_versionless_target) + + qt_install(TARGETS "${target}Versionless" EXPORT ${export_name}) + endforeach() + qt_install(EXPORT ${export_name} NAMESPACE Qt:: DESTINATION "${__arg_CONFIG_INSTALL_DIR}") +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() |