[CMAKE] Turn import libs into regular C static libs

Embed msvcrtex into libmsvcrt

Idea taken from Thomas Faber
This commit is contained in:
Jérôme Gardou 2020-11-02 10:51:08 +01:00 committed by Jérôme Gardou
parent cad583967b
commit b96e88894a
7 changed files with 109 additions and 60 deletions

View file

@ -1,14 +1,12 @@
include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/crt/include)
spec2def(msvcrt.dll msvcrt.spec)
spec2def(msvcrt.dll msvcrt.spec ADD_IMPORTLIB)
# The msvcrt <-> msvcrtex trick
generate_import_lib(libmsvcrt_real msvcrt.dll msvcrt.spec)
add_library(libmsvcrt INTERFACE)
# Let consumers of msvcrt have the right defines
target_compile_definitions(libmsvcrt INTERFACE _DLL __USE_CRTIMP)
# if the linked module is one of win32gui;win32cui;win32dll;win32ocx;cpl link it with msvcrtex, which itself is linked to libmsvcrt_real
# Otherwise, just link to libmsvcrt_real
target_link_libraries(libmsvcrt INTERFACE "$<IF:$<IN_LIST:$<TARGET_PROPERTY:REACTOS_MODULE_TYPE>,win32gui;win32cui;win32dll;win32ocx;cpl>,msvcrtex,libmsvcrt_real>")
# Embed msvcrtex into libmsvcrt
target_sources(libmsvcrt PRIVATE $<TARGET_OBJECTS:msvcrtex>)
add_definitions(
-DUSE_MSVCRT_PREFIX
@ -35,7 +33,10 @@ target_link_libraries(msvcrt crt wine ${PSEH_LIB})
if(MSVC)
# export of deleting destructor "name"
target_link_options(msvcrt PRIVATE "/ignore:4102")
set_property(TARGET libmsvcrt_real APPEND PROPERTY STATIC_LIBRARY_OPTIONS "/ignore:4102")
set_property(TARGET libmsvcrt APPEND PROPERTY STATIC_LIBRARY_OPTIONS "/ignore:4102")
if(ARCH STREQUAL "i386")
target_sources(libmsvcrt PRIVATE $<TARGET_OBJECTS:ftol2_sse>)
endif()
endif()
add_importlibs(msvcrt kernel32 ntdll)

View file

@ -322,20 +322,52 @@ function(generate_import_lib _libname _dllname _spec_file)
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_libname}_implib.def
COMMAND native-spec2def -n=${_dllname} -a=${ARCH2} ${ARGN} --implib -d=${CMAKE_CURRENT_BINARY_DIR}/${_libname}_implib.def ${CMAKE_CURRENT_SOURCE_DIR}/${_spec_file}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_spec_file} native-spec2def)
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${_libname}_implib.def PROPERTIES EXTERNAL_OBJECT TRUE)
# Create normal importlib
_add_library(${_libname} STATIC EXCLUDE_FROM_ALL ${CMAKE_CURRENT_BINARY_DIR}/${_libname}_implib.def)
set_target_properties(${_libname} PROPERTIES LINKER_LANGUAGE "IMPLIB" PREFIX "")
# With this, we let DLLTOOL create an 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_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})
# Create delayed importlib
_add_library(${_libname}_delayed STATIC EXCLUDE_FROM_ALL ${CMAKE_CURRENT_BINARY_DIR}/${_libname}_implib.def)
set_target_properties(${_libname}_delayed PROPERTIES LINKER_LANGUAGE "IMPLIB_DELAYED" PREFIX "")
# 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 "")
# 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_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 "")
endfunction()
# Cute little hack to produce import libs
set(CMAKE_IMPLIB_CREATE_STATIC_LIBRARY "${CMAKE_DLLTOOL} --def <OBJECTS> --kill-at --output-lib=<TARGET>")
set(CMAKE_IMPLIB_DELAYED_CREATE_STATIC_LIBRARY "${CMAKE_DLLTOOL} --def <OBJECTS> --kill-at --output-delaylib=<TARGET>")
function(spec2def _dllname _spec_file)
cmake_parse_arguments(__spec2def "ADD_IMPORTLIB;NO_PRIVATE_WARNINGS;WITH_RELAY" "VERSION" "" ${ARGN})

View file

