@@ -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"
@@ -1472,9 +1480,32 @@ function Build-CMakeProject {
14721480 $UseCXX = $UseBuiltCompilers.Contains (" CXX" ) -or $UseMSVCCompilers.Contains (" CXX" ) -or $UsePinnedCompilers.Contains (" CXX" )
14731481 $UseSwift = $UseBuiltCompilers.Contains (" Swift" ) -or $UsePinnedCompilers.Contains (" Swift" )
14741482
1483+ # We need to manually prefix linker flags with `-Xlinker` if we are using
1484+ # the GNU driver or if Swift is used as the linker driver.
1485+ # This is not necessary with CMake 4.0+ as CMP0181 simplifies the handling
1486+ # of linker arguments.
1487+ $PrefixLinkerFlags = if ($Platform.OS -eq [OS ]::Android) {
1488+ # We pass the linker location to the driver, not to the linker.
1489+ $false
1490+ } elseif ($CMakeSupportsCMP0181 ) {
1491+ # Not necessary if CMP0181 is supported.
1492+ $false
1493+ } elseif ($UseGnuDriver ) {
1494+ # Always necessary with the GNU driver.
1495+ $true
1496+ } else {
1497+ # Only necessary with Swift projects, when CMake is not passing the linker flags.
1498+ $UseSwift -and $CMakePassesSwiftLinkerFlags
1499+ }
1500+
14751501 # Add additional defines (unless already present)
14761502 $Defines = $Defines.Clone ()
14771503
1504+ # Always enable CMP0181 if available.
1505+ if ($CMakeSupportsCMP0181 ) {
1506+ Add-KeyValueIfNew $Defines CMAKE_POLICY_DEFAULT_CMP0181 NEW
1507+ }
1508+
14781509 Add-KeyValueIfNew $Defines CMAKE_BUILD_TYPE Release
14791510
14801511 # Avoid specifying `CMAKE_SYSTEM_NAME` and `CMAKE_SYSTEM_PROCESSOR` on
@@ -1645,23 +1676,31 @@ function Build-CMakeProject {
16451676 @ (" -gnone" )
16461677 }
16471678
1648- # Disable EnC as that introduces padding in the conformance tables
1649- $SwiftFlags += @ (" -Xlinker" , " /INCREMENTAL:NO" )
1650- # Swift requires COMDAT folding and de-duplication
1651- $SwiftFlags += @ (" -Xlinker" , " /OPT:REF" , " -Xlinker" , " /OPT:ICF" )
1679+ if (-not $CMakePassesSwiftLinkerFlags ) {
1680+ # Disable EnC as that introduces padding in the conformance tables
1681+ $SwiftFlags += @ (" -Xlinker" , " /INCREMENTAL:NO" )
1682+ # Swift requires COMDAT folding and de-duplication
1683+ $SwiftFlags += @ (" -Xlinker" , " /OPT:REF" , " -Xlinker" , " /OPT:ICF" )
1684+ }
16521685
16531686 Add-FlagsDefine $Defines CMAKE_Swift_FLAGS $SwiftFlags
16541687 # Workaround CMake 3.26+ enabling `-wmo` by default on release builds
16551688 Add-FlagsDefine $Defines CMAKE_Swift_FLAGS_RELEASE " -O"
16561689 Add-FlagsDefine $Defines CMAKE_Swift_FLAGS_RELWITHDEBINFO " -O"
1657- }
16581690
1659- $LinkerFlags = if ($UseGNUDriver ) {
1660- @ (" -Xlinker" , " /INCREMENTAL:NO" , " -Xlinker" , " /OPT:REF" , " -Xlinker" , " /OPT:ICF" )
1661- } else {
1662- @ (" /INCREMENTAL:NO" , " /OPT:REF" , " /OPT:ICF" )
1691+ if ($CMakePassesSwiftLinkerFlags ) {
1692+ # CMake 3.30+ passes all linker flags to Swift as the linker driver,
1693+ # including those from the internal CMake modules files, without
1694+ # a `-Xlinker` prefix. This causes build failures as Swift cannot
1695+ # parse linker flags.
1696+ # Overwrite the release linker flags to be empty to avoid this.
1697+ Add-KeyValueIfNew $Defines CMAKE_EXE_LINKER_FLAGS_RELEASE " "
1698+ Add-KeyValueIfNew $Defines CMAKE_SHARED_LINKER_FLAGS_RELEASE " "
1699+ }
16631700 }
16641701
1702+ $LinkerFlags = @ (" /INCREMENTAL:NO" , " /OPT:REF" , " /OPT:ICF" )
1703+
16651704 if ($DebugInfo ) {
16661705 if ($UseASM -or $UseC -or $UseCXX ) {
16671706 # Prefer `/Z7` over `/ZI`
@@ -1671,10 +1710,14 @@ function Build-CMakeProject {
16711710 Add-KeyValueIfNew $Defines CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded
16721711 Add-KeyValueIfNew $Defines CMAKE_POLICY_DEFAULT_CMP0141 NEW
16731712
1674- $LinkerFlags += if ($UseGNUDriver ) {
1675- @ (" -Xlinker" , " /DEBUG" )
1676- } else {
1677- @ (" /DEBUG" )
1713+ $LinkerFlags += @ (" /DEBUG" )
1714+
1715+ # The linker flags are shared across every language, and `/IGNORE:longsections` is an
1716+ # `lld-link.exe` argument, not `link.exe`, so this can only be enabled when we use
1717+ # `lld-link.exe` for linking.
1718+ # TODO: Investigate supporting fission with PE/COFF, this should avoid this warning.
1719+ if ($SwiftDebugFormat -eq " dwarf" -and -not ($UseMSVCCompilers.Contains (" C" ) -or $UseMSVCCompilers.Contains (" CXX" ))) {
1720+ $LinkerFlags += @ (" /IGNORE:longsections" )
16781721 }
16791722
16801723 # The linker flags are shared across every language, and `/IGNORE:longsections` is an
@@ -1825,24 +1868,33 @@ function Build-CMakeProject {
18251868 $Value = $Define.Value.Replace (" \" , " /" )
18261869 } else {
18271870 # Flags array, multiple tokens, quoting needed for tokens containing spaces
1828- $Value = " "
1829- foreach ($Arg in $Define.Value ) {
1830- if ($Value.Length -gt 0 ) {
1831- $Value += " "
1832- }
1833-
1834- $ArgWithForwardSlashes = $Arg.Replace (" \" , " /" )
1835- if ($ArgWithForwardSlashes.Contains (" " )) {
1871+ $EscapedArgs = $Define.Value | ForEach-Object {
1872+ $Arg = $_.Replace (" \" , " /" )
1873+ if ($Arg.Contains (" " )) {
18361874 # Escape the quote so it makes it through. PowerShell 5 and Core
18371875 # handle quotes differently, so we need to check the version.
18381876 $quote = if ($PSEdition -eq " Core" ) { ' "' } else { ' \"' }
1839- $Value += " $quote$ArgWithForwardSlashes $quote "
1877+ " $quote$Arg $quote "
18401878 } else {
1841- $Value += $ArgWithForwardSlashes
1879+ $Arg
18421880 }
18431881 }
1844- }
18451882
1883+ # Linker flags are handled differently depending on the CMake version.
1884+ $IsLinkerFlag = $Define.Key -match " _LINKER_FLAGS" -and ($Platform.OS -ne [OS ]::Android)
1885+ $Value = if ($IsLinkerFlag ) {
1886+ if ($CMakeSupportsCMP0181 ) { " LINKER:" } elseif ($PrefixLinkerFlags ) { " -Xlinker " } else { " " }
1887+ } else {
1888+ " "
1889+ }
1890+ $Separator = if ($IsLinkerFlag ) {
1891+ if ($CMakeSupportsCMP0181 ) { " ," } elseif ($PrefixLinkerFlags ) { " -Xlinker " } else { " " }
1892+ } else {
1893+ " "
1894+ }
1895+
1896+ $Value += $EscapedArgs -join $Separator
1897+ }
18461898 $cmakeGenerateArgs += @ (" -D" , " $ ( $Define.Key ) =$Value " )
18471899 }
18481900
0 commit comments