summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmake/QtBaseGlobalTargets.cmake1
-rw-r--r--cmake/QtBuild.cmake1
-rw-r--r--cmake/QtPrlHelpers.cmake10
-rw-r--r--cmake/QtStartupHelpers.cmake16
-rw-r--r--src/corelib/CMakeLists.txt13
-rw-r--r--src/corelib/Qt6CoreConfigExtras.cmake.in2
-rw-r--r--src/corelib/Qt6CoreMacros.cmake100
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()