cmake: Ensure Mingw builds pick up and use the WinMain entry point

The cmake code path didn't export QT_NEEDS_QMAIN as a public define
to be inherited by consumers. As a result, the users's main() would
be defined as normal (instead of being named qMain). This in turn
would lead mingw to pick main() as the entrypoint during link time.

We want to go through our WinMain entrypoint (for now), even if
MingGW today has mechanisms for calling the user's main() directly,
as our WinMain uses GetCommandLineW() and as a result prevents
the arguments to main() from being wildcard expanded. and we
want to keep parity between qmake and CMake in how this behaves,
even if we end up changing it in the future.

We follow what qmake does, and expose QT_NEEDS_QMAIN to clients.
With the user's main being then named qMain, mingw will look for
our WinMain.

This in turn leads to the problem of static link ordering, where
adding -lmingw32 as a dependency of the static library target
results in it ending up _after_ the static library during link
time, and the static linker ends up discarding the entry point
library.

To solve this, we split the entry point module into two targets,
one for consumers, and one internal that is the actual static
library. By adding the -lmingw32 dependency to the former target,
we ensure it's added before the static library during linking.

Change-Id: I342c979f56669d5a5a5c237f476556c4e2baf432
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
This commit is contained in:
Tor Arne Vestbø 2020-10-21 15:08:26 +02:00
parent 851e1cb4c4
commit 525372c567

View File

@ -4,32 +4,81 @@ if (NOT WIN32)
return()
endif()
# The EntryPoint package consists of two targets: one for CMake consumption,
# and one internal that produces the static library. Together these form the
# entrypoint module in qmake terms. This split allows us to inject library
# dependencies that need to go _before_ the static library, to work around
# CMake's lack of whole archive.
# ---- The header-only target produces the actual module ----
qt_internal_add_module(EntryPoint
STATIC
INTERNAL_MODULE
NO_SYNC_QT
NO_MODULE_HEADERS
NO_PRIVATE_MODULE
DEFINES
QT_NO_FOREACH
INCLUDE_DIRECTORIES
$<TARGET_PROPERTY:Qt::Core,INTERFACE_INCLUDE_DIRECTORIES>
HEADER_MODULE
INTERNAL_MODULE
NO_SYNC_QT
NO_MODULE_HEADERS
NO_PRIVATE_MODULE
)
if (MSVC)
# Store debug information inside the static lib
qt_internal_replace_compiler_flags(
"/Zi" "/Z7"
CONFIGS DEBUG RELWITHDEBINFO
IN_CURRENT_SCOPE)
# We don't need any include paths or default module defines
set_target_properties(EntryPoint PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ""
INTERFACE_COMPILE_DEFINITIONS ""
)
# And since this module is the one producing the module pri,
# we need to manually tell it that what we're actually doing
# is producing a module that has a static library.
set_target_properties(EntryPoint PROPERTIES
INTERFACE_QT_MODULE_INTERNAL_CONFIG "staticlib"
)
# ---- While the static library target does the work ----
qt_internal_add_cmake_library(EntryPointImplementation STATIC
INCLUDE_DIRECTORIES
$<TARGET_PROPERTY:Qt::Core,INTERFACE_INCLUDE_DIRECTORIES>
)
set_target_properties(EntryPointImplementation PROPERTIES
OUTPUT_NAME "${INSTALL_CMAKE_NAMESPACE}EntryPoint${QT_LIBINFIX}"
ARCHIVE_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}"
)
# ---- Now we're ready to set up the platform specifics ----
if(WIN32)
qt_internal_extend_target(EntryPointImplementation
SOURCES qtentrypoint_win.cpp
LIBRARIES shell32
)
if(MSVC)
# Store debug information inside the static lib
qt_internal_replace_compiler_flags(
"/Zi" "/Z7"
CONFIGS DEBUG RELWITHDEBINFO
IN_CURRENT_SCOPE)
endif()
if(MINGW)
# The mingw32 library needs to come before the entry-point library in the
# linker line, so that the static linker will pick up the WinMain symbol
# from the entry-point library. The logic is duplicated in entrypoint.prf
# on the qmake side.
target_link_libraries(EntryPoint INTERFACE mingw32)
target_compile_definitions(EntryPoint INTERFACE QT_NEEDS_QMAIN)
qt_internal_extend_target(EntryPointImplementation DEFINES QT_NEEDS_QMAIN)
endif()
endif()
qt_internal_extend_target(EntryPoint CONDITION WIN32
SOURCES qtentrypoint_win.cpp
LIBRARIES shell32
)
# ---- Finally, make sure the static library can be consumed by clients -----
# Must be added last, so that any library dependencies added above will
# precede the entrypoint library at link time.
target_link_libraries(EntryPoint INTERFACE EntryPointImplementation)
set(export_name "${INSTALL_CMAKE_NAMESPACE}EntryPointTargets")
qt_install(TARGETS EntryPointImplementation EXPORT ${export_name})
qt_generate_prl_file(EntryPointImplementation "${INSTALL_LIBDIR}")
qt_internal_extend_target(EntryPoint CONDITION MINGW
DEFINES QT_NEEDS_QMAIN
)
# special case end