Skip to content

Commit 8fc6189

Browse files
committed
Build: pass through Embedded flag to link jobs
Without passing this flag, Swift Driver links such products as if they're not built for embedded platforms at all, passing incorrect flags to the linker. This is not reproducible when using plain `swiftc`, as that combines both compile and link jobs by default, but SwiftPM prefers to run those separately, which requires this special handling. ### Modifications: Directly checking in `ProductBuildDescription/linkArguments` whether all of the product's targets are built in the embedded mode. If so, we're passing the embedded mode flag to Swift Driver. Unfortunately, `BuildSettings.AssignmentTable` is formed too early in the build process right in `PackageModel`, while we still need to run checks specific build settings quite late in the build stage. Because of that, there's no clean way to check if `Embedded` flag is passed other than directly rendering `BuildSettings.Scope` to a string and running a substring check on that. In the future we should move `BuildSettings` out of `PackageModel`, ensuring that SwiftPM clients don't rely on this behavior anymore. ### Result: Products that have targets using Embedded Swift can be built with SwiftPM, assuming that Swift Driver handles other linker flags correctly.
1 parent 3e8328e commit 8fc6189

File tree

2 files changed

+96
-7
lines changed

2 files changed

+96
-7
lines changed

Sources/Build/BuildDescription/ProductBuildDescription.swift

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription
198198
// No arguments for static libraries.
199199
return []
200200
case .test:
201-
// Test products are bundle when using objectiveC, executable when using test entry point.
201+
// Test products are bundle when using Objective-C, executable when using test entry point.
202202
switch self.buildParameters.testingParameters.testProductStyle {
203203
case .loadableBundle:
204204
args += ["-Xlinker", "-bundle"]
@@ -271,8 +271,24 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription
271271
}
272272
args += ["@\(self.linkFileListPath.pathString)"]
273273

274-
// Embed the swift stdlib library path inside tests and executables on Darwin.
275274
if containsSwiftTargets {
275+
// A product is embedded if all of its static targets are embedded.
276+
var isEmbeddedProduct = true
277+
278+
for target in self.product.targets {
279+
let flags = self.buildParameters.createScope(for: target).evaluate(.OTHER_SWIFT_FLAGS)
280+
281+
// FIXME: update this comparison to use `contains` on `Collection` when macOS 13 is available.
282+
if !flags.joined(separator: " ").contains("-enable-experimental-feature Embedded") {
283+
isEmbeddedProduct = false
284+
break
285+
}
286+
}
287+
if isEmbeddedProduct {
288+
args += ["-enable-experimental-feature", "Embedded"]
289+
}
290+
291+
// Embed the swift stdlib library path inside tests and executables on Darwin.
276292
let useStdlibRpath: Bool
277293
switch self.product.type {
278294
case .library(let type):
@@ -297,11 +313,9 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription
297313
args += ["-Xlinker", "-rpath", "-Xlinker", backDeployedStdlib.pathString]
298314
}
299315
}
300-
}
301-
302-
// Don't link runtime compatibility patch libraries if there are no
303-
// Swift sources in the target.
304-
if !containsSwiftTargets {
316+
} else {
317+
// Don't link runtime compatibility patch libraries if there are no
318+
// Swift sources in the target.
305319
args += ["-runtime-compatibility-version", "none"]
306320
}
307321

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2014-2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
@testable
14+
import Build
15+
16+
import class Basics.ObservabilitySystem
17+
import class TSCBasic.InMemoryFileSystem
18+
19+
import class PackageModel.Manifest
20+
import struct PackageModel.TargetDescription
21+
22+
@testable
23+
import struct PackageGraph.ResolvedProduct
24+
25+
import func SPMTestSupport.loadPackageGraph
26+
import func SPMTestSupport.mockBuildParameters
27+
import func SPMTestSupport.XCTAssertNoDiagnostics
28+
import XCTest
29+
30+
final class ProductBuildDescriptionTests: XCTestCase {
31+
func testEmbeddedProducts() throws {
32+
let fs = InMemoryFileSystem(
33+
emptyFiles:
34+
"/Pkg/Sources/exe/main.swift"
35+
)
36+
37+
let observability = ObservabilitySystem.makeForTesting()
38+
let graph = try loadPackageGraph(
39+
fileSystem: fs,
40+
manifests: [
41+
Manifest.createRootManifest(
42+
displayName: "Pkg",
43+
path: "/Pkg",
44+
targets: [
45+
TargetDescription(
46+
name: "exe",
47+
settings: [.init(tool: .swift, kind: .enableExperimentalFeature("Embedded"))]
48+
),
49+
]
50+
),
51+
],
52+
observabilityScope: observability.topScope
53+
)
54+
XCTAssertNoDiagnostics(observability.diagnostics)
55+
56+
let id = ResolvedProduct.ID(targetName: "exe", packageIdentity: .plain("pkg"), buildTriple: .destination)
57+
let package = try XCTUnwrap(graph.rootPackages.first)
58+
let product = try XCTUnwrap(graph.allProducts[id])
59+
60+
let buildDescription = try ProductBuildDescription(
61+
package: package,
62+
product: product,
63+
toolsVersion: .v5_9,
64+
buildParameters: mockBuildParameters(environment: .init(platform: .macOS)),
65+
fileSystem: fs,
66+
observabilityScope: observability.topScope
67+
)
68+
69+
XCTAssertTrue(
70+
try buildDescription.linkArguments()
71+
.joined(separator: " ")
72+
.contains("-enable-experimental-feature Embedded")
73+
)
74+
}
75+
}

0 commit comments

Comments
 (0)