@@ -511,6 +511,15 @@ function Get-CMake {
511511 throw " CMake not found on Path nor in the Visual Studio Installation. Please Install CMake to continue."
512512}
513513
514+ $cmake = Get-CMake
515+ $CMakeVersionString = & $cmake -- version | Select-String - Pattern ' cmake version ([\d\.]+)' | ForEach-Object { $_.Matches [0 ].Groups[1 ].Value }
516+ $CMakeVersion = [Version ]$CMakeVersionString
517+ # Starting with CMake 3.30, CMake propagates linker flags to Swift.
518+ $CMakePassesSwiftLinkerFlags = $CMakeVersion -ge [version ]' 3.30'
519+ # CMP0181 enables support for the `LINKER:flag1,flag2,...` syntax in
520+ # `CMAKE_[EXE|SHARED|MODULE]_LINKER_FLAGS[_<CONFIG>]` variables.
521+ $CMakeSupportsCMP0181 = $CMakeVersion -ge [version ]' 4.0'
522+
514523function Get-Ninja {
515524 try {
516525 return (Get-Command " Ninja.exe" - ErrorAction Stop).Source
@@ -522,7 +531,6 @@ function Get-Ninja {
522531 throw " Ninja not found on Path nor in the Visual Studio Installation. Please Install Ninja to continue."
523532}
524533
525- $cmake = Get-CMake
526534$ninja = Get-Ninja
527535
528536$NugetRoot = " $BinaryCache \nuget"
@@ -1420,9 +1428,32 @@ function Build-CMakeProject {
14201428 $UseCXX = $UseBuiltCompilers.Contains (" CXX" ) -or $UseMSVCCompilers.Contains (" CXX" ) -or $UsePinnedCompilers.Contains (" CXX" )
14211429 $UseSwift = $UseBuiltCompilers.Contains (" Swift" ) -or $UsePinnedCompilers.Contains (" Swift" )
14221430
1431+ # We need to manually prefix linker flags with `-Xlinker` if we are using
1432+ # the GNU driver or if Swift is used as the linker driver.
1433+ # This is not necessary with CMake 4.0+ as CMP0181 simplifies the handling
1434+ # of linker arguments.
1435+ $PrefixLinkerFlags = if ($Platform.OS -eq [OS ]::Android) {
1436+ # We pass the linker location to the driver, not to the linker.
1437+ $false
1438+ } elseif ($CMakeSupportsCMP0181 ) {
1439+ # Not necessary if CMP0181 is supported.
1440+ $false
1441+ } elseif ($UseGnuDriver ) {
1442+ # Always necessary with the GNU driver.
1443+ $true
1444+ } else {
1445+ # Only necessary with Swift projects, when CMake is not passing the linker flags.
1446+ $UseSwift -and $CMakePassesSwiftLinkerFlags
1447+ }
1448+
14231449 # Add additional defines (unless already present)
14241450 $Defines = $Defines.Clone ()
14251451
1452+ # Always enable CMP0181 if available.
1453+ if ($CMakeSupportsCMP0181 ) {
1454+ Add-KeyValueIfNew $Defines CMAKE_POLICY_DEFAULT_CMP0181 NEW
1455+ }
1456+
14261457 Add-KeyValueIfNew $Defines CMAKE_BUILD_TYPE Release
14271458
14281459 # Avoid specifying `CMAKE_SYSTEM_NAME` and `CMAKE_SYSTEM_PROCESSOR` on
@@ -1593,23 +1624,31 @@ function Build-CMakeProject {
15931624 @ (" -gnone" )
15941625 }
15951626
1596- # Disable EnC as that introduces padding in the conformance tables
1597- $SwiftFlags += @ (" -Xlinker" , " /INCREMENTAL:NO" )
1598- # Swift requires COMDAT folding and de-duplication
1599- $SwiftFlags += @ (" -Xlinker" , " /OPT:REF" , " -Xlinker" , " /OPT:ICF" )
1627+ if (-not $CMakePassesSwiftLinkerFlags ) {
1628+ # Disable EnC as that introduces padding in the conformance tables
1629+ $SwiftFlags += @ (" -Xlinker" , " /INCREMENTAL:NO" )
1630+ # Swift requires COMDAT folding and de-duplication
1631+ $SwiftFlags += @ (" -Xlinker" , " /OPT:REF" , " -Xlinker" , " /OPT:ICF" )
1632+ }
16001633
16011634 Add-FlagsDefine $Defines CMAKE_Swift_FLAGS $SwiftFlags
16021635 # Workaround CMake 3.26+ enabling `-wmo` by default on release builds
16031636 Add-FlagsDefine $Defines CMAKE_Swift_FLAGS_RELEASE " -O"
16041637 Add-FlagsDefine $Defines CMAKE_Swift_FLAGS_RELWITHDEBINFO " -O"
1605- }
16061638
1607- $LinkerFlags = if ($UseGNUDriver ) {
1608- @ (" -Xlinker" , " /INCREMENTAL:NO" , " -Xlinker" , " /OPT:REF" , " -Xlinker" , " /OPT:ICF" )
1609- } else {
1610- @ (" /INCREMENTAL:NO" , " /OPT:REF" , " /OPT:ICF" )
1639+ if ($CMakePassesSwiftLinkerFlags ) {
1640+ # CMake 3.30+ passes all linker flags to Swift as the linker driver,
1641+ # including those from the internal CMake modules files, without
1642+ # a `-Xlinker` prefix. This causes build failures as Swift cannot
1643+ # parse linker flags.
1644+ # Overwrite the release linker flags to be empty to avoid this.
1645+ Add-KeyValueIfNew $Defines CMAKE_EXE_LINKER_FLAGS_RELEASE " "
1646+ Add-KeyValueIfNew $Defines CMAKE_SHARED_LINKER_FLAGS_RELEASE " "
1647+ }
16111648 }
16121649
1650+ $LinkerFlags = @ (" /INCREMENTAL:NO" , " /OPT:REF" , " /OPT:ICF" )
1651+
16131652 if ($DebugInfo ) {
16141653 if ($UseASM -or $UseC -or $UseCXX ) {
16151654 # Prefer `/Z7` over `/ZI`
@@ -1619,10 +1658,14 @@ function Build-CMakeProject {
16191658 Add-KeyValueIfNew $Defines CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded
16201659 Add-KeyValueIfNew $Defines CMAKE_POLICY_DEFAULT_CMP0141 NEW
16211660
1622- $LinkerFlags += if ($UseGNUDriver ) {
1623- @ (" -Xlinker" , " /DEBUG" )
1624- } else {
1625- @ (" /DEBUG" )
1661+ $LinkerFlags += @ (" /DEBUG" )
1662+
1663+ # The linker flags are shared across every language, and `/IGNORE:longsections` is an
1664+ # `lld-link.exe` argument, not `link.exe`, so this can only be enabled when we use
1665+ # `lld-link.exe` for linking.
1666+ # TODO: Investigate supporting fission with PE/COFF, this should avoid this warning.
1667+ if ($SwiftDebugFormat -eq " dwarf" -and -not ($UseMSVCCompilers.Contains (" C" ) -or $UseMSVCCompilers.Contains (" CXX" ))) {
1668+ $LinkerFlags += @ (" /IGNORE:longsections" )
16261669 }
16271670
16281671 # The linker flags are shared across every language, and `/IGNORE:longsections` is an
@@ -1772,11 +1815,27 @@ function Build-CMakeProject {
17721815 # Single token value, no need to quote spaces, the splat operator does the right thing.
17731816 $Value = $Define.Value.Replace (" \" , " /" )
17741817 } else {
1818+ # Linker flags are escaped differently, depending on the CMake version.
1819+ $IsLinkerFlag = $Define.Key -match " _LINKER_FLAGS" -and ($Platform.OS -ne [OS ]::Android)
1820+
17751821 # Flags array, multiple tokens, quoting needed for tokens containing spaces
1776- $Value = " "
1822+ $Value = if ($IsLinkerFlag ) {
1823+ if ($CMakeSupportsCMP0181 ) { " LINKER:" } elseif ($PrefixLinkerFlags ) { " -Xlinker " } else { " " }
1824+ } else {
1825+ " "
1826+ }
1827+ $Separator = if ($IsLinkerFlag ) {
1828+ if ($CMakeSupportsCMP0181 ) { " ," } elseif ($PrefixLinkerFlags ) { " -Xlinker " } else { " " }
1829+ } else {
1830+ " "
1831+ }
1832+
1833+ $FirstArg = $true
17771834 foreach ($Arg in $Define.Value ) {
1778- if ($Value.Length -gt 0 ) {
1779- $Value += " "
1835+ if ($FirstArg ) {
1836+ $FirstArg = $false
1837+ } else {
1838+ $Value += $Separator
17801839 }
17811840
17821841 $ArgWithForwardSlashes = $Arg.Replace (" \" , " /" )
0 commit comments