@@ -511,6 +511,15 @@ function Get-CMake {
511
511
throw " CMake not found on Path nor in the Visual Studio Installation. Please Install CMake to continue."
512
512
}
513
513
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
+
514
523
function Get-Ninja {
515
524
try {
516
525
return (Get-Command " Ninja.exe" - ErrorAction Stop).Source
@@ -522,7 +531,6 @@ function Get-Ninja {
522
531
throw " Ninja not found on Path nor in the Visual Studio Installation. Please Install Ninja to continue."
523
532
}
524
533
525
- $cmake = Get-CMake
526
534
$ninja = Get-Ninja
527
535
528
536
$NugetRoot = " $BinaryCache \nuget"
@@ -1472,9 +1480,32 @@ function Build-CMakeProject {
1472
1480
$UseCXX = $UseBuiltCompilers.Contains (" CXX" ) -or $UseMSVCCompilers.Contains (" CXX" ) -or $UsePinnedCompilers.Contains (" CXX" )
1473
1481
$UseSwift = $UseBuiltCompilers.Contains (" Swift" ) -or $UsePinnedCompilers.Contains (" Swift" )
1474
1482
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
+
1475
1501
# Add additional defines (unless already present)
1476
1502
$Defines = $Defines.Clone ()
1477
1503
1504
+ # Always enable CMP0181 if available.
1505
+ if ($CMakeSupportsCMP0181 ) {
1506
+ Add-KeyValueIfNew $Defines CMAKE_POLICY_DEFAULT_CMP0181 NEW
1507
+ }
1508
+
1478
1509
Add-KeyValueIfNew $Defines CMAKE_BUILD_TYPE Release
1479
1510
1480
1511
# Avoid specifying `CMAKE_SYSTEM_NAME` and `CMAKE_SYSTEM_PROCESSOR` on
@@ -1645,23 +1676,31 @@ function Build-CMakeProject {
1645
1676
@ (" -gnone" )
1646
1677
}
1647
1678
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
+ }
1652
1685
1653
1686
Add-FlagsDefine $Defines CMAKE_Swift_FLAGS $SwiftFlags
1654
1687
# Workaround CMake 3.26+ enabling `-wmo` by default on release builds
1655
1688
Add-FlagsDefine $Defines CMAKE_Swift_FLAGS_RELEASE " -O"
1656
1689
Add-FlagsDefine $Defines CMAKE_Swift_FLAGS_RELWITHDEBINFO " -O"
1657
- }
1658
1690
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
+ }
1663
1700
}
1664
1701
1702
+ $LinkerFlags = @ (" /INCREMENTAL:NO" , " /OPT:REF" , " /OPT:ICF" )
1703
+
1665
1704
if ($DebugInfo ) {
1666
1705
if ($UseASM -or $UseC -or $UseCXX ) {
1667
1706
# Prefer `/Z7` over `/ZI`
@@ -1671,10 +1710,14 @@ function Build-CMakeProject {
1671
1710
Add-KeyValueIfNew $Defines CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded
1672
1711
Add-KeyValueIfNew $Defines CMAKE_POLICY_DEFAULT_CMP0141 NEW
1673
1712
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" )
1678
1721
}
1679
1722
1680
1723
# The linker flags are shared across every language, and `/IGNORE:longsections` is an
@@ -1825,24 +1868,33 @@ function Build-CMakeProject {
1825
1868
$Value = $Define.Value.Replace (" \" , " /" )
1826
1869
} else {
1827
1870
# 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 (" " )) {
1836
1874
# Escape the quote so it makes it through. PowerShell 5 and Core
1837
1875
# handle quotes differently, so we need to check the version.
1838
1876
$quote = if ($PSEdition -eq " Core" ) { ' "' } else { ' \"' }
1839
- $Value += " $quote$ArgWithForwardSlashes $quote "
1877
+ " $quote$Arg $quote "
1840
1878
} else {
1841
- $Value += $ArgWithForwardSlashes
1879
+ $Arg
1842
1880
}
1843
1881
}
1844
- }
1845
1882
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
+ }
1846
1898
$cmakeGenerateArgs += @ (" -D" , " $ ( $Define.Key ) =$Value " )
1847
1899
}
1848
1900
0 commit comments