diff options
-rw-r--r-- | cmake/QtBaseGlobalTargets.cmake | 1 | ||||
-rw-r--r-- | cmake/QtBuild.cmake | 1 | ||||
-rw-r--r-- | cmake/QtPrlHelpers.cmake | 10 | ||||
-rw-r--r-- | cmake/QtStartupHelpers.cmake | 16 | ||||
-rw-r--r-- | src/corelib/CMakeLists.txt | 13 | ||||
-rw-r--r-- | src/corelib/Qt6CoreConfigExtras.cmake.in | 2 | ||||
-rw-r--r-- | src/corelib/Qt6CoreMacros.cmake | 100 |
7 files changed, 135 insertions, 8 deletions
diff --git a/cmake/QtBaseGlobalTargets.cmake b/cmake/QtBaseGlobalTargets.cmake index dae6cb5d13..b317d191b9 100644 --- a/cmake/QtBaseGlobalTargets.cmake +++ b/cmake/QtBaseGlobalTargets.cmake @@ -460,6 +460,7 @@ qt_copy_or_install(FILES cmake/QtSeparateDebugInfo.cmake cmake/QtSetup.cmake cmake/QtSimdHelpers.cmake + cmake/QtStartupHelpers.cmake cmake/QtStandaloneTestsConfig.cmake.in cmake/QtSyncQtHelpers.cmake cmake/QtTargetHelpers.cmake diff --git a/cmake/QtBuild.cmake b/cmake/QtBuild.cmake index e0cad89cb9..bd186c28b9 100644 --- a/cmake/QtBuild.cmake +++ b/cmake/QtBuild.cmake @@ -478,6 +478,7 @@ include(QtRpathHelpers) include(QtSanitizerHelpers) include(QtScopeFinalizerHelpers) include(QtSimdHelpers) +include(QtStartupHelpers) include(QtSyncQtHelpers) include(QtTargetHelpers) include(QtTestHelpers) diff --git a/cmake/QtPrlHelpers.cmake b/cmake/QtPrlHelpers.cmake index 7977afd030..932565f318 100644 --- a/cmake/QtPrlHelpers.cmake +++ b/cmake/QtPrlHelpers.cmake @@ -29,6 +29,16 @@ function(qt_internal_walk_libs target out_var dict_name operation) return() endif() list(APPEND collected ${target}) + + if(target STREQUAL "${QT_CMAKE_EXPORT_NAMESPACE}::Startup") + # We can't (and don't need to) process Startup, because it contains $<TARGET_PROPERTY:prop> + # genexes which get replaced with $<TARGET_PROPERTY:Startup,prop> genexes in the code below + # and that causes 'INTERFACE_LIBRARY targets may only have whitelisted properties.' errors + # with CMake versions equal to or lower than 3.18. These errors are super unintuitive to + # debug because there's no mention that it's happening during a file(GENERATE) call. + return() + endif() + if(NOT TARGET ${dict_name}) add_library(${dict_name} INTERFACE IMPORTED GLOBAL) endif() diff --git a/cmake/QtStartupHelpers.cmake b/cmake/QtStartupHelpers.cmake new file mode 100644 index 0000000000..0e7288e9cf --- /dev/null +++ b/cmake/QtStartupHelpers.cmake @@ -0,0 +1,16 @@ +# Set up some internal requirements for the Startup target. +# +# The creation of the Startup target and its linkage setup happens in 2 places: +# - in src/corelib/CMakeLists.txt when building qtbase. +# - at find_package(Qt6Core) time. +# +# See _qt_internal_setup_startup_target() in Qt6CoreMacros.cmake for the implementation of that. +function(qt_internal_setup_startup_target) + set(dependent_target "Core") + + # On windows, find_package(Qt6Core) should call find_package(Qt6WinMain) so that Startup can + # link against WinMain. + if(WIN32) + qt_record_extra_qt_package_dependency("${dependent_target}" WinMain "${PROJECT_VERSION}") + endif() +endfunction() diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index b6802a6fb5..061032fad7 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -1293,15 +1293,12 @@ endif() qt_internal_apply_gc_binaries_conditional(Core PUBLIC) -if(WIN32) - set(isExe $<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>) - set(isWin32 $<BOOL:$<TARGET_PROPERTY:WIN32_EXECUTABLE>>) - set(isNotExcluded $<NOT:$<BOOL:$<TARGET_PROPERTY:Qt5_NO_LINK_QTMAIN>>>) - set(isPolicyNEW $<TARGET_POLICY:CMP0020>) +# Run some required internal code before creating the Startup target. +qt_internal_setup_startup_target() - target_link_libraries(Core INTERFACE $<$<AND:${isExe},${isWin32},${isNotExcluded},${isPolicyNEW}>:Qt::WinMain>) - qt_record_extra_qt_package_dependency(Core WinMain "${PROJECT_VERSION}") -endif() +# Create the Startup target and set flags on it, so that they are already +# available at Core build time. +_qt_internal_setup_startup_target() # Record darwin minimum deployment target. if(APPLE AND CMAKE_OSX_DEPLOYMENT_TARGET) diff --git a/src/corelib/Qt6CoreConfigExtras.cmake.in b/src/corelib/Qt6CoreConfigExtras.cmake.in index c43e4f772e..6e56a20b29 100644 --- a/src/corelib/Qt6CoreConfigExtras.cmake.in +++ b/src/corelib/Qt6CoreConfigExtras.cmake.in @@ -47,6 +47,8 @@ set(QT@PROJECT_VERSION_MAJOR@_IS_SHARED_LIBS_BUILD "@BUILD_SHARED_LIBS@") get_filename_component(_Qt6CoreConfigDir ${CMAKE_CURRENT_LIST_FILE} PATH) set(_Qt6CTestMacros "${_Qt6CoreConfigDir}/Qt6CTestMacros.cmake") +_qt_internal_setup_startup_target() + if(ANDROID_PLATFORM) include("${CMAKE_CURRENT_LIST_DIR}/@QT_CMAKE_EXPORT_NAMESPACE@AndroidMacros.cmake") endif() diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake index b1c9661dca..a9f76cc99e 100644 --- a/src/corelib/Qt6CoreMacros.cmake +++ b/src/corelib/Qt6CoreMacros.cmake @@ -1317,3 +1317,103 @@ function(_qt_internal_apply_strict_cpp target) endif() endif() endfunction() + +# Sets up auto-linkage of platform-specific entry points. +# +# See qt_internal_setup_startup_target() in qtbase/cmake/QtStartupHelpers.cmake for the internal +# implementation counterpart. +# +# A project that uses Qt can opt-out of this auto-linking behavior by either setting the +# QT_NO_LINK_QTMAIN property to TRUE on a target, or by setting the +# QT_NO_LINK_QTMAIN variable to TRUE before the find_package(Qt6) call. +# +# QT_NO_LINK_QTMAIN replaces the old Qt5_NO_LINK_QTMAIN name for both the property and variable +#name. +# +# This function is called by Qt6CoreConfigExtras.cmake at find_package(Qt6Core) time. +# The reason the linkage is done at find_package() time instead of Qt build time is to allow +# opting out via a variable. This ensures compatibility with Qt5 behavior. +# If it was done at build time, opt-out could only be achieved via the property. +function(_qt_internal_setup_startup_target) + set(target "${QT_CMAKE_EXPORT_NAMESPACE}::Startup") + set(dependent_target "${QT_CMAKE_EXPORT_NAMESPACE}::Core") + + # Get actual Core target name. + get_target_property(dependent_aliased_target "${dependent_target}" ALIASED_TARGET) + if(dependent_aliased_target) + set(dependent_target "${dependent_aliased_target}") + endif() + + # Check if Core is being built as part of current CMake invocation. + # If it is, that means the Core target scope is global and the same scope should be set for the + # to-be-created Startup target, to avoid creating 100s of local IMPORTED Startup targets + # when building with -DBUILD_TESTING=ON and -DBUILD_EXAMPLES=ON due to multiple + # find_package(Qt6Core) calls. + get_target_property(core_imported "${dependent_target}" IMPORTED) + set(create_global "") + if(NOT core_imported) + set(create_global "GLOBAL") + endif() + + # Create Startup only if it's not available in the current scope. + # Guards against multiple find_package(Qt6Core) calls. + if(NOT TARGET "${target}") + add_library("${target}" INTERFACE IMPORTED ${create_global}) + endif() + + # Allow variable opt-out. Has to be after target creation, because Core always links against + # Startup. + if(QT_NO_LINK_QTMAIN) + return() + endif() + + # find_package(Qt6Core) can be called multiple times, but we only want to set the flags once. + set(initialized_prop "_qt_startup_target_initialized") + get_target_property(initialized "${target}" "${initialized_prop}") + if(initialized) + return() + else() + set_target_properties("${target}" PROPERTIES "${initialized_prop}" TRUE) + endif() + + # On Windows this enables automatic linkage to WinMain. + # On iOS this enables automatic passing of a linker flag that will change the default + # entry point of the linked executable. + set(isExe "$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>") + set(isNotExcluded "$<NOT:$<BOOL:$<TARGET_PROPERTY:QT_NO_LINK_QTMAIN>>>") + if(WIN32) + set(isWin32 "$<BOOL:$<TARGET_PROPERTY:WIN32_EXECUTABLE>>") + set(isPolicyNEW "$<TARGET_POLICY:CMP0020>") + set(finalGenex "$<$<AND:${isExe},${isWin32},${isNotExcluded},${isPolicyNEW}>:Qt::WinMain>") + + # Use set_target_properties instead of target_link_libraries because the latter has some + # weird additional behavior of checking which project the target belongs to, and might + # error out when called multiple times from different scopes. + set_target_properties("${target}" PROPERTIES INTERFACE_LINK_LIBRARIES "${finalGenex}") + elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS") + set(flag "-Wl,-e,_qt_main_wrapper") + set(finalGenex "$<$<AND:${isExe},${isNotExcluded}>:${flag}>") + + set_target_properties("${target}" PROPERTIES INTERFACE_LINK_OPTIONS "${finalGenex}") + endif() + + # Set up the dependency on Startup for the local Core target, if it hasn't been set yet. + set(initialized_prop "_qt_core_startup_dependency_initialized") + get_target_property(initialized "${dependent_target}" "${initialized_prop}") + if(initialized) + get_target_property(thelibs "${dependent_target}" INTERFACE_LINK_LIBRARIES) + return() + else() + set_target_properties("${dependent_target}" PROPERTIES "${initialized_prop}" TRUE) + + # Export the initialized property on Core, to ensure that Core links against Startup + # only once in a non-qtbase project. + if(NOT core_imported) + set_property(TARGET "${dependent_target}" APPEND PROPERTY + EXPORT_PROPERTIES "${initialized_prop}") + endif() + endif() + + target_link_libraries("${dependent_target}" INTERFACE "${target}") + get_target_property(thelibs "${dependent_target}" INTERFACE_LINK_LIBRARIES) +endfunction() |