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_<LANG>_LINK_DEF_FILE_FLAG` variable to
avoid the conflict.  Preserve the language-agnostic variable
for compatibility with projects that reference it.

Fixes: #26005
This commit is contained in:
Brad King
2025-05-28 13:19:21 -04:00
parent 9ffbef62ca
commit 8b710d8264
14 changed files with 48 additions and 11 deletions

View File

@@ -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

View File

@@ -0,0 +1,14 @@
CMAKE_<LANG>_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 ``<LANG>``.
CMake sets this variable automatically during toolchain inspection by
calls to the :command:`project` or :command:`enable_language` commands.
If the :variable:`!CMAKE_<LANG>_LINK_DEF_FILE_FLAG` variable
is defined, it takes precedence over the language-agnostic
:variable:`CMAKE_LINK_DEF_FILE_FLAG` variable.

View File

@@ -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_<LANG>_LINK_DEF_FILE_FLAG` variable
is defined, it takes precedence over :variable:`!CMAKE_LINK_DEF_FILE_FLAG`.

View File

@@ -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)

View File

@@ -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
"<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_MODULE_${lang}_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS> -o <TARGET> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>")

View File

@@ -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

View File

@@ -396,6 +396,7 @@ macro(__windows_compiler_msvc lang)
set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE
"<CMAKE_${lang}_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO}${_COMPILE_${lang}} <DEFINES> <INCLUDES> <FLAGS> /FoNUL /FAs /Fa<ASSEMBLY_SOURCE> /c <SOURCE>${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_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}")

View File

@@ -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} <LINK_FLAGS> /out:<TARGET> <OBJECTS> ")
set(CMAKE_${lang}_CREATE_SHARED_LIBRARY "<CMAKE_${lang}_COMPILER> ${CMAKE_START_TEMP_FILE} -Mmakedll -implib:<TARGET_IMPLIB> -Xlinker -pdb:<TARGET_PDB> -Xlinker -version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <LINK_FLAGS> -o <TARGET> <OBJECTS> <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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(

View File

@@ -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);

View File

@@ -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_<LANG>_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)

View File

@@ -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 $<TARGET_OBJECTS:A>)
if(CMAKE_LINK_DEF_FILE_FLAG OR NOT WIN32)
if(CMAKE_C_LINK_DEF_FILE_FLAG OR NOT WIN32)
list(APPEND ABshared_SRCS $<TARGET_OBJECTS:B> AB.def)
else()
set(NO_A NO_A)