From 8b710d826407972955f6cdaed0e210199f2f48a9 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 28 May 2025 13:19:21 -0400 Subject: [PATCH] Linker: Generate per-language module -DEF: flags on Windows With IntelLLVM on Windows, we link using the compiler driver. With MSVC on Windows, we invoke the linker directly. If we use both in a single build tree, for separate languages, the value of `CMAKE_LINK_DEF_FILE_FLAG` conflicts. Add a per-language `CMAKE__LINK_DEF_FILE_FLAG` variable to avoid the conflict. Preserve the language-agnostic variable for compatibility with projects that reference it. Fixes: #26005 --- Help/manual/cmake-variables.7.rst | 1 + Help/variable/CMAKE_LANG_LINK_DEF_FILE_FLAG.rst | 14 ++++++++++++++ Help/variable/CMAKE_LINK_DEF_FILE_FLAG.rst | 6 ++++++ Modules/Platform/Windows-Clang.cmake | 3 ++- Modules/Platform/Windows-GNU.cmake | 2 ++ Modules/Platform/Windows-IntelLLVM.cmake | 3 ++- Modules/Platform/Windows-MSVC.cmake | 1 + Modules/Platform/Windows-PGI.cmake | 2 ++ Source/cmLocalGenerator.cxx | 12 ++++++++---- Source/cmLocalGenerator.h | 3 ++- Source/cmMakefileExecutableTargetGenerator.cxx | 2 +- Source/cmMakefileLibraryTargetGenerator.cxx | 4 ++-- Tests/ModuleDefinition/CMakeLists.txt | 4 ++++ Tests/ObjectLibrary/CMakeLists.txt | 2 +- 14 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 Help/variable/CMAKE_LANG_LINK_DEF_FILE_FLAG.rst diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 4cda7b4829..f89268fdb8 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -493,6 +493,7 @@ Variables that Control the Build /variable/CMAKE_LANG_COMPILER_LAUNCHER /variable/CMAKE_LANG_CPPCHECK /variable/CMAKE_LANG_CPPLINT + /variable/CMAKE_LANG_LINK_DEF_FILE_FLAG /variable/CMAKE_LANG_ICSTAT /variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE /variable/CMAKE_LANG_LINK_GROUP_USING_FEATURE diff --git a/Help/variable/CMAKE_LANG_LINK_DEF_FILE_FLAG.rst b/Help/variable/CMAKE_LANG_LINK_DEF_FILE_FLAG.rst new file mode 100644 index 0000000000..96feb797cc --- /dev/null +++ b/Help/variable/CMAKE_LANG_LINK_DEF_FILE_FLAG.rst @@ -0,0 +1,14 @@ +CMAKE__LINK_DEF_FILE_FLAG +------------------------------- + +.. versionadded:: 4.1 + +Linker flag to be used to specify a ``.def`` file for dll creation +with the toolchain for language ````. + +CMake sets this variable automatically during toolchain inspection by +calls to the :command:`project` or :command:`enable_language` commands. + +If the :variable:`!CMAKE__LINK_DEF_FILE_FLAG` variable +is defined, it takes precedence over the language-agnostic +:variable:`CMAKE_LINK_DEF_FILE_FLAG` variable. diff --git a/Help/variable/CMAKE_LINK_DEF_FILE_FLAG.rst b/Help/variable/CMAKE_LINK_DEF_FILE_FLAG.rst index fa09f9f9c3..d6a1fb79b5 100644 --- a/Help/variable/CMAKE_LINK_DEF_FILE_FLAG.rst +++ b/Help/variable/CMAKE_LINK_DEF_FILE_FLAG.rst @@ -5,3 +5,9 @@ Linker flag to be used to specify a ``.def`` file for dll creation. The flag will be used to add a ``.def`` file when creating a dll on Windows; this is only defined on Windows. + +CMake sets this variable automatically during toolchain inspection by +calls to the :command:`project` or :command:`enable_language` commands. + +If the per-language :variable:`CMAKE__LINK_DEF_FILE_FLAG` variable +is defined, it takes precedence over :variable:`!CMAKE_LINK_DEF_FILE_FLAG`. diff --git a/Modules/Platform/Windows-Clang.cmake b/Modules/Platform/Windows-Clang.cmake index 34ed2bcf91..c40a4d7cfd 100644 --- a/Modules/Platform/Windows-Clang.cmake +++ b/Modules/Platform/Windows-Clang.cmake @@ -33,7 +33,8 @@ macro(__windows_compiler_clang_gnu lang) set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "") set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll.a" ".a" ".lib") set(CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS 1) - set (CMAKE_LINK_DEF_FILE_FLAG "-Xlinker /DEF:") + set(CMAKE_${lang}_LINK_DEF_FILE_FLAG "-Xlinker /DEF:") + set(CMAKE_LINK_DEF_FILE_FLAG "${CMAKE_${lang}_LINK_DEF_FILE_FLAG}") set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Xlinker" " ") set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP) diff --git a/Modules/Platform/Windows-GNU.cmake b/Modules/Platform/Windows-GNU.cmake index ea7b77b0b7..687caf27e5 100644 --- a/Modules/Platform/Windows-GNU.cmake +++ b/Modules/Platform/Windows-GNU.cmake @@ -127,6 +127,8 @@ macro(__windows_compiler_gnu lang) set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "@") endif() + set(CMAKE_${lang}_LINK_DEF_FILE_FLAG "") # Empty string: passing the file is enough + # Binary link rules. set(CMAKE_${lang}_CREATE_SHARED_MODULE " -o ${CMAKE_GNULD_IMAGE_VERSION} ") diff --git a/Modules/Platform/Windows-IntelLLVM.cmake b/Modules/Platform/Windows-IntelLLVM.cmake index 2b9d83b35c..953da81f01 100644 --- a/Modules/Platform/Windows-IntelLLVM.cmake +++ b/Modules/Platform/Windows-IntelLLVM.cmake @@ -35,7 +35,8 @@ macro(__windows_compiler_intel lang) set(CMAKE_${lang}_CREATE_WIN32_EXE "${CMAKE_${lang}_LINKER_WRAPPER_FLAG}/subsystem:windows") set(CMAKE_${lang}_CREATE_CONSOLE_EXE "${CMAKE_${lang}_LINKER_WRAPPER_FLAG}/subsystem:console") - set(CMAKE_LINK_DEF_FILE_FLAG "${CMAKE_${lang}_LINKER_WRAPPER_FLAG}/DEF:") + set(CMAKE_${lang}_LINK_DEF_FILE_FLAG "${CMAKE_${lang}_LINKER_WRAPPER_FLAG}/DEF:") + set(CMAKE_LINK_DEF_FILE_FLAG "${CMAKE_${lang}_LINK_DEF_FILE_FLAG}") set(CMAKE_LIBRARY_PATH_FLAG "${CMAKE_${lang}_LINKER_WRAPPER_FLAG}/LIBPATH:") set(CMAKE_${lang}_LINK_EXECUTABLE diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake index 6dce85b9d5..b31de86479 100644 --- a/Modules/Platform/Windows-MSVC.cmake +++ b/Modules/Platform/Windows-MSVC.cmake @@ -396,6 +396,7 @@ macro(__windows_compiler_msvc lang) set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE " ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO}${_COMPILE_${lang}} /FoNUL /FAs /Fa /c ${CMAKE_END_TEMP_FILE}") + set(CMAKE_${lang}_LINK_DEF_FILE_FLAG "/DEF:") set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_OBJECTS 1) set(CMAKE_${lang}_LINK_EXECUTABLE "${_CMAKE_VS_LINK_EXE} ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE} /out: /implib: /pdb: /version:.${_PLATFORM_LINK_FLAGS} ${CMAKE_END_TEMP_FILE}") diff --git a/Modules/Platform/Windows-PGI.cmake b/Modules/Platform/Windows-PGI.cmake index ae68eba421..40776996e5 100644 --- a/Modules/Platform/Windows-PGI.cmake +++ b/Modules/Platform/Windows-PGI.cmake @@ -37,6 +37,8 @@ else() endif() macro(__windows_compiler_pgi lang) + set(CMAKE_${lang}_LINK_DEF_FILE_FLAG "-def:") + # Shared library compile and link rules. set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "lib ${CMAKE_CL_NOLOGO} /out: ") set(CMAKE_${lang}_CREATE_SHARED_LIBRARY " ${CMAKE_START_TEMP_FILE} -Mmakedll -implib: -Xlinker -pdb: -Xlinker -version:. -o ${CMAKE_END_TEMP_FILE}") diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 0440a014e5..14254602b5 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1673,7 +1673,7 @@ void cmLocalGenerator::GetTargetFlags( this->AppendWarningAsErrorLinkerFlags(extraLinkFlags, target, linkLanguage); this->AppendIPOLinkerFlags(extraLinkFlags, target, config, linkLanguage); this->AppendModuleDefinitionFlag(extraLinkFlags, target, linkLineComputer, - config); + config, linkLanguage); if (!extraLinkFlags.empty()) { this->GetGlobalGenerator()->EncodeLiteral(extraLinkFlags); @@ -3615,7 +3615,8 @@ std::string cmLocalGenerator::GetLinkDependencyFile( void cmLocalGenerator::AppendModuleDefinitionFlag( std::string& flags, cmGeneratorTarget const* target, - cmLinkLineComputer* linkLineComputer, std::string const& config) + cmLinkLineComputer* linkLineComputer, std::string const& config, + std::string const& lang) { cmGeneratorTarget::ModuleDefinitionInfo const* mdi = target->GetModuleDefinitionInfo(config); @@ -3623,8 +3624,11 @@ void cmLocalGenerator::AppendModuleDefinitionFlag( return; } - cmValue defFileFlag = - this->Makefile->GetDefinition("CMAKE_LINK_DEF_FILE_FLAG"); + cmValue defFileFlag = this->Makefile->GetDefinition( + cmStrCat("CMAKE_", lang, "_LINK_DEF_FILE_FLAG")); + if (!defFileFlag) { + defFileFlag = this->Makefile->GetDefinition("CMAKE_LINK_DEF_FILE_FLAG"); + } if (!defFileFlag) { return; } diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 1c4dd4ec50..2815ee68e7 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -192,7 +192,8 @@ public: void AppendModuleDefinitionFlag(std::string& flags, cmGeneratorTarget const* target, cmLinkLineComputer* linkLineComputer, - std::string const& config); + std::string const& config, + std::string const& lang); bool AppendLWYUFlags(std::string& flags, cmGeneratorTarget const* target, std::string const& lang); diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index c812874ba5..3a4112d392 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -421,7 +421,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) this->LocalGenerator->AppendModuleDefinitionFlag( linkFlags, this->GeneratorTarget, linkLineComputer.get(), - this->GetConfigName()); + this->GetConfigName(), linkLanguage); } this->LocalGenerator->AppendIPOLinkerFlags( diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 57b699171b..0ec30dba03 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -188,7 +188,7 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink) this->LocalGenerator->AppendModuleDefinitionFlag( extraFlags, this->GeneratorTarget, linkLineComputer.get(), - this->GetConfigName()); + this->GetConfigName(), linkLanguage); this->UseLWYU = this->LocalGenerator->AppendLWYUFlags( extraFlags, this->GeneratorTarget, linkLanguage); @@ -224,7 +224,7 @@ void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink) this->LocalGenerator->AppendModuleDefinitionFlag( extraFlags, this->GeneratorTarget, linkLineComputer.get(), - this->GetConfigName()); + this->GetConfigName(), linkLanguage); this->UseLWYU = this->LocalGenerator->AppendLWYUFlags( extraFlags, this->GeneratorTarget, linkLanguage); diff --git a/Tests/ModuleDefinition/CMakeLists.txt b/Tests/ModuleDefinition/CMakeLists.txt index 089495eb54..92c2204e02 100644 --- a/Tests/ModuleDefinition/CMakeLists.txt +++ b/Tests/ModuleDefinition/CMakeLists.txt @@ -1,6 +1,10 @@ cmake_minimum_required(VERSION 3.10) project(ModuleDefinition C) +# Simulate another language overriding the -DEF: flag. +# The generators now prefer CMAKE__LINK_DEF_FILE_FLAG. +set(CMAKE_LINK_DEF_FILE_FLAG "bad-def-flag:") + # Test .def file source recognition for DLLs. add_library(example_dll SHARED example_dll.c example_dll.def) diff --git a/Tests/ObjectLibrary/CMakeLists.txt b/Tests/ObjectLibrary/CMakeLists.txt index 39a3e42af0..5bac59117c 100644 --- a/Tests/ObjectLibrary/CMakeLists.txt +++ b/Tests/ObjectLibrary/CMakeLists.txt @@ -32,7 +32,7 @@ target_link_libraries(UseABstatic ABstatic) # Test module definition file to export object library symbols in the test # below if the platform needs and supports it. set(ABshared_SRCS $) -if(CMAKE_LINK_DEF_FILE_FLAG OR NOT WIN32) +if(CMAKE_C_LINK_DEF_FILE_FLAG OR NOT WIN32) list(APPEND ABshared_SRCS $ AB.def) else() set(NO_A NO_A)