[CMAKE] Don't re-archive import libraries

Instead create an IMPORTED library from the output of dlltool.
This prevents binutils 2.40+ nested archive crash (bug #31614):
This commit is contained in:
Timo Kreuzer
2026-01-09 13:45:12 +02:00
parent 07de64139a
commit 62cc9c498e
6 changed files with 40 additions and 37 deletions

View File

@@ -204,8 +204,8 @@ add_cd_file(TARGET msvcrt DESTINATION reactos/system32 FOR all)
# Let consumers of msvcrt have the right defines
target_compile_definitions(libmsvcrt INTERFACE _DLL __USE_CRTIMP)
# Embed msvcrtex into libmsvcrt
target_sources(libmsvcrt PRIVATE $<TARGET_OBJECTS:msvcrtex>)
# Link libmsvcrt to msvcrtex
target_link_libraries(libmsvcrt INTERFACE msvcrtex)
# Link GCC stack protector lib
if (STACK_PROTECTOR)

View File

@@ -42,7 +42,7 @@ target_link_libraries(ucrtbase
)
# Implicitly link to vcstartup
target_link_libraries(libucrtbase vcstartup)
target_link_libraries(libucrtbase INTERFACE vcstartup)
if(MSVC)
target_link_libraries(ucrtbase runtmchk)

View File

@@ -25,7 +25,7 @@ add_asm_files(ntoskrnl_asm ${NTOSKRNL_ASM_SOURCE})
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
# Clang optimises strcmp calls to memcmp.
target_sources(libntoskrnl PRIVATE $<TARGET_OBJECTS:memcmp>)
target_link_libraries(libntoskrnl INTERFACE memcmp)
endif()
if((CMAKE_C_COMPILER_ID STREQUAL "Clang") OR (CMAKE_C_COMPILER_ID STREQUAL "GNU"))

View File

@@ -443,48 +443,46 @@ function(generate_import_lib _libname _dllname _spec_file __version_arg __dbg_ar
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_spec_file} native-spec2def)
# With this, we let DLLTOOL create an import library
# Note: previously we re-archived the import library created by dlltool into
# a thin archive ('ar crT'). This is broken with binutils 2.40+ (bug #31614)
# and leads to a linker crash. The new method of using an IMPORTED library
# avoids this. It does no longer allow to embed new object files into the
# import libraries, but this is replaced by linking the additinal libraries
# to the import library.
set(LIBRARY_PRIVATE_DIR ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_libname}.dir)
add_custom_command(
OUTPUT ${LIBRARY_PRIVATE_DIR}/${_libname}.a
# ar just puts stuff into the archive, without looking twice. Just delete the lib, we're going to rebuild it anyway
COMMAND ${CMAKE_COMMAND} -E rm -f $<TARGET_FILE:${_libname}>
COMMAND ${CMAKE_COMMAND} -E rm -f ${LIBRARY_PRIVATE_DIR}/${_libname}.a
COMMAND ${CMAKE_DLLTOOL} --def ${CMAKE_CURRENT_BINARY_DIR}/${_libname}_implib.def --kill-at --output-lib=${_libname}.a -t ${_libname}
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${_libname}_implib.def
WORKING_DIRECTORY ${LIBRARY_PRIVATE_DIR})
# We create a static library with the importlib thus created as object. AR will extract the obj files and archive it again as a thin lib
set_source_files_properties(
${LIBRARY_PRIVATE_DIR}/${_libname}.a
PROPERTIES
EXTERNAL_OBJECT TRUE)
_add_library(${_libname} STATIC EXCLUDE_FROM_ALL
${LIBRARY_PRIVATE_DIR}/${_libname}.a)
set_target_properties(${_libname}
PROPERTIES
LINKER_LANGUAGE "C"
PREFIX "")
# Create a custom target for the import library generation
add_custom_target(${_libname}_implib_target DEPENDS ${LIBRARY_PRIVATE_DIR}/${_libname}.a)
# Create an IMPORTED library that references the dlltool output
_add_library(${_libname} STATIC IMPORTED GLOBAL)
set_target_properties(${_libname} PROPERTIES IMPORTED_LOCATION ${LIBRARY_PRIVATE_DIR}/${_libname}.a)
add_dependencies(${_libname} ${_libname}_implib_target)
# Do the same with delay-import libs
set(LIBRARY_PRIVATE_DIR ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_libname}_delayed.dir)
add_custom_command(
OUTPUT ${LIBRARY_PRIVATE_DIR}/${_libname}_delayed.a
# ar just puts stuff into the archive, without looking twice. Just delete the lib, we're going to rebuild it anyway
COMMAND ${CMAKE_COMMAND} -E rm -f $<TARGET_FILE:${_libname}_delayed>
COMMAND ${CMAKE_COMMAND} -E rm -f ${LIBRARY_PRIVATE_DIR}/${_libname}_delayed.a
COMMAND ${CMAKE_DLLTOOL} --def ${CMAKE_CURRENT_BINARY_DIR}/${_libname}_implib.def --kill-at --output-delaylib=${_libname}_delayed.a -t ${_libname}_delayed
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${_libname}_implib.def
WORKING_DIRECTORY ${LIBRARY_PRIVATE_DIR})
# We create a static library with the importlib thus created. AR will extract the obj files and archive it again as a thin lib
set_source_files_properties(
${LIBRARY_PRIVATE_DIR}/${_libname}_delayed.a
PROPERTIES
EXTERNAL_OBJECT TRUE)
_add_library(${_libname}_delayed STATIC EXCLUDE_FROM_ALL
${LIBRARY_PRIVATE_DIR}/${_libname}_delayed.a)
set_target_properties(${_libname}_delayed
PROPERTIES
LINKER_LANGUAGE "C"
PREFIX "")
# Create a custom target for the delay-import library generation
add_custom_target(${_libname}_delayed_implib_target DEPENDS ${LIBRARY_PRIVATE_DIR}/${_libname}_delayed.a)
# Create an IMPORTED library for delay-import
_add_library(${_libname}_delayed STATIC IMPORTED GLOBAL)
set_target_properties(${_libname}_delayed PROPERTIES IMPORTED_LOCATION ${LIBRARY_PRIVATE_DIR}/${_libname}_delayed.a)
add_dependencies(${_libname}_delayed ${_libname}_delayed_implib_target)
endfunction()
function(spec2def _dllname _spec_file)

View File

@@ -90,9 +90,12 @@ endif()
set_source_files_properties(${MSVCRTEX_ASM_SOURCE} PROPERTIES COMPILE_DEFINITIONS "_DLL;_MSVCRTEX_")
add_asm_files(msvcrtex_asm ${MSVCRTEX_ASM_SOURCE})
add_library(msvcrtex OBJECT ${MSVCRTEX_SOURCE} ${msvcrtex_asm})
add_library(msvcrtex STATIC ${MSVCRTEX_SOURCE} ${msvcrtex_asm})
target_compile_definitions(msvcrtex PRIVATE _DLL _MSVCRTEX_)
# msvcrtex depends on msvcrt and kernel32
target_link_libraries(msvcrtex INTERFACE libmsvcrt libkernel32)
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
target_compile_options(msvcrtex PRIVATE $<$<COMPILE_LANGUAGE:C>:-Wno-main>)
if(LTCG)
@@ -105,7 +108,7 @@ set_source_files_properties(startup/crtexe.c
startup/wcrtexe.c PROPERTIES COMPILE_DEFINITIONS _M_CEE_PURE)
if(NOT MSVC)
target_link_libraries(msvcrtex oldnames)
target_link_libraries(msvcrtex INTERFACE oldnames)
endif()
add_dependencies(msvcrtex psdk asm)

View File

@@ -5,17 +5,19 @@ if(NOT MSVC)
add_custom_command(
OUTPUT ${LIBRARY_PRIVATE_DIR}/oldnames.a
# ar just puts stuff into the archive, without looking twice. Just delete the lib, we're going to rebuild it anyway
COMMAND ${CMAKE_COMMAND} -E rm -f $<TARGET_FILE:oldnames>
COMMAND ${CMAKE_COMMAND} -E rm -f ${LIBRARY_PRIVATE_DIR}/oldnames.a
COMMAND ${CMAKE_DLLTOOL} --def ${CMAKE_CURRENT_SOURCE_DIR}/moldname-msvcrt.def --kill-at --output-lib=oldnames.a -t oldnames
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/moldname-msvcrt.def
WORKING_DIRECTORY ${LIBRARY_PRIVATE_DIR})
set_source_files_properties(
${LIBRARY_PRIVATE_DIR}/oldnames.a
PROPERTIES
EXTERNAL_OBJECT TRUE)
_add_library(oldnames STATIC EXCLUDE_FROM_ALL ${LIBRARY_PRIVATE_DIR}/oldnames.a)
set_target_properties(oldnames PROPERTIES LINKER_LANGUAGE "C")
# Create a custom target for the import library generation
add_custom_target(oldnames_target DEPENDS ${LIBRARY_PRIVATE_DIR}/oldnames.a)
# Create an IMPORTED library that references the dlltool output
_add_library(oldnames STATIC IMPORTED GLOBAL)
set_target_properties(oldnames PROPERTIES IMPORTED_LOCATION ${LIBRARY_PRIVATE_DIR}/oldnames.a)
add_dependencies(oldnames oldnames_target)
set_target_properties(oldnames PROPERTIES LINKER_LANGUAGE "C")
else()
add_asm_files(oldnames_asm oldnames-common.S oldnames-msvcrt.S)
add_library(oldnames ${oldnames_asm})