Fix dependencies on sources generated in a different scope to target

In certain situations, a file generated by add_custom_command(OUTPUT)
may be added as a source to a target defined in a different directory
scope. That makes its GENERATED source property not visible to the
target for CMake versions before 3.20. For 3.20 and later, policy
CMP0118 can make the generated state of a source file global, but that
policy is under the control of the user project, since its value at
the end of the target's directory scope is what is used. Therefore we
can force that global visibility using CMP0118. With CMake 3.18 or
later, we can set source properties in arbitrary scopes, which allows
us to force visibility in the scopes we need it. Use that for all
CMake versions 3.18 and later to make the source file properties
visible to the target.

Making the generated state of a source file visible to the target
isn't enough on its own. In the scope that the file is generated,
there must be a target that depends on the file or else CMake won't
set up the necessary dependencies to ensure that generation happens
before the target tries to use it. Add targets in the generated
file's own scope where we currently might not do that.

Task-number: QTBUG-95200
Pick-to: 6.2
Change-Id: Ic1dfca1a193041de01d7f903b79473b9d47f1d1d
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
This commit is contained in:
Craig Scott 2021-09-07 15:51:18 +10:00
parent 6d20630b06
commit 0d4b2355e5

View File

@ -1183,13 +1183,24 @@ function(qt6_extract_metatypes target)
COMMENT "Running moc --collect-json for target ${target}"
)
# We can't rely on policy CMP0118 since user project controls it
set(scope_args)
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
set(scope_args TARGET_DIRECTORY ${target})
endif()
set_source_files_properties(${metatypes_file_gen} ${metatypes_file} ${scope_args}
PROPERTIES GENERATED TRUE
)
# We still need to add this file as a source of the target, otherwise the file
# rule above is not triggered. INTERFACE_SOURCES do not properly register
# as dependencies to build the current target.
# TODO: Can we pass ${metatypes_file} instead of ${metatypes_file_gen} as a source?
# TODO: Do we still need the _gen variant at all?
target_sources(${target} PRIVATE ${metatypes_file_gen})
set_source_files_properties(${metatypes_file} PROPERTIES HEADER_FILE_ONLY TRUE)
set_source_files_properties(${metatypes_file} ${scope_args}
PROPERTIES HEADER_FILE_ONLY TRUE
)
set_target_properties(${target} PROPERTIES
INTERFACE_QT_MODULE_HAS_META_TYPES YES
@ -1459,6 +1470,11 @@ END
target_link_libraries(${target} PRIVATE $<TARGET_OBJECTS:${target}_rc>)
endif()
set(scope_args)
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
set(scope_args TARGET_DIRECTORY ${end_target})
endif()
while(outputs)
list(POP_FRONT cfgs cfg)
list(POP_FRONT outputs output)
@ -1467,6 +1483,10 @@ END
DEPENDS "${input}"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${input}" "${output}"
)
# We can't rely on policy CMP0118 since user project controls it
set_source_files_properties(${output} ${scope_args}
PROPERTIES GENERATED TRUE
)
target_sources(${end_target} PRIVATE "$<$<CONFIG:${cfg}>:${output}>")
endwhile()
endif()
@ -1731,8 +1751,7 @@ function(_qt_internal_process_resource target resourceName)
endif()
return()
endif()
set(generatedBaseName "${resourceName}")
set(generatedResourceFile "${CMAKE_CURRENT_BINARY_DIR}/.rcc/${generatedBaseName}.qrc")
set(generatedResourceFile "${CMAKE_CURRENT_BINARY_DIR}/.rcc/${resourceName}.qrc")
# Generate .qrc file:
@ -1799,7 +1818,7 @@ function(_qt_internal_process_resource target resourceName)
# Set output file name for rcc command
if(isBinary)
set(generatedOutfile "${CMAKE_CURRENT_BINARY_DIR}/${generatedBaseName}.rcc")
set(generatedOutfile "${CMAKE_CURRENT_BINARY_DIR}/${resourceName}.rcc")
if(rcc_DESTINATION)
# Add .rcc suffix if it's not specified by user
get_filename_component(destinationRccExt "${rcc_DESTINATION}" LAST_EXT)
@ -1828,12 +1847,29 @@ function(_qt_internal_process_resource target resourceName)
set(output_targets "")
if(isBinary)
# Add generated .rcc target to 'all' set
add_custom_target(binary_resource_${generatedBaseName} ALL DEPENDS "${generatedOutfile}")
add_custom_target(binary_resource_${resourceName} ALL DEPENDS "${generatedOutfile}")
if(rcc_OUTPUT_TARGETS)
set(${rcc_OUTPUT_TARGETS} "" PARENT_SCOPE)
endif()
else()
set_property(SOURCE "${generatedOutfile}" PROPERTY SKIP_AUTOGEN ON)
# We can't rely on policy CMP0118 since user project controls it.
# We also want SKIP_AUTOGEN known in the target's scope, where we can.
set(scope_args)
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
set(scope_args TARGET_DIRECTORY ${target})
endif()
set_source_files_properties(${generatedOutfile} ${scope_args} PROPERTIES
SKIP_AUTOGEN TRUE
GENERATED TRUE
)
get_target_property(target_source_dir ${target} SOURCE_DIR)
if(NOT target_source_dir STREQUAL CMAKE_CURRENT_SOURCE_DIR)
# We have to create a separate target in this scope that depends on
# the generated file, otherwise the original target won't have the
# required dependencies in place to ensure correct build order.
add_custom_target(${target}_${resourceName} DEPENDS ${generatedOutfile})
add_dependencies(${target} ${target}_${resourceName})
endif()
set_property(TARGET ${target} APPEND PROPERTY _qt_generated_qrc_files "${generatedResourceFile}")
__qt_propagate_generated_resource(${target} ${resourceName} "${generatedOutfile}" output_targets)