@ -264,9 +264,6 @@ function(set_module_type_toolchain MODULE TYPE)
endfunction()
# Define those for having real libraries
set(CMAKE_IMPLIB_CREATE_STATIC_LIBRARY "LINK /LIB /NOLOGO <LINK_FLAGS> /OUT:<TARGET> <OBJECTS>")
if(ARCH STREQUAL "arm")
set(CMAKE_STUB_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> -nologo -o <OBJECT> <SOURCE>")
else()
@ -299,41 +296,41 @@ function(generate_import_lib _libname _dllname _spec_file)
set(_def_file ${CMAKE_CURRENT_BINARY_DIR}/${_libname}_implib.def)
set(_asm_stubs_file ${CMAKE_CURRENT_BINARY_DIR}/${_libname}_stubs.asm)
# Generate the asm stub file and the def file for import library
# Generate the def and asm stub files
add_custom_command(
OUTPUT ${_asm_stubs_file} ${_def_file}
COMMAND native-spec2def --ms -a=${SPEC2DEF_ARCH} --implib -n=${_dllname} -d=${_def_file} -l=${_asm_stubs_file} ${CMAKE_CURRENT_SOURCE_DIR}/${_spec_file}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_spec_file} native-spec2def)
if(MSVC_IDE)
# Compile the generated asm stub file
if(ARCH STREQUAL "arm")
set(_asm_stub_command ${CMAKE_ASM_COMPILER} -nologo -o ${_asm_stubs_file}.obj ${_asm_stubs_file})
else()
set(_asm_stub_command ${CMAKE_ASM_COMPILER} /Cp /Fo${_asm_stubs_file}.obj /c /Ta ${_asm_stubs_file})
endif()
add_custom_command(
OUTPUT ${_asm_stubs_file}.obj
COMMAND ${_asm_stub_command}
DEPENDS ${_asm_stubs_file})
# Compile the generated asm stub file
if(ARCH STREQUAL "arm")
set(_asm_stub_command ${CMAKE_ASM_COMPILER} -nologo -o ${_asm_stubs_file}.obj ${_asm_stubs_file})
else()
# Be clear about the "language"
# Thanks MS for creating a stupid linker
set_source_files_properties(${_asm_stubs_file} PROPERTIES LANGUAGE "STUB_ASM")
set(_asm_stub_command ${CMAKE_ASM_COMPILER} /nologo /Cp /Fo${_asm_stubs_file}.obj /c /Ta ${_asm_stubs_file})
endif()
add_custom_command(
OUTPUT ${_asm_stubs_file}.obj
COMMAND ${_asm_stub_command}
DEPENDS ${_asm_stubs_file})
# Add our library
if(MSVC_IDE)
add_library(${_libname} STATIC EXCLUDE_FROM_ALL ${_asm_stubs_file}.obj)
set_source_files_properties(${_asm_stubs_file}.obj PROPERTIES EXTERNAL_OBJECT TRUE)
set_target_properties(${_libname} PROPERTIES LINKER_LANGUAGE "C")
else()
# NOTE: as stub file and def file are generated in one pass, depending on one is like depending on the other
add_library(${_libname} STATIC EXCLUDE_FROM_ALL ${_asm_stubs_file})
# set correct "link rule"
set_target_properties(${_libname} PROPERTIES LINKER_LANGUAGE "IMPLIB")
endif()
set_target_properties(${_libname} PROPERTIES STATIC_LIBRARY_FLAGS "/DEF:${_def_file}")
# generate the intermediate import lib
set(_libfile_tmp ${CMAKE_CURRENT_BINARY_DIR}/${_libname}_tmp.lib)
set(_static_lib_options )
add_custom_command(
OUTPUT ${_libfile_tmp}
COMMAND
LINK /LIB NOLOGO /MACHINE:${WINARCH}
$<TARGET_PROPERTY:${_libname},STATIC_LIBRARY_FLAGS> $<TARGET_PROPERTY:${_libname},STATIC_LIBRARY_OPTIONS>
DEF:${_def_file} /OUT:${_libfile_tmp} ${_asm_stubs_file}.obj
DEPENDS ${_asm_stubs_file}.obj ${_def_file})
# By giving the import lib as an object input, LIB extracts the relevant object files and make a new library.
# This allows us to treat the implib as a regular static library
set_source_files_properties(${_libfile_tmp} PROPERTIES EXTERNAL_OBJECT TRUE)
add_library(${_libname} STATIC ${_libfile_tmp})
set_target_properties(${_libname} PROPERTIES LINKER_LANGUAGE "C")
endfunction()
if(ARCH STREQUAL "amd64")
@ -376,7 +373,7 @@ function(spec2def _dllname _spec_file)
if(__spec2def_ADD_IMPORTLIB)
generate_import_lib(lib${_file} ${_dllname} ${_spec_file})
if(__spec2def_NO_PRIVATE_WARNINGS)
add_target_property(lib${_file} STATIC_LIBRARY_FLAGS "/ignore:4104")
set_property(TARGET lib${_file} APPEND PROPERTY STATIC_LIBRARY_OPTIONS /ignore:4104)
endif()
endif()
endfunction()

