Refactor Metatypes dependency propagation

Every metatypes.json files is now added as an INTERFACE source file to a
target. This enables us later to correctly collect all the
metatypes.json files from dependent targets. This information is also
correctly exported via export()/install().

To avoid the metatypes.json appearing in every target's source list,
the file path is wrapped in a generator expression which will only be
evaluated when the consuming target has the property
QT_CONSUMES_METATYPES set to true. At the moment this is limited to
targets which need to interact with qmltyperegistrar.

Change-Id: I0ffebcd069a923383f7ed11cde2c94ecf2fb13f3
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
This commit is contained in:
Leander Beernaert 2020-02-07 14:12:27 +01:00
parent 360d9fba23
commit c431e2d33c
4 changed files with 49 additions and 139 deletions

View File

@ -1862,8 +1862,6 @@ set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})")
set(args INSTALL_DIR "${metatypes_install_dir}") set(args INSTALL_DIR "${metatypes_install_dir}")
endif() endif()
qt6_generate_meta_types_json_file(${target} ${args}) qt6_generate_meta_types_json_file(${target} ${args})
get_target_property(QT_MODULE_META_TYPES_FILE ${target} INTERFACE_QT_META_TYPES_INSTALL_FILE)
get_target_property(QT_MODULE_META_TYPES_DEP_FILE ${target} INTERFACE_QT_META_TYPES_INSTALL_DEP_FILE)
endif() endif()
configure_package_config_file( configure_package_config_file(
"${QT_CMAKE_DIR}/QtModuleConfig.cmake.in" "${QT_CMAKE_DIR}/QtModuleConfig.cmake.in"

View File

@ -45,27 +45,6 @@ if(NOT _qt_module_target_type STREQUAL "INTERFACE_LIBRARY")
endif() endif()
endif() endif()
# Apply meta types properties
if (@QT_MODULE_HAS_META_TYPES_FILE@)
if (NOT QT_NO_CREATE_TARGETS)
set_target_properties("@INSTALL_CMAKE_NAMESPACE@::@target@" PROPERTIES
INTERFACE_QT_MODULE_HAS_META_TYPES TRUE
INTERFACE_QT_META_TYPES_INSTALL_FILE "@QT_MODULE_META_TYPES_FILE@"
INTERFACE_QT_META_TYPES_INSTALL_DEP_FILE "@QT_MODULE_META_TYPES_DEP_FILE@"
)
endif()
if (NOT QT_NO_CREATE_VERSIONLESS_TARGETS)
get_target_property(is_alias_target "Qt::@target@" ALIASED_TARGET)
if (NOT is_alias_target)
set_target_properties("Qt::@target@" PROPERTIES
INTERFACE_QT_MODULE_HAS_META_TYPES TRUE
INTERFACE_QT_META_TYPES_INSTALL_FILE "@QT_MODULE_META_TYPES_FILE@"
INTERFACE_QT_META_TYPES_INSTALL_DEP_FILE "@QT_MODULE_META_TYPES_DEP_FILE@"
)
endif()
endif()
endif()
# Load Module's BuildIntenals should any exist # Load Module's BuildIntenals should any exist
if (@INSTALL_CMAKE_NAMESPACE@BuildInternals_DIR AND if (@INSTALL_CMAKE_NAMESPACE@BuildInternals_DIR AND

View File

@ -321,6 +321,15 @@ if(NOT BUILD_SHARED_LIBS)
) )
endif() endif()
# Core_qobject is never exported so we need to duplicate the metatypes file
# interface on Core
get_target_property(core_qobject_metatypes_file_genex_build Core_qobject QT_MODULE_META_TYPES_FILE_GENEX_BUILD)
get_target_property(core_qobject_metatypes_file_genex_install Core_qobject QT_MODULE_META_TYPES_FILE_GENEX_INSTALL)
target_sources(Core INTERFACE
${core_qobject_metatypes_file_genex_build}
${core_qobject_metatypes_file_genex_install}
)
set_property(TARGET Core APPEND PROPERTY set_property(TARGET Core APPEND PROPERTY
PUBLIC_HEADER "${CMAKE_CURRENT_BINARY_DIR}/global/qconfig.h") PUBLIC_HEADER "${CMAKE_CURRENT_BINARY_DIR}/global/qconfig.h")
set_property(TARGET Core APPEND PROPERTY set_property(TARGET Core APPEND PROPERTY

View File

@ -595,102 +595,7 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
endfunction() endfunction()
endif() endif()
# Generate metatypes dependency file. This function extracts the list of
# metatypes files as well as the dependency file from the direct library
# dependencies of a target via generator expressions.
# Parameters:
# dep_file: Location where to generate the dependency file for build time
# dependencies.
# dep_file_install: Location where to generate the dependency file which
# is expected to be installed.
function(qt6_generate_meta_types_dep_file target dep_file dep_file_install)
# Due to generator expressions it is not possible to recursively evaluate
# the LINK_LIBRARIES of target. Therefore we generate a dependency file for
# every module with metatypes which can be evaluated at build time.
# When generating this file we need to take into account that there are two
# levels at which dependencies can be expressed: build and install.
# Build dependencies refer to targets which are being built along side the
# original target. These targets' install dependencies are not available
# at this point in time. We set a special property on these targets that's
# only available at build time.
# Install dependencies refer to targets which are found via a find_package()
# call.
# Both install and build targets have the
# INTERFACE_QT_META_TYPES_INSTALL_[DEP_FILE|FILE]. When building the target,
# INTERFACE_QT_META_TYPES_INSTALL_... refer to the expected install
# directory to be appended to CMAKE_INSTALL_PREFIX.
# Only build target have the INTERFACE_QT_META_TYPES_[DEP_FILE|FILE] which
# point to the files that have been produced during build time.
# Finally, to make sure the targets actually have a metatypes files, we
# check if they have the INTERFACE_QT_MODULE_HAS_META_TYPES property.
#
# Note: All properties start with INTERFACE_ since it is the only way to
# set properties on interface targets that get generated in the
# QtModuleConfig.in
#
get_target_property(link_dependencies ${target} LINK_LIBRARIES)
set(prop_dep "INTERFACE_QT_META_TYPES_BUILD_DEP_FILE")
set(prop_file "INTERFACE_QT_META_TYPES_BUILD_FILE")
set(prop_file_install "INTERFACE_QT_META_TYPES_INSTALL_FILE")
set(prop_dep_install "INTERFACE_QT_META_TYPES_INSTALL_DEP_FILE")
set(prop_is_local "INTERFACE_QT_MODULE_META_TYPES_FROM_BUILD")
set(prop_has_metatypes "INTERFACE_QT_MODULE_HAS_META_TYPES")
set(gen_exp "")
set(gen_exp_install "")
foreach(dep IN LISTS link_dependencies)
# Skip over any flags starting with -, like -framework or -lboo.
if("${dep}" MATCHES "^-")
continue()
endif()
# replace LINK_ONLY with true, or we will get an error evaluating that
# generator expression
string(REPLACE "$<LINK_ONLY:" "$<1:" genex_target "$<GENEX_EVAL:${dep}>")
string(REPLACE "$<TARGET_OBJECTS:" "$<1:" genex_target "${genex_target}")
set(genex_check_is_local
"$<TARGET_GENEX_EVAL:${genex_target},$<TARGET_PROPERTY:${genex_target},${prop_is_local}>>"
)
set(genex_is_target "$<TARGET_EXISTS:$<IF:$<BOOL:${genex_target}>,${genex_target},-NOTFOUND>>")
set(genex_has_metatypes
"$<TARGET_GENEX_EVAL:${genex_target},$<TARGET_PROPERTY:${genex_target},${prop_has_metatypes}>>"
)
set(genex_get_metatypes
"$<TARGET_GENEX_EVAL:${genex_target},$<TARGET_PROPERTY:${genex_target},${prop_file}>>"
)
set(genex_get_metatypes_dep
"$<TARGET_GENEX_EVAL:${genex_target},$<TARGET_PROPERTY:${genex_target},${prop_dep}>>"
)
set(genex_get_metatypes_install
"$<TARGET_GENEX_EVAL:${genex_target},$<TARGET_PROPERTY:${genex_target},${prop_file_install}>>"
)
set(genex_get_metatypes_install_dep
"$<TARGET_GENEX_EVAL:${genex_target},$<TARGET_PROPERTY:${genex_target},${prop_dep_install}>>"
)
set(get_local_or_install
"$<IF:$<BOOL:${genex_check_is_local}>,${genex_get_metatypes}=${genex_get_metatypes_dep},${genex_get_metatypes_install}=${genex_get_metatypes_install_dep}>"
)
list(APPEND gen_exp
"$<$<AND:$<BOOL:${genex_target}>,$<BOOL:${genex_has_metatypes}>>:${get_local_or_install}>"
)
list(APPEND gen_exp_install
"$<$<AND:$<BOOL:${genex_target}>,$<BOOL:${genex_get_metatypes_install}>>:${genex_get_metatypes_install}=${genex_get_metatypes_install_dep}>"
)
endforeach()
file(GENERATE
OUTPUT "${dep_file}"
CONTENT "$<JOIN:$<GENEX_EVAL:${gen_exp}>,\n>"
)
file(GENERATE
OUTPUT "${dep_file_install}"
CONTENT "$<JOIN:$<GENEX_EVAL:${gen_exp_install}>,\n>"
)
endfunction()
#
# Generate Qt metatypes.json for a target. By default we check whether AUTOMOC # Generate Qt metatypes.json for a target. By default we check whether AUTOMOC
# has been enabled and we extract the information from that target. Should you # has been enabled and we extract the information from that target. Should you
# not wish to use automoc you need to pass in all the generated json files via the # not wish to use automoc you need to pass in all the generated json files via the
@ -808,36 +713,62 @@ function(qt6_generate_meta_types_json_file target)
set(metatypes_file_name "qt6${target_lowercase}_metatypes.json") set(metatypes_file_name "qt6${target_lowercase}_metatypes.json")
set(metatypes_file "${target_binary_dir}/meta_types/${metatypes_file_name}") set(metatypes_file "${target_binary_dir}/meta_types/${metatypes_file_name}")
set(metatypes_file_gen "${target_binary_dir}/meta_types/${metatypes_file_name}.gen")
set(metatypes_dep_file_name "qt6${target_lowercase}_metatypes_dep.txt") set(metatypes_dep_file_name "qt6${target_lowercase}_metatypes_dep.txt")
set(metatypes_dep_file "${target_binary_dir}/meta_types/${metatypes_dep_file_name}") set(metatypes_dep_file "${target_binary_dir}/meta_types/${metatypes_dep_file_name}")
add_custom_command(OUTPUT ${metatypes_file} # Due to generated source file dependency rules being tied to the directory
# scope in which they are created it is not possible for other targets which
# are defined in a separate scope to see these rules. This leads to failures
# in locating the generated source files.
# To work around this we write a dummy file to disk to make sure targets
# which link against the current target do not produce the error. This dummy
# file is then replaced with the contents of the generated file during
# build.
if (NOT EXISTS ${metatypes_file})
file(MAKE_DIRECTORY "${target_binary_dir}/meta_types")
file(TOUCH ${metatypes_file})
endif()
add_custom_command(OUTPUT ${metatypes_file_gen} ${metatypes_file}
DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::moc ${automoc_dependencies} ${manual_dependencies} DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::moc ${automoc_dependencies} ${manual_dependencies}
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::moc COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::moc
-o ${metatypes_file} -o ${metatypes_file_gen}
--collect-json ${automoc_args} ${manual_args} --collect-json ${automoc_args} ${manual_args}
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${metatypes_file_gen}
${metatypes_file}
COMMENT "Runing automoc with --collect-json" COMMENT "Runing automoc with --collect-json"
) )
target_sources(${target} PRIVATE ${metatypes_file}) # We still need to add this file as a source of Core, otherwise the file
# rule above is not triggered. INTERFACE_SOURCES do not properly register
# as dependencies to build the current target.
target_sources(${target} PRIVATE ${metatypes_file_gen})
set(metatypes_file_genex_build)
set(metatypes_file_genex_install)
if (arg_COPY_OVER_INSTALL)
set(metatypes_file_genex_build
"$<BUILD_INTERFACE:$<$<BOOL:$<TARGET_PROPERTY:QT_CONSUMES_METATYPES>>:${arg_INSTALL_DIR}/${metatypes_file_name}>>"
)
else()
set(metatypes_file_genex_build
"$<BUILD_INTERFACE:$<$<BOOL:$<TARGET_PROPERTY:QT_CONSUMES_METATYPES>>:${metatypes_file}>>"
)
set(metatypes_file_genex_install
"$<INSTALL_INTERFACE:$<$<BOOL:$<TARGET_PROPERTY:QT_CONSUMES_METATYPES>>:$<INSTALL_PREFIX>/${arg_INSTALL_DIR}/${metatypes_file_name}>>"
)
endif()
set_source_files_properties(${metatypes_file} PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties(${metatypes_file} PROPERTIES HEADER_FILE_ONLY TRUE)
# Set the required properties. See documentation of
# qt6_generate_meta_types_dep_file()
set_target_properties(${target} PROPERTIES set_target_properties(${target} PROPERTIES
INTERFACE_QT_MODULE_HAS_META_TYPES YES INTERFACE_QT_MODULE_HAS_META_TYPES YES
INTERFACE_QT_MODULE_META_TYPES_FROM_BUILD YES INTERFACE_QT_MODULE_META_TYPES_FROM_BUILD YES
INTERFACE_QT_META_TYPES_BUILD_FILE ${metatypes_file} INTERFACE_QT_META_TYPES_BUILD_FILE ${metatypes_file}
INTERFACE_QT_META_TYPES_BUILD_DEP_FILE ${metatypes_dep_file} QT_MODULE_META_TYPES_FILE_GENEX_BUILD "${metatypes_file_genex_build}"
INTERFACE_QT_META_TYPES_INSTALL_FILE "${arg_INSTALL_DIR}/${metatypes_file_name}" QT_MODULE_META_TYPES_FILE_GENEX_INSTALL "${metatypes_file_genex_install}"
INTERFACE_QT_META_TYPES_INSTALL_DEP_FILE "${arg_INSTALL_DIR}/${metatypes_dep_file_name}"
) )
target_sources(${target} INTERFACE ${metatypes_file_genex_build} ${metatypes_file_genex_install})
qt6_generate_meta_types_dep_file(${target}
"${metatypes_dep_file}"
"${metatypes_dep_file}.install"
)
if (arg_COPY_OVER_INSTALL) if (arg_COPY_OVER_INSTALL)
get_target_property(target_type ${target} TYPE) get_target_property(target_type ${target} TYPE)
@ -845,13 +776,10 @@ function(qt6_generate_meta_types_json_file target)
COMMAND ${CMAKE_COMMAND} -E copy_if_different COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${metatypes_file}" "${metatypes_file}"
"${arg_INSTALL_DIR}/${metatypes_file_name}" "${arg_INSTALL_DIR}/${metatypes_file_name}"
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${metatypes_dep_file}.install"
"${arg_INSTALL_DIR}/${metatypes_dep_file_name}"
) )
if (target_type STREQUAL "OBJECT_LIBRARY") if (target_type STREQUAL "OBJECT_LIBRARY")
add_custom_target(${target}_metatypes_copy add_custom_target(${target}_metatypes_copy
DEPENDS "${metatypes_file}" "${metatypes_dep_file}" DEPENDS "${metatypes_file}"
${command_args} ${command_args}
) )
add_dependencies(${target} ${target}_metatypes_copy) add_dependencies(${target} ${target}_metatypes_copy)
@ -864,10 +792,6 @@ function(qt6_generate_meta_types_json_file target)
install(FILES "${metatypes_file}" install(FILES "${metatypes_file}"
DESTINATION "${arg_INSTALL_DIR}" DESTINATION "${arg_INSTALL_DIR}"
) )
install(FILES "${metatypes_dep_file}.install"
DESTINATION "${arg_INSTALL_DIR}"
RENAME "${metatypes_dep_file_name}"
)
endif() endif()
endfunction() endfunction()