@@ -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"
@@ -1420,9 +1428,32 @@ function Build-CMakeProject {
1420
1428
$UseCXX = $UseBuiltCompilers.Contains (" CXX" ) -or $UseMSVCCompilers.Contains (" CXX" ) -or $UsePinnedCompilers.Contains (" CXX" )
1421
1429
$UseSwift = $UseBuiltCompilers.Contains (" Swift" ) -or $UsePinnedCompilers.Contains (" Swift" )
1422
1430
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
+
1423
1449
# Add additional defines (unless already present)
1424
1450
$Defines = $Defines.Clone ()
1425
1451
1452
+ # Always enable CMP0181 if available.
1453
+ if ($CMakeSupportsCMP0181 ) {
1454
+ Add-KeyValueIfNew $Defines CMAKE_POLICY_DEFAULT_CMP0181 NEW
1455
+ }
1456
+
1426
1457
Add-KeyValueIfNew $Defines CMAKE_BUILD_TYPE Release
1427
1458
1428
1459
# Avoid specifying `CMAKE_SYSTEM_NAME` and `CMAKE_SYSTEM_PROCESSOR` on
@@ -1593,23 +1624,31 @@ function Build-CMakeProject {
1593
1624
@ (" -gnone" )
1594
1625
}
1595
1626
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
+ }
1600
1633
1601
1634
Add-FlagsDefine $Defines CMAKE_Swift_FLAGS $SwiftFlags
1602
1635
# Workaround CMake 3.26+ enabling `-wmo` by default on release builds
1603
1636
Add-FlagsDefine $Defines CMAKE_Swift_FLAGS_RELEASE " -O"
1604
1637
Add-FlagsDefine $Defines CMAKE_Swift_FLAGS_RELWITHDEBINFO " -O"
1605
- }
1606
1638
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
+ }
1611
1648
}
1612
1649
1650
+ $LinkerFlags = @ (" /INCREMENTAL:NO" , " /OPT:REF" , " /OPT:ICF" )
1651
+
1613
1652
if ($DebugInfo ) {
1614
1653
if ($UseASM -or $UseC -or $UseCXX ) {
1615
1654
# Prefer `/Z7` over `/ZI`
@@ -1619,10 +1658,14 @@ function Build-CMakeProject {
1619
1658
Add-KeyValueIfNew $Defines CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded
1620
1659
Add-KeyValueIfNew $Defines CMAKE_POLICY_DEFAULT_CMP0141 NEW
1621
1660
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" )
1626
1669
}
1627
1670
1628
1671
# The linker flags are shared across every language, and `/IGNORE:longsections` is an
@@ -1772,11 +1815,27 @@ function Build-CMakeProject {
1772
1815
# Single token value, no need to quote spaces, the splat operator does the right thing.
1773
1816
$Value = $Define.Value.Replace (" \" , " /" )
1774
1817
} 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
+
1775
1821
# 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
1777
1834
foreach ($Arg in $Define.Value ) {
1778
- if ($Value.Length -gt 0 ) {
1779
- $Value += " "
1835
+ if ($FirstArg ) {
1836
+ $FirstArg = $false
1837
+ } else {
1838
+ $Value += $Separator
1780
1839
}
1781
1840
1782
1841
$ArgWithForwardSlashes = $Arg.Replace (" \" , " /" )
0 commit comments