View file

@ -49,7 +49,6 @@ if(ARCH STREQUAL "i386")
list(APPEND MSVCRTEX_ASM_SOURCE
except/i386/chkstk_asm.s
except/i386/chkstk_ms.s
math/i386/ftol2_asm.s
math/i386/alldiv_asm.s)
list(APPEND MSVCRTEX_SOURCE
math/i386/ci.c
@ -102,11 +101,16 @@ endif()
set_source_files_properties(${MSVCRTEX_ASM_SOURCE} PROPERTIES COMPILE_DEFINITIONS "_DLL;_MSVCRTEX_")
add_asm_files(msvcrtex_asm ${MSVCRTEX_ASM_SOURCE})
add_library(msvcrtex ${MSVCRTEX_SOURCE} ${msvcrtex_asm})
add_library(msvcrtex OBJECT ${MSVCRTEX_SOURCE} ${msvcrtex_asm})
target_compile_definitions(msvcrtex PRIVATE _DLL _MSVCRTEX_)
# Link msvcrtex to the "real" msvcrt.dll library. See msvcrt.dll CMakeLists.txt to see what really happens here
target_link_libraries(msvcrtex libmsvcrt_real libkernel32)
if(MSVC AND (ARCH STREQUAL "i386"))
# user32.dll needs this as a stand-alone object file
add_asm_files(ftol2_asm math/i386/ftol2_asm.s)
add_library(ftol2_sse OBJECT ${ftol2_asm})
target_compile_definitions(ftol2_sse PRIVATE $<TARGET_PROPERTY:msvcrtex,COMPILE_DEFINITIONS>)
endif()
if(GCC OR CLANG)
target_compile_options(msvcrtex PRIVATE $<$<COMPILE_LANGUAGE:C>:-Wno-main>)

View file

@ -1,8 +1,21 @@
if(NOT MSVC)
_add_library(oldnames STATIC EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/moldname-msvcrt.def)
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/moldname-msvcrt.def PROPERTIES EXTERNAL_OBJECT TRUE)
set_target_properties(oldnames PROPERTIES LINKER_LANGUAGE "IMPLIB" PREFIX "")
# Use the same trick as with the other import libs. See gcc.cmake --> generate_import_lib function
set(LIBRARY_PRIVATE_DIR ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/oldnames.dir)
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_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")
else()
add_asm_files(oldnames_asm oldnames-msvcrt.S)
add_library(oldnames ${oldnames_asm})

View file

@ -60,10 +60,13 @@ target_link_libraries(gdi32
wine
win32ksys
dxguid
msvcrtex
atan2
${PSEH_LIB})
if(MSVC AND (ARCH STREQUAL "i386"))
target_sources(gdi32 PRIVATE $<TARGET_OBJECTS:ftol2_sse>)
endif()
add_importlibs(gdi32 user32 advapi32 kernel32 ntdll)
add_pch(gdi32 include/precomp.h SOURCE)
add_dependencies(gdi32 psdk)

View file

@ -82,9 +82,8 @@ set_module_type(user32 win32dll ENTRYPOINT DllMain 12 UNICODE)
target_link_libraries(user32 user32_wsprintf wine win32ksys ${PSEH_LIB})
add_dependencies(user32 asm)
if(MSVC)
# for __ftol2_sse, float to int cast helper
target_link_libraries(user32 msvcrtex)
if(MSVC AND (ARCH STREQUAL "i386"))
target_sources(user32 PRIVATE $<TARGET_OBJECTS:ftol2_sse>)
endif()
add_delay_importlibs(user32 imm32 usp10)