diff options
Diffstat (limited to 'cmake/QtSyncQtHelpers.cmake')
-rw-r--r-- | cmake/QtSyncQtHelpers.cmake | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/cmake/QtSyncQtHelpers.cmake b/cmake/QtSyncQtHelpers.cmake index 40f9cf8e25..fa7e2bf066 100644 --- a/cmake/QtSyncQtHelpers.cmake +++ b/cmake/QtSyncQtHelpers.cmake @@ -206,3 +206,269 @@ function(qt_compute_injection_forwarding_header target) string(APPEND ${arg_OUT_VAR} " ${relpath}:${fwd}") set(${arg_OUT_VAR} ${${arg_OUT_VAR}} PARENT_SCOPE) endfunction() + +# The function generates the Qt module header structure in build directory and creates install +# rules. Apart the lists of header files the function takes into account +# QT_REPO_PUBLIC_NAMESPACE_REGEX cache variable, that can be set by repository in .cmake.conf file. +# The variable tells the syncqt program, what namespaces are treated as public. Symbols in public +# namespaces are considered when generating CaMeL case header files. +function(qt_internal_target_sync_headers target module_headers module_headers_generated) + if(NOT TARGET ${QT_CMAKE_EXPORT_NAMESPACE}::syncqt) + message(FATAL_ERROR "${QT_CMAKE_EXPORT_NAMESPACE}::syncqt is not a target.") + endif() + get_target_property(has_headers ${target} _qt_module_has_headers) + if(NOT has_headers) + return() + endif() + + qt_internal_module_info(module "${target}") + + get_target_property(sync_source_directory ${target} _qt_sync_source_directory) + set(syncqt_timestamp "${CMAKE_CURRENT_BINARY_DIR}/${target}_syncqt_timestamp") + set(syncqt_outputs "${syncqt_timestamp}") + + set(is_interface_lib FALSE) + get_target_property(type ${target} TYPE) + if(type STREQUAL "INTERFACE_LIBRARY") + set(is_interface_lib TRUE) + endif() + + set(version_script_private_content_file "") + if(NOT is_interface_lib) + list(APPEND syncqt_outputs + "${module_build_interface_include_dir}/${module}Version" + "${module_build_interface_include_dir}/qt${module_lower}version.h") + if(TEST_ld_version_script) + set(version_script_private_content_file + "${CMAKE_CURRENT_BINARY_DIR}/${target}.version.private_content") + set(version_script_args + "-versionScript" "${version_script_private_content_file}") + list(APPEND syncqt_outputs "${version_script_private_content_file}") + qt_internal_add_linker_version_script(${target} + PRIVATE_CONTENT_FILE "${version_script_private_content_file}") + endif() + endif() + + # Check for _qt_module_is_3rdparty_header_library flag to detect non-Qt modules and + # indicate this to syncqt. + get_target_property(is_3rd_party_library ${target} _qt_module_is_3rdparty_header_library) + set(non_qt_module_argument "") + if(is_3rd_party_library) + set(non_qt_module_argument "-nonQt") + else() + list(APPEND syncqt_outputs "${module_build_interface_include_dir}/${module}") + if(QT_FEATURE_headersclean) + list(APPEND syncqt_outputs + "${CMAKE_CURRENT_BINARY_DIR}/${module}_header_check_exceptions") + endif() + endif() + + set(is_framework FALSE) + if(NOT is_interface_lib) + get_target_property(is_framework ${target} FRAMEWORK) + if(is_framework) + qt_internal_get_framework_info(fw ${target}) + get_target_property(fw_output_base_dir ${target} LIBRARY_OUTPUT_DIRECTORY) + set(framework_args "-framework" + "-frameworkIncludeDir" "${fw_output_base_dir}/${fw_versioned_header_dir}" + ) + endif() + endif() + + qt_internal_get_qt_all_known_modules(known_modules) + + get_target_property(is_internal_module ${target} _qt_is_internal_module) + set(internal_module_argument "") + if(is_internal_module) + set(internal_module_argument "-internal") + endif() + + get_target_property(qpa_filter_regex ${target} _qt_module_qpa_headers_filter_regex) + get_target_property(private_filter_regex ${target} _qt_module_private_headers_filter_regex) + + # We need to use the real paths since otherwise it may lead to the invalid work of the + # std::filesystem API + get_filename_component(source_dir_real "${sync_source_directory}" REALPATH) + get_filename_component(binary_dir_real "${CMAKE_CURRENT_BINARY_DIR}" REALPATH) + + if(QT_REPO_PUBLIC_NAMESPACE_REGEX) + set(public_namespaces_filter -publicNamespaceFilter "${QT_REPO_PUBLIC_NAMESPACE_REGEX}") + endif() + + if(qpa_filter_regex) + set(qpa_filter_argument + -qpaHeadersFilter "${qpa_filter_regex}" + ) + endif() + + set(common_syncqt_arguments + -module "${module}" + -sourceDir "${source_dir_real}" + -binaryDir "${binary_dir_real}" + -privateHeadersFilter "${private_filter_regex}" + -includeDir "${module_build_interface_include_dir}" + -privateIncludeDir "${module_build_interface_private_include_dir}" + -qpaIncludeDir "${module_build_interface_qpa_include_dir}" + ${qpa_filter_argument} + ${public_namespaces_filter} + ${non_qt_module_argument} + ${internal_module_argument} + ) + + if(QT_INTERNAL_ENABLE_SYNCQT_DEBUG_OUTPUT) + list(APPEND common_syncqt_arguments -debug) + endif() + + + if(is_framework) + list(REMOVE_ITEM module_headers "${CMAKE_CURRENT_BINARY_DIR}/${target}_fake_header.h") + endif() + + # Filter the generated ui_ header files and header files located in the 'doc/' subdirectory. + list(FILTER module_headers EXCLUDE REGEX + "(.+/(ui_)[^/]+\\.h|${CMAKE_CURRENT_SOURCE_DIR}(/.+)?/doc/+\\.h)") + + set(module_headers_rsp "${binary_dir_real}/module_headers") + list(JOIN module_headers "\n" module_headers_string) + qt_configure_file_v2(OUTPUT "${module_headers_rsp}" CONTENT "${module_headers_string}") + + set(module_headers_generated_rsp "${binary_dir_real}/module_headers_generated") + list(JOIN module_headers_generated "\n" module_headers_generated_string) + qt_configure_file_v2(OUTPUT "${module_headers_generated_rsp}" CONTENT + "${module_headers_generated_string}") + + set(syncqt_staging_dir "${module_build_interface_include_dir}/.syncqt_staging") + add_custom_command( + OUTPUT + ${syncqt_outputs} + COMMAND + ${QT_CMAKE_EXPORT_NAMESPACE}::syncqt + ${common_syncqt_arguments} + -headers "@${module_headers_rsp}" + -generatedHeaders "@${module_headers_generated_rsp}" + -stagingDir "${syncqt_staging_dir}" + -knownModules ${known_modules} + ${framework_args} + ${version_script_args} + COMMAND + ${CMAKE_COMMAND} -E touch "${syncqt_timestamp}" + DEPENDS + ${module_headers_rsp} + ${module_headers_generated_rsp} + ${module_headers} + ${QT_CMAKE_EXPORT_NAMESPACE}::syncqt + COMMENT + "Running syncqt.cpp for module: ${module}" + VERBATIM + ) + add_custom_target(${target}_sync_headers + DEPENDS + ${syncqt_outputs} + ) + add_dependencies(sync_headers ${target}_sync_headers) + + # This target is required when building docs, to make all header files and their aliases + # available for qdoc. + # ${target}_sync_headers is added as dependency to make sure that + # ${target}_sync_all_public_headers is running after ${target}_sync_headers, when building docs. + add_custom_target(${target}_sync_all_public_headers + COMMAND + ${QT_CMAKE_EXPORT_NAMESPACE}::syncqt + ${common_syncqt_arguments} + -all + DEPENDS + ${module_headers} + ${QT_CMAKE_EXPORT_NAMESPACE}::syncqt + ${target}_sync_headers + VERBATIM + ) + + if(NOT TARGET sync_all_public_headers) + add_custom_target(sync_all_public_headers) + endif() + add_dependencies(sync_all_public_headers ${target}_sync_all_public_headers) + + if(NOT is_3rd_party_library AND NOT is_framework) + # Install all the CaMeL style aliases of header files from the staging directory in one rule + qt_install(DIRECTORY "${syncqt_staging_dir}/" + DESTINATION "${module_install_interface_include_dir}" + ) + endif() + + if(NOT is_interface_lib) + set_property(TARGET ${target} + APPEND PROPERTY AUTOGEN_TARGET_DEPENDS "${target}_sync_headers") + endif() + add_dependencies(${target} "${target}_sync_headers") + + + get_target_property(private_module_target ${target} _qt_private_module_target_name) + if(private_module_target) + add_dependencies(${private_module_target} "${target}_sync_headers") + endif() + + # Run sync Qt first time at configure step to make all header files available for the code model + # of IDEs. + get_property(synced_modules GLOBAL PROPERTY _qt_synced_modules) + if(NOT "${module}" IN_LIST synced_modules) + message(STATUS "Running syncqt.cpp for module: ${module}") + get_target_property(syncqt_location ${QT_CMAKE_EXPORT_NAMESPACE}::syncqt LOCATION) + execute_process( + COMMAND + ${syncqt_location} + ${common_syncqt_arguments} + -headers "@${module_headers_rsp}" + -generatedHeaders "@${module_headers_generated_rsp}" + -stagingDir "${syncqt_staging_dir}" + -knownModules ${known_modules} + ${framework_args} + RESULT_VARIABLE syncqt_result + OUTPUT_VARIABLE syncqt_output + ERROR_VARIABLE syncqt_output + ) + if(NOT syncqt_result EQUAL 0) + message(FATAL_ERROR + "Unable to execute syncqt.cpp for module ${target}: ${syncqt_output}") + endif() + set_property(GLOBAL APPEND PROPERTY _qt_synced_modules ${module}) + endif() +endfunction() + +function(qt_internal_collect_sync_header_dependencies out_var skip_non_existing) + if(NOT QT_USE_SYNCQT_CPP) + set(${out_var} "" PARENT_SCOPE) + return() + endif() + + list(LENGTH ARGN sync_headers_target_count) + if(sync_headers_target_count EQUAL 0) + message(FATAL_ERROR "Invalid use of qt_internal_collect_sync_header_dependencies," + " dependencies are not specified") + endif() + + set(${out_var} "") + foreach(sync_headers_target IN LISTS ARGN) + set(sync_headers_target "${sync_headers_target}_sync_headers") + if(NOT skip_non_existing OR TARGET ${sync_headers_target}) + list(APPEND ${out_var} ${sync_headers_target}) + endif() + endforeach() + list(REMOVE_DUPLICATES ${out_var}) + + set(${out_var} "${${out_var}}" PARENT_SCOPE) +endfunction() + +function(qt_internal_add_sync_header_dependencies target) + qt_internal_collect_sync_header_dependencies(sync_headers_targets FALSE ${ARGN}) + if(sync_headers_targets) + add_dependencies(${target} ${sync_headers_targets}) + endif() +endfunction() + +function(qt_internal_add_autogen_sync_header_dependencies target) + qt_internal_collect_sync_header_dependencies(sync_headers_targets TRUE ${ARGN}) + foreach(sync_headers_target IN LISTS sync_headers_targets) + set_property(TARGET ${target} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS + "${sync_headers_target}") + endforeach() +endfunction() |