From 62cc9c498eb5ce2cb80310fe9f6ecf7603d74aca Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Fri, 9 Jan 2026 13:45:12 +0200 Subject: [PATCH] [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): --- dll/win32/msvcrt/CMakeLists.txt | 4 +-- dll/win32/ucrtbase/CMakeLists.txt | 2 +- ntoskrnl/CMakeLists.txt | 2 +- sdk/cmake/gcc.cmake | 46 +++++++++++++++---------------- sdk/lib/crt/msvcrtex.cmake | 7 +++-- sdk/lib/crt/oldnames.cmake | 16 ++++++----- 6 files changed, 40 insertions(+), 37 deletions(-) diff --git a/dll/win32/msvcrt/CMakeLists.txt b/dll/win32/msvcrt/CMakeLists.txt index e247db75933..d2d052397dd 100644 --- a/dll/win32/msvcrt/CMakeLists.txt +++ b/dll/win32/msvcrt/CMakeLists.txt @@ -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 $) +# Link libmsvcrt to msvcrtex +target_link_libraries(libmsvcrt INTERFACE msvcrtex) # Link GCC stack protector lib if (STACK_PROTECTOR) diff --git a/dll/win32/ucrtbase/CMakeLists.txt b/dll/win32/ucrtbase/CMakeLists.txt index 749c863a747..598198a4c87 100644 --- a/dll/win32/ucrtbase/CMakeLists.txt +++ b/dll/win32/ucrtbase/CMakeLists.txt @@ -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) diff --git a/ntoskrnl/CMakeLists.txt b/ntoskrnl/CMakeLists.txt index c583ac4b32f..d33ff76dcc0 100644 --- a/ntoskrnl/CMakeLists.txt +++ b/ntoskrnl/CMakeLists.txt @@ -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_link_libraries(libntoskrnl INTERFACE memcmp) endif() if((CMAKE_C_COMPILER_ID STREQUAL "Clang") OR (CMAKE_C_COMPILER_ID STREQUAL "GNU")) diff --git a/sdk/cmake/gcc.cmake b/sdk/cmake/gcc.cmake index fe4d304cc66..5e9d5d42214 100644 --- a/sdk/cmake/gcc.cmake +++ b/sdk/cmake/gcc.cmake @@ -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 $ + 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 $ + 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) diff --git a/sdk/lib/crt/msvcrtex.cmake b/sdk/lib/crt/msvcrtex.cmake index c986bae1efb..ff74ebb68b3 100644 --- a/sdk/lib/crt/msvcrtex.cmake +++ b/sdk/lib/crt/msvcrtex.cmake @@ -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 $<$:-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) diff --git a/sdk/lib/crt/oldnames.cmake b/sdk/lib/crt/oldnames.cmake index 93b2a55721a..90099b48800 100644 --- a/sdk/lib/crt/oldnames.cmake +++ b/sdk/lib/crt/oldnames.cmake @@ -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 $ + 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})