Skip to content

Commit f8451c1

Browse files
authored
[Swift Build] Implement --disable-local-rpath (#9366)
Thread the option to PIF generation and set the LD_RUNPATH_SEARCH_PATHS appropriately
1 parent e1f3ce2 commit f8451c1

File tree

6 files changed

+88
-22
lines changed

6 files changed

+88
-22
lines changed

Sources/SwiftBuildSupport/PIFBuilder.swift

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,12 @@ package struct PIFBuilderParameters {
6767
/// Additional rules for including a source or resource file in a target
6868
let additionalFileRules: [FileRuleDescription]
6969

70-
package init(isPackageAccessModifierSupported: Bool, enableTestability: Bool, shouldCreateDylibForDynamicProducts: Bool, toolchainLibDir: AbsolutePath, pkgConfigDirectories: [AbsolutePath], supportedSwiftVersions: [SwiftLanguageVersion], pluginScriptRunner: PluginScriptRunner, disableSandbox: Bool, pluginWorkingDirectory: AbsolutePath, additionalFileRules: [FileRuleDescription]) {
70+
/// Add rpaths which allow loading libraries adjacent to the current image at runtime. This is desirable
71+
/// when launching build products from the build directory, but should often be disabled when deploying
72+
/// the build products to a different location.
73+
let addLocalRpaths: Bool
74+
75+
package init(isPackageAccessModifierSupported: Bool, enableTestability: Bool, shouldCreateDylibForDynamicProducts: Bool, toolchainLibDir: AbsolutePath, pkgConfigDirectories: [AbsolutePath], supportedSwiftVersions: [SwiftLanguageVersion], pluginScriptRunner: PluginScriptRunner, disableSandbox: Bool, pluginWorkingDirectory: AbsolutePath, additionalFileRules: [FileRuleDescription], addLocalRPaths: Bool) {
7176
self.isPackageAccessModifierSupported = isPackageAccessModifierSupported
7277
self.enableTestability = enableTestability
7378
self.shouldCreateDylibForDynamicProducts = shouldCreateDylibForDynamicProducts
@@ -78,6 +83,7 @@ package struct PIFBuilderParameters {
7883
self.disableSandbox = disableSandbox
7984
self.pluginWorkingDirectory = pluginWorkingDirectory
8085
self.additionalFileRules = additionalFileRules
86+
self.addLocalRpaths = addLocalRPaths
8187
}
8288
}
8389

@@ -406,6 +412,7 @@ public final class PIFBuilder {
406412
delegate: packagePIFBuilderDelegate,
407413
buildToolPluginResultsByTargetName: buildToolPluginResultsByTargetName,
408414
createDylibForDynamicProducts: self.parameters.shouldCreateDylibForDynamicProducts,
415+
addLocalRpaths: self.parameters.addLocalRpaths,
409416
packageDisplayVersion: package.manifest.displayName,
410417
fileSystem: self.fileSystem,
411418
observabilityScope: self.observabilityScope
@@ -503,7 +510,8 @@ public final class PIFBuilder {
503510
disableSandbox: Bool,
504511
pluginWorkingDirectory: AbsolutePath,
505512
pkgConfigDirectories: [Basics.AbsolutePath],
506-
additionalFileRules: [FileRuleDescription]
513+
additionalFileRules: [FileRuleDescription],
514+
addLocalRpaths: Bool
507515
) async throws -> String {
508516
let parameters = PIFBuilderParameters(
509517
buildParameters,
@@ -512,6 +520,7 @@ public final class PIFBuilder {
512520
disableSandbox: disableSandbox,
513521
pluginWorkingDirectory: pluginWorkingDirectory,
514522
additionalFileRules: additionalFileRules,
523+
addLocalRpaths: addLocalRpaths
515524
)
516525
let builder = Self(
517526
graph: packageGraph,
@@ -773,7 +782,8 @@ extension PIFBuilderParameters {
773782
pluginScriptRunner: PluginScriptRunner,
774783
disableSandbox: Bool,
775784
pluginWorkingDirectory: AbsolutePath,
776-
additionalFileRules: [FileRuleDescription]
785+
additionalFileRules: [FileRuleDescription],
786+
addLocalRpaths: Bool
777787
) {
778788
self.init(
779789
isPackageAccessModifierSupported: buildParameters.driverParameters.isPackageAccessModifierSupported,
@@ -786,6 +796,7 @@ extension PIFBuilderParameters {
786796
disableSandbox: disableSandbox,
787797
pluginWorkingDirectory: pluginWorkingDirectory,
788798
additionalFileRules: additionalFileRules,
799+
addLocalRPaths: addLocalRpaths,
789800
)
790801
}
791802
}

Sources/SwiftBuildSupport/PackagePIFBuilder.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,11 @@ public final class PackagePIFBuilder {
168168
/// * <rdar://56889224> Remove IDEPackageSupportCreateDylibsForDynamicProducts.
169169
let createDylibForDynamicProducts: Bool
170170

171+
/// Add rpaths which allow loading libraries adjacent to the current image at runtime. This is desirable
172+
/// when launching build products from the build directory, but should often be disabled when deploying
173+
/// the build products to a different location.
174+
let addLocalRpaths: Bool
175+
171176
/// Package display version, if any (i.e., it can be a version, branch or a git ref).
172177
let packageDisplayVersion: String?
173178

@@ -195,6 +200,7 @@ public final class PackagePIFBuilder {
195200
delegate: PackagePIFBuilder.BuildDelegate,
196201
buildToolPluginResultsByTargetName: [String: [BuildToolPluginInvocationResult]],
197202
createDylibForDynamicProducts: Bool = false,
203+
addLocalRpaths: Bool = true,
198204
packageDisplayVersion: String?,
199205
fileSystem: FileSystem,
200206
observabilityScope: ObservabilityScope
@@ -208,6 +214,7 @@ public final class PackagePIFBuilder {
208214
self.packageDisplayVersion = packageDisplayVersion
209215
self.fileSystem = fileSystem
210216
self.observabilityScope = observabilityScope
217+
self.addLocalRpaths = addLocalRpaths
211218
}
212219

213220
public init(
@@ -217,6 +224,7 @@ public final class PackagePIFBuilder {
217224
delegate: PackagePIFBuilder.BuildDelegate,
218225
buildToolPluginResultsByTargetName: [String: BuildToolPluginInvocationResult],
219226
createDylibForDynamicProducts: Bool = false,
227+
addLocalRpaths: Bool = true,
220228
packageDisplayVersion: String?,
221229
fileSystem: FileSystem,
222230
observabilityScope: ObservabilityScope
@@ -227,6 +235,7 @@ public final class PackagePIFBuilder {
227235
self.delegate = delegate
228236
self.buildToolPluginResultsByTargetName = buildToolPluginResultsByTargetName.mapValues { [$0] }
229237
self.createDylibForDynamicProducts = createDylibForDynamicProducts
238+
self.addLocalRpaths = addLocalRpaths
230239
self.packageDisplayVersion = packageDisplayVersion
231240
self.fileSystem = fileSystem
232241
self.observabilityScope = observabilityScope

Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Modules.swift

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -750,12 +750,21 @@ extension PackagePIFProjectBuilder {
750750
//
751751
// An imparted build setting on C will propagate back to both B and A.
752752
// FIXME: -rpath should not be given if -static is
753-
impartedSettings[.LD_RUNPATH_SEARCH_PATHS] =
754-
["$(RPATH_ORIGIN)"] +
755-
(impartedSettings[.LD_RUNPATH_SEARCH_PATHS] ?? ["$(inherited)"])
753+
var rpaths: [String] = []
754+
if let existingRpaths = impartedSettings[.LD_RUNPATH_SEARCH_PATHS] {
755+
rpaths.append(contentsOf: existingRpaths)
756+
}
757+
if pifBuilder.addLocalRpaths {
758+
rpaths.append("$(RPATH_ORIGIN)")
759+
impartedSettings[.LD_RUNPATH_SEARCH_PATHS] = rpaths + ["$(inherited)"]
760+
}
756761

757762
var impartedDebugSettings = impartedSettings
758-
impartedDebugSettings[.LD_RUNPATH_SEARCH_PATHS]! += ["$(BUILT_PRODUCTS_DIR)/PackageFrameworks"]
763+
if pifBuilder.addLocalRpaths {
764+
// FIXME: Why is this rpath only added to the debug config? We should investigate reworking this.
765+
rpaths.append("$(BUILT_PRODUCTS_DIR)/PackageFrameworks")
766+
impartedDebugSettings[.LD_RUNPATH_SEARCH_PATHS] = rpaths + ["$(inherited)"]
767+
}
759768

760769
self.project[keyPath: sourceModuleTargetKeyPath].common.addBuildConfig { id in
761770
BuildConfig(

Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Products.swift

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,13 @@ extension PackagePIFProjectBuilder {
119119

120120
if mainModule.type == .test {
121121
// FIXME: we shouldn't always include both the deep and shallow bundle paths here, but for that we'll need rdar://31867023
122-
settings[.LD_RUNPATH_SEARCH_PATHS] = [
123-
"$(RPATH_ORIGIN)/Frameworks",
124-
"$(RPATH_ORIGIN)/../Frameworks",
125-
"$(inherited)"
126-
]
122+
if pifBuilder.addLocalRpaths {
123+
settings[.LD_RUNPATH_SEARCH_PATHS] = [
124+
"$(RPATH_ORIGIN)/Frameworks",
125+
"$(RPATH_ORIGIN)/../Frameworks",
126+
"$(inherited)"
127+
]
128+
}
127129
settings[.GENERATE_INFOPLIST_FILE] = "YES"
128130
settings[.SKIP_INSTALL] = "NO"
129131
settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS].lazilyInitialize { ["$(inherited)"] }
@@ -1019,10 +1021,12 @@ extension PackagePIFProjectBuilder {
10191021

10201022
// A test-runner should always be adjacent to the dynamic library containing the tests,
10211023
// so add the appropriate rpaths.
1022-
settings[.LD_RUNPATH_SEARCH_PATHS] = [
1023-
"$(inherited)",
1024-
"$(RPATH_ORIGIN)"
1025-
]
1024+
if pifBuilder.addLocalRpaths {
1025+
settings[.LD_RUNPATH_SEARCH_PATHS] = [
1026+
"$(inherited)",
1027+
"$(RPATH_ORIGIN)"
1028+
]
1029+
}
10261030

10271031
let deploymentTargets = unitTestProduct.deploymentTargets
10281032
settings[.MACOSX_DEPLOYMENT_TARGET] = deploymentTargets?[.macOS] ?? nil

Sources/SwiftBuildSupport/SwiftBuildSystem.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,7 +1095,6 @@ public final class SwiftBuildSystem: SPMBuildCore.BuildSystem {
10951095
break
10961096
}
10971097

1098-
// TODO: shouldDisableLocalRpath
10991098
// TODO: shouldLinkStaticSwiftStdlib
11001099

11011100
return settings
@@ -1161,7 +1160,8 @@ public final class SwiftBuildSystem: SPMBuildCore.BuildSystem {
11611160
pluginScriptRunner: self.pluginConfiguration.scriptRunner,
11621161
disableSandbox: self.pluginConfiguration.disableSandbox,
11631162
pluginWorkingDirectory: self.pluginConfiguration.workDirectory,
1164-
additionalFileRules: additionalFileRules
1163+
additionalFileRules: additionalFileRules,
1164+
addLocalRpaths: !self.buildParameters.linkingParameters.shouldDisableLocalRpath
11651165
),
11661166
fileSystem: self.fileSystem,
11671167
observabilityScope: self.observabilityScope,

Tests/SwiftBuildSupportTests/PIFBuilderTests.swift

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import _InternalTestSupport
2222
import Workspace
2323

2424
extension PIFBuilderParameters {
25-
fileprivate static func constructDefaultParametersForTesting(temporaryDirectory: Basics.AbsolutePath) throws -> Self {
25+
fileprivate static func constructDefaultParametersForTesting(temporaryDirectory: Basics.AbsolutePath, addLocalRpaths: Bool) throws -> Self {
2626
self.init(
2727
isPackageAccessModifierSupported: true,
2828
enableTestability: false,
@@ -37,12 +37,13 @@ extension PIFBuilderParameters {
3737
),
3838
disableSandbox: false,
3939
pluginWorkingDirectory: temporaryDirectory.appending(component: "plugin-working-dir"),
40-
additionalFileRules: []
40+
additionalFileRules: [],
41+
addLocalRPaths: addLocalRpaths
4142
)
4243
}
4344
}
4445

45-
fileprivate func withGeneratedPIF(fromFixture fixtureName: String, do doIt: (SwiftBuildSupport.PIF.TopLevelObject, TestingObservability) async throws -> ()) async throws {
46+
fileprivate func withGeneratedPIF(fromFixture fixtureName: String, addLocalRpaths: Bool = true, do doIt: (SwiftBuildSupport.PIF.TopLevelObject, TestingObservability) async throws -> ()) async throws {
4647
try await fixture(name: fixtureName) { fixturePath in
4748
let observabilitySystem = ObservabilitySystem.makeForTesting()
4849
let workspace = try Workspace(
@@ -58,7 +59,7 @@ fileprivate func withGeneratedPIF(fromFixture fixtureName: String, do doIt: (Swi
5859
)
5960
let builder = PIFBuilder(
6061
graph: graph,
61-
parameters: try PIFBuilderParameters.constructDefaultParametersForTesting(temporaryDirectory: fixturePath),
62+
parameters: try PIFBuilderParameters.constructDefaultParametersForTesting(temporaryDirectory: fixturePath, addLocalRpaths: addLocalRpaths),
6263
fileSystem: localFileSystem,
6364
observabilityScope: observabilitySystem.topScope
6465
)
@@ -238,4 +239,36 @@ struct PIFBuilderTests {
238239
}
239240
}
240241
}
242+
243+
@Test func disablingLocalRpaths() async throws {
244+
try await withGeneratedPIF(fromFixture: "Miscellaneous/Simple") { pif, observabilitySystem in
245+
#expect(observabilitySystem.diagnostics.filter {
246+
$0.severity == .error
247+
}.isEmpty)
248+
249+
do {
250+
let releaseConfig = try pif.workspace
251+
.project(named: "Foo")
252+
.target(named: "Foo")
253+
.buildConfig(named: "Release")
254+
255+
#expect(releaseConfig.impartedBuildProperties.settings[.LD_RUNPATH_SEARCH_PATHS] == ["$(RPATH_ORIGIN)", "$(inherited)"])
256+
}
257+
}
258+
259+
try await withGeneratedPIF(fromFixture: "Miscellaneous/Simple", addLocalRpaths: false) { pif, observabilitySystem in
260+
#expect(observabilitySystem.diagnostics.filter {
261+
$0.severity == .error
262+
}.isEmpty)
263+
264+
do {
265+
let releaseConfig = try pif.workspace
266+
.project(named: "Foo")
267+
.target(named: "Foo")
268+
.buildConfig(named: "Release")
269+
270+
#expect(releaseConfig.impartedBuildProperties.settings[.LD_RUNPATH_SEARCH_PATHS] == nil)
271+
}
272+
}
273+
}
241274
}

0 commit comments

Comments
 (0)