Skip to content

Commit fc1b37a

Browse files
authored
Don't link libc++ or libstd++ for Embedded Swift (#7357)
These libraries are not usually available for embedded platforms. A workaround of passing this flag via `unsafeFlags` in `Package.swift` still remains after this change.
1 parent 2a01f6e commit fc1b37a

File tree

4 files changed

+117
-17
lines changed

4 files changed

+117
-17
lines changed

Sources/Build/BuildPlan/BuildPlan+Product.swift

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ import struct PackageGraph.ResolvedProduct
1717
import struct PackageGraph.ResolvedTarget
1818
import class PackageModel.BinaryTarget
1919
import class PackageModel.ClangTarget
20+
21+
@_spi(SwiftPMInternal)
2022
import class PackageModel.Target
23+
2124
import class PackageModel.SwiftTarget
2225
import class PackageModel.SystemLibraryTarget
2326
import struct SPMBuildCore.BuildParameters
@@ -28,7 +31,10 @@ extension BuildPlan {
2831
/// Plan a product.
2932
func plan(buildProduct: ProductBuildDescription) throws {
3033
// Compute the product's dependency.
31-
let dependencies = try computeDependencies(of: buildProduct.product, buildParameters: buildProduct.buildParameters)
34+
let dependencies = try computeDependencies(
35+
of: buildProduct.product,
36+
buildParameters: buildProduct.buildParameters
37+
)
3238

3339
// Add flags for system targets.
3440
for systemModule in dependencies.systemModules {
@@ -50,19 +56,24 @@ extension BuildPlan {
5056
}
5157
}
5258

53-
// Link C++ if needed.
54-
// Note: This will come from build settings in future.
55-
for target in dependencies.staticTargets {
56-
if case let target as ClangTarget = target.underlying, target.isCXX {
57-
let triple = buildProduct.buildParameters.triple
58-
if triple.isDarwin() {
59-
buildProduct.additionalFlags += ["-lc++"]
60-
} else if triple.isWindows() {
61-
// Don't link any C++ library.
62-
} else {
63-
buildProduct.additionalFlags += ["-lstdc++"]
59+
// Don't link libc++ or libstd++ when building for Embedded Swift.
60+
// Users can still link it manually for embedded platforms when needed,
61+
// by providing `-Xlinker -lc++` options via CLI or `Package.swift`.
62+
if !buildProduct.product.targets.contains(where: \.underlying.isEmbeddedSwiftTarget) {
63+
// Link C++ if needed.
64+
// Note: This will come from build settings in future.
65+
for target in dependencies.staticTargets {
66+
if case let target as ClangTarget = target.underlying, target.isCXX {
67+
let triple = buildProduct.buildParameters.triple
68+
if triple.isDarwin() {
69+
buildProduct.additionalFlags += ["-lc++"]
70+
} else if triple.isWindows() {
71+
// Don't link any C++ library.
72+
} else {
73+
buildProduct.additionalFlags += ["-lstdc++"]
74+
}
75+
break
6476
}
65-
break
6677
}
6778
}
6879

Sources/PackageModel/Target/Target.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,15 @@ public class Target: PolymorphicCodableProtocol {
339339
self.pluginUsages = []
340340
self.usesUnsafeFlags = try container.decode(Bool.self, forKey: .usesUnsafeFlags)
341341
}
342+
343+
@_spi(SwiftPMInternal)
344+
public var isEmbeddedSwiftTarget: Bool {
345+
for case .enableExperimentalFeature("Embedded") in self.buildSettingsDescription.swiftSettings.map(\.kind) {
346+
return true
347+
}
348+
349+
return false
350+
}
342351
}
343352

344353
extension Target: Hashable {
@@ -371,3 +380,10 @@ public extension Sequence where Iterator.Element == Target {
371380
}
372381
}
373382
}
383+
384+
extension [TargetBuildSettingDescription.Setting] {
385+
@_spi(SwiftPMInternal)
386+
public var swiftSettings: Self {
387+
self.filter { $0.tool == .swift }
388+
}
389+
}

Sources/SPMTestSupport/MockPackageGraphs.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,46 @@ public func trivialPackageGraph(pkgRootPath: AbsolutePath) throws -> MockPackage
156156

157157
return (graph, fs, observability.topScope)
158158
}
159+
160+
@_spi(SwiftPMInternal)
161+
public func embeddedCxxInteropPackageGraph(pkgRootPath: AbsolutePath) throws -> MockPackageGraph {
162+
let fs = InMemoryFileSystem(
163+
emptyFiles:
164+
"/Pkg/Sources/app/main.swift",
165+
"/Pkg/Sources/lib/lib.cpp",
166+
"/Pkg/Sources/lib/include/lib.h",
167+
"/Pkg/Tests/test/TestCase.swift"
168+
)
169+
170+
let observability = ObservabilitySystem.makeForTesting()
171+
let graph = try loadPackageGraph(
172+
fileSystem: fs,
173+
manifests: [
174+
Manifest.createRootManifest(
175+
displayName: "Pkg",
176+
path: "/Pkg",
177+
targets: [
178+
TargetDescription(
179+
name: "app",
180+
dependencies: ["lib"],
181+
settings: [.init(tool: .swift, kind: .enableExperimentalFeature("Embedded"))]
182+
),
183+
TargetDescription(
184+
name: "lib",
185+
dependencies: [],
186+
settings: [.init(tool: .swift, kind: .interoperabilityMode(.Cxx))]
187+
),
188+
TargetDescription(
189+
name: "test",
190+
dependencies: ["lib"],
191+
type: .test
192+
),
193+
]
194+
),
195+
],
196+
observabilityScope: observability.topScope
197+
)
198+
XCTAssertNoDiagnostics(observability.diagnostics)
199+
200+
return (graph, fs, observability.topScope)
201+
}

Tests/BuildTests/CrossCompilationBuildPlanTests.swift

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ import class PackageModel.Manifest
2020
import struct PackageModel.TargetDescription
2121
import func SPMTestSupport.loadPackageGraph
2222

23+
@_spi(SwiftPMInternal)
24+
import func SPMTestSupport.embeddedCxxInteropPackageGraph
25+
2326
@_spi(SwiftPMInternal)
2427
import func SPMTestSupport.macrosPackageGraph
2528

@@ -37,13 +40,12 @@ import XCTest
3740

3841
final class CrossCompilationBuildPlanTests: XCTestCase {
3942
func testEmbeddedWasmTarget() throws {
40-
let pkgPath = AbsolutePath("/Pkg")
41-
let (graph, fs, observabilityScope) = try trivialPackageGraph(pkgRootPath: pkgPath)
43+
var (graph, fs, observabilityScope) = try trivialPackageGraph(pkgRootPath: "/Pkg")
4244

4345
let triple = try Triple("wasm32-unknown-none-wasm")
4446
var parameters = mockBuildParameters(targetTriple: triple)
4547
parameters.linkingParameters.shouldLinkStaticSwiftStdlib = true
46-
let result = try BuildPlanResult(plan: BuildPlan(
48+
var result = try BuildPlanResult(plan: BuildPlan(
4749
buildParameters: parameters,
4850
graph: graph,
4951
fileSystem: fs,
@@ -55,7 +57,34 @@ final class CrossCompilationBuildPlanTests: XCTestCase {
5557
result.checkTargetsCount(5)
5658

5759
let buildPath = result.plan.productsBuildPath
58-
let appBuildDescription = try result.buildProduct(for: "app")
60+
var appBuildDescription = try result.buildProduct(for: "app")
61+
XCTAssertEqual(
62+
try appBuildDescription.linkArguments(),
63+
[
64+
result.plan.destinationBuildParameters.toolchain.swiftCompilerPath.pathString,
65+
"-L", buildPath.pathString,
66+
"-o", buildPath.appending(components: "app.wasm").pathString,
67+
"-module-name", "app", "-static-stdlib", "-emit-executable",
68+
"@\(buildPath.appending(components: "app.product", "Objects.LinkFileList"))",
69+
"-target", triple.tripleString,
70+
"-g",
71+
]
72+
)
73+
74+
(graph, fs, observabilityScope) = try embeddedCxxInteropPackageGraph(pkgRootPath: "/Pkg")
75+
76+
result = try BuildPlanResult(plan: BuildPlan(
77+
buildParameters: parameters,
78+
graph: graph,
79+
fileSystem: fs,
80+
observabilityScope: observabilityScope
81+
))
82+
result.checkProductsCount(2)
83+
// There are two additional targets on non-Apple platforms, for test discovery and
84+
// test entry point
85+
result.checkTargetsCount(5)
86+
87+
appBuildDescription = try result.buildProduct(for: "app")
5988
XCTAssertEqual(
6089
try appBuildDescription.linkArguments(),
6190
[
@@ -64,6 +93,7 @@ final class CrossCompilationBuildPlanTests: XCTestCase {
6493
"-o", buildPath.appending(components: "app.wasm").pathString,
6594
"-module-name", "app", "-static-stdlib", "-emit-executable",
6695
"@\(buildPath.appending(components: "app.product", "Objects.LinkFileList"))",
96+
"-enable-experimental-feature", "Embedded",
6797
"-target", triple.tripleString,
6898
"-g",
6999
]

0 commit comments

Comments
 (0)