561fc8107f
User projects can set the QT_PROMOTE_TO_GLOBAL_TARGETS variable to true so that the various imported targets created by find_package(Qt6) are promoted to global targets. This would allow a project to find Qt packages in a subdirectory scope while using those Qt targets from a different scope. E.g. it fixes errors like CMake Error at CMakeLists.txt:5 (target_link_libraries): Error evaluating generator expression: $<TARGET_OBJECTS:Qt6::Widgets_resources_1> Objects of target "Qt6::Widgets_resources_1" referenced but no such target exists. when trying to use a static Qt from a sibling scope. Various 3rd party dependency targets (like Atomic or ZLIB) are not made global due to limitations in CMake, but as long as those targets are not mentioned directly, it shouldn't cause issues. The targets are made global in the generated QtFooAdditionalTargetInfo.cmake file. To ensure that resource object libraries promoted, the generation of the file has to be done at the end of the defining scope where qt_internal_export_additional_targets_file is called, which is achieved with a deferred finalizer. Replaced all occurrences of target promotion with a helper function which allows tracing of all promoted targets by specifying --log-level=debug to CMake. Pick-to: 6.2 Fixes: QTBUG-92878 Change-Id: Ic4ec03b0bc383d7e591a58c520c3974fbea746d2 Reviewed-by: Alexey Edelev <alexey.edelev@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
102 lines
4.5 KiB
CMake
102 lines
4.5 KiB
CMake
# Add a finalizer function for the current CMake list file.
|
|
# It will be processed just before leaving the current source directory scope.
|
|
#
|
|
# When using CMake 3.18 or lower:
|
|
# You may add up to nine arguments that are passed to the finalizer.
|
|
# A finalizer that is registered with qt_add_list_file_finalizer(foo bar baz)
|
|
# will be called with nine arguments: foo(bar baz IGNORE IGNORE IGNORE...),
|
|
# because CMake's handling of empty list elements is a cruel joke.
|
|
# For CMake < 3.18 the function qt_watch_current_list_dir must know about the finalizer.
|
|
#
|
|
# When using CMake 3.19 or higher, no more INGORE parameters are passed. Instead we
|
|
# use cmake_language(DEFER CALL) and pass arguments as usual.
|
|
# qt_watch_current_list_dir also doesn't need to know about the finalizer
|
|
function(qt_add_list_file_finalizer func)
|
|
set(use_cmake_defer_call TRUE)
|
|
if(CMAKE_VERSION VERSION_LESS "3.19.0")
|
|
set(use_cmake_defer_call FALSE)
|
|
endif()
|
|
|
|
if(use_cmake_defer_call)
|
|
cmake_language(EVAL CODE "cmake_language(DEFER CALL \"${func}\" ${ARGN}) ")
|
|
else()
|
|
set_property(GLOBAL APPEND
|
|
PROPERTY QT_LIST_FILE_FINALIZER_FILES "${CMAKE_CURRENT_LIST_FILE}")
|
|
set_property(GLOBAL APPEND
|
|
PROPERTY QT_LIST_FILE_FINALIZER_FUNCS ${func})
|
|
foreach(i RANGE 1 9)
|
|
set(arg "${ARGV${i}}")
|
|
if(i GREATER_EQUAL ARGC OR "${arg}" STREQUAL "")
|
|
set(arg "IGNORE")
|
|
endif()
|
|
set_property(GLOBAL APPEND
|
|
PROPERTY QT_LIST_FILE_FINALIZER_ARGV${i} "${arg}")
|
|
endforeach()
|
|
endif()
|
|
endfunction()
|
|
|
|
# Watcher function for the variable CMAKE_CURRENT_LIST_DIR.
|
|
# This is the driver of the finalizer facility.
|
|
function(qt_watch_current_list_dir variable access value current_list_file stack)
|
|
if(NOT access STREQUAL "MODIFIED_ACCESS")
|
|
# We are only interested in modifications of CMAKE_CURRENT_LIST_DIR.
|
|
return()
|
|
endif()
|
|
list(GET stack -1 stack_top)
|
|
if(stack_top STREQUAL current_list_file)
|
|
# If the top of the stack equals the current list file then
|
|
# we're entering a file. We're not interested in this case.
|
|
return()
|
|
endif()
|
|
get_property(files GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FILES)
|
|
if(NOT files)
|
|
return()
|
|
endif()
|
|
get_property(funcs GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FUNCS)
|
|
foreach(i RANGE 1 9)
|
|
get_property(args${i} GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_ARGV${i})
|
|
endforeach()
|
|
list(LENGTH files n)
|
|
set(i 0)
|
|
while(i LESS n)
|
|
list(GET files ${i} file)
|
|
if(file STREQUAL stack_top)
|
|
list(GET funcs ${i} func)
|
|
foreach(k RANGE 1 9)
|
|
list(GET args${k} ${i} a${k})
|
|
endforeach()
|
|
# We've found a file we're looking for. Call the finalizer.
|
|
if(${CMAKE_VERSION} VERSION_LESS "3.18.0")
|
|
# Make finalizer known functions here:
|
|
if(func STREQUAL "qt_finalize_module")
|
|
qt_finalize_module(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
|
|
elseif(func STREQUAL "qt_finalize_plugin")
|
|
qt_finalize_plugin(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
|
|
elseif(func STREQUAL "qt_internal_finalize_app")
|
|
qt_internal_finalize_app(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
|
|
elseif(func STREQUAL "qt_internal_export_additional_targets_file_finalizer")
|
|
qt_internal_export_additional_targets_file_finalizer(
|
|
${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
|
|
else()
|
|
message(FATAL_ERROR "qt_watch_current_list_dir doesn't know about ${func}. Consider adding it.")
|
|
endif()
|
|
else()
|
|
cmake_language(CALL ${func} ${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
|
|
endif()
|
|
list(REMOVE_AT files ${i})
|
|
list(REMOVE_AT funcs ${i})
|
|
foreach(k RANGE 1 9)
|
|
list(REMOVE_AT args${k} ${i})
|
|
endforeach()
|
|
math(EXPR n "${n} - 1")
|
|
else()
|
|
math(EXPR i "${i} + 1")
|
|
endif()
|
|
endwhile()
|
|
set_property(GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FILES ${files})
|
|
set_property(GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FUNCS ${funcs})
|
|
foreach(i RANGE 1 9)
|
|
set_property(GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_ARGV${i} "${args${i}}")
|
|
endforeach()
|
|
endfunction()
|