VS: Suppress MSBuild default link flags not specified by project or user

MSBuild adds some `link` flags by default, but for CMake they may not
match what's produced by command-line generators.  If these flags are
not specified by the project or user, suppress them.

Fixes: #27004
This commit is contained in:
AJIOB
2025-06-17 18:16:54 +03:00
committed by Brad King
parent 68eb6fb683
commit 99d09ec45a
4 changed files with 133 additions and 25 deletions

View File

@@ -4550,32 +4550,35 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
}
if (this->MSTools) {
if (this->GeneratorTarget->IsWin32Executable(config)) {
if (this->GlobalGenerator->TargetsWindowsCE()) {
linkOptions.AddFlag("SubSystem", "WindowsCE");
if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
if (this->ClOptions[config]->UsingUnicode()) {
linkOptions.AddFlag("EntryPointSymbol", "wWinMainCRTStartup");
} else {
linkOptions.AddFlag("EntryPointSymbol", "WinMainCRTStartup");
if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
// Specify an entry point for executables.
if (this->GeneratorTarget->IsWin32Executable(config)) {
if (this->GlobalGenerator->TargetsWindowsCE()) {
linkOptions.AddFlag("SubSystem", "WindowsCE");
if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
if (this->ClOptions[config]->UsingUnicode()) {
linkOptions.AddFlag("EntryPointSymbol", "wWinMainCRTStartup");
} else {
linkOptions.AddFlag("EntryPointSymbol", "WinMainCRTStartup");
}
}
} else {
linkOptions.AddFlag("SubSystem", "Windows");
}
} else {
linkOptions.AddFlag("SubSystem", "Windows");
if (this->GlobalGenerator->TargetsWindowsCE()) {
linkOptions.AddFlag("SubSystem", "WindowsCE");
if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
if (this->ClOptions[config]->UsingUnicode()) {
linkOptions.AddFlag("EntryPointSymbol", "mainWCRTStartup");
} else {
linkOptions.AddFlag("EntryPointSymbol", "mainACRTStartup");
}
}
} else {
linkOptions.AddFlag("SubSystem", "Console");
};
}
} else {
if (this->GlobalGenerator->TargetsWindowsCE()) {
linkOptions.AddFlag("SubSystem", "WindowsCE");
if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
if (this->ClOptions[config]->UsingUnicode()) {
linkOptions.AddFlag("EntryPointSymbol", "mainWCRTStartup");
} else {
linkOptions.AddFlag("EntryPointSymbol", "mainACRTStartup");
}
}
} else {
linkOptions.AddFlag("SubSystem", "Console");
};
}
if (cmValue stackVal = this->Makefile->GetDefinition(
@@ -4660,6 +4663,26 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
}
}
if (this->ProjectType == VsProjectType::vcxproj && this->MSTools) {
// Suppress MSBuild default settings for which the project
// specifies no flags.
if (!linkOptions.HasFlag("DataExecutionPrevention")) {
linkOptions.AddFlag("DataExecutionPrevention", "");
}
if (!linkOptions.HasFlag("ImageHasSafeExceptionHandlers")) {
linkOptions.AddFlag("ImageHasSafeExceptionHandlers", "");
}
if (!linkOptions.HasFlag("LinkErrorReporting")) {
linkOptions.AddFlag("LinkErrorReporting", "");
}
if (!linkOptions.HasFlag("RandomizedBaseAddress")) {
linkOptions.AddFlag("RandomizedBaseAddress", "");
}
if (!linkOptions.HasFlag("SubSystem")) {
linkOptions.AddFlag("SubSystem", "");
}
}
this->LinkOptions[config] = std::move(pOptions);
return true;
}

View File

@@ -1,4 +1,4 @@
macro(VsDefaultFlags_check tgt)
macro(VsDefaultCompilerFlags_check tgt)
set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/${tgt}.vcxproj")
if(NOT EXISTS "${vcProjectFile}")
set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not exist.")
@@ -38,4 +38,83 @@ macro(VsDefaultFlags_check tgt)
endif()
endmacro()
VsDefaultFlags_check(empty)
macro(VsDefaultLinkerFlags_check tgt needs_subsystem_console)
set(HAVE_DataExecutionPrevention 0)
set(HAVE_ImageHasSafeExceptionHandlers 0)
set(HAVE_LinkErrorReporting 0)
set(HAVE_RandomizedBaseAddress 0)
set(HAVE_SubSystem 0)
set(HAVE_SubSystem_Console 0)
file(STRINGS "${vcProjectFile}" lines)
foreach(line IN LISTS lines)
if(line MATCHES "^ *<DataExecutionPrevention></DataExecutionPrevention>")
set(HAVE_DataExecutionPrevention 1)
endif()
if(line MATCHES "^ *<ImageHasSafeExceptionHandlers></ImageHasSafeExceptionHandlers>")
set(HAVE_ImageHasSafeExceptionHandlers 1)
endif()
if(line MATCHES "^ *<LinkErrorReporting></LinkErrorReporting>")
set(HAVE_LinkErrorReporting 1)
endif()
if(line MATCHES "^ *<RandomizedBaseAddress></RandomizedBaseAddress>")
set(HAVE_RandomizedBaseAddress 1)
endif()
if(line MATCHES "^ *<SubSystem></SubSystem>")
set(HAVE_SubSystem 1)
endif()
if(line MATCHES "^ *<SubSystem>Console</SubSystem>")
set(HAVE_SubSystem_Console 1)
endif()
endforeach()
if(NOT HAVE_DataExecutionPrevention)
set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not have a <DataExecutionPrevention> property.")
return()
endif()
if(NOT HAVE_ImageHasSafeExceptionHandlers)
set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not have a <ImageHasSafeExceptionHandlers> property.")
return()
endif()
if(NOT HAVE_LinkErrorReporting)
set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not have a <LinkErrorReporting> property.")
return()
endif()
if(NOT HAVE_RandomizedBaseAddress)
set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not have a <RandomizedBaseAddress> property.")
return()
endif()
if(${needs_subsystem_console})
if(HAVE_SubSystem)
set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj has a <SubSystem> property.")
return()
endif()
if(NOT HAVE_SubSystem_Console)
set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not have a <SubSystem> property with 'Console' value.")
return()
endif()
else()
if(NOT HAVE_SubSystem)
set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not have a <SubSystem> property.")
return()
endif()
if(HAVE_SubSystem_Console)
set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj has a <SubSystem> property with 'Console' value.")
return()
endif()
endif()
endmacro()
VsDefaultCompilerFlags_check(emptyStatic)
VsDefaultCompilerFlags_check(emptyShared)
VsDefaultLinkerFlags_check(emptyShared OFF)
VsDefaultCompilerFlags_check(main)
VsDefaultLinkerFlags_check(main ON)

View File

@@ -1,2 +1,4 @@
enable_language(C)
add_library(empty empty.c)
add_library(emptyStatic STATIC empty.c)
add_library(emptyShared SHARED empty.c)
add_executable(main main.c)

View File

@@ -0,0 +1,4 @@
int main(int argc, char** argv)
{
return 0;
}