Skip to content

Commit 38e21a2

Browse files
authored
Add an rpath flag to disable the default of looking in the local directory for shared libraries (#6947)
This is useful when deploying build products, as most executables are not installed in the same directory as libraries and system libraries do not need it for system paths. Use the new flag when installing SwiftPM itself and the {Manifest,Plugin}API libraries on ELF platforms. On linux, I currently see this with Swift 5.9: ``` > readelf -d swift-5.9-RELEASE-ubuntu20.04/usr/lib/swift/pm/*I/lib*so swift-5.9-RELEASE-ubuntu20.04/usr/bin/swift-package|ag "File:|runpath" File: swift-5.9-RELEASE-ubuntu20.04/usr/lib/swift/pm/ManifestAPI/libPackageDescription.so 0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN:$ORIGIN/../../linux] File: swift-5.9-RELEASE-ubuntu20.04/usr/lib/swift/pm/PluginAPI/libPackagePlugin.so 0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN:$ORIGIN/../../linux] File: swift-5.9-RELEASE-ubuntu20.04/usr/bin/swift-package 0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN:$ORIGIN/../lib/swift/linux] ``` After applying this pull to trunk on Android, the extraneous rpath is gone: ``` > llvm-readelf -d build/Ninja-Release/toolchain-android-aarch64/usr/lib/swift/pm/*I/lib*so build/Ninja-Release/toolchain-android-aarch64/usr/bin/swift-package|ag "File:|runpath" File: build/Ninja-Release/toolchain-android-aarch64/usr/lib/swift/pm/ManifestAPI/libPackageDescription.so 0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN/../../android] File: build/Ninja-Release/toolchain-android-aarch64/usr/lib/swift/pm/PluginAPI/libPackagePlugin.so 0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN/../../android] File: build/Ninja-Release/toolchain-android-aarch64/usr/bin/swift-package 0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN/../lib/swift/android:/data/data/com.termux/files/usr/lib] ``` I have no idea if this is useful on Darwin too, but I went ahead and disabled adding `@loader_rpath` too. Let me know if that's worthwhile.
1 parent 052c298 commit 38e21a2

File tree

8 files changed

+111
-8
lines changed

8 files changed

+111
-8
lines changed

Sources/Build/BuildDescription/ProductBuildDescription.swift

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -257,12 +257,14 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription
257257
}
258258

259259
// Set rpath such that dynamic libraries are looked up
260-
// adjacent to the product.
261-
if self.buildParameters.targetTriple.isLinux() {
262-
args += ["-Xlinker", "-rpath=$ORIGIN"]
263-
} else if self.buildParameters.targetTriple.isDarwin() {
264-
let rpath = self.product.type == .test ? "@loader_path/../../../" : "@loader_path"
265-
args += ["-Xlinker", "-rpath", "-Xlinker", rpath]
260+
// adjacent to the product, unless overridden.
261+
if !self.buildParameters.shouldDisableLocalRpath {
262+
if self.buildParameters.targetTriple.isLinux() {
263+
args += ["-Xlinker", "-rpath=$ORIGIN"]
264+
} else if self.buildParameters.targetTriple.isDarwin() {
265+
let rpath = self.product.type == .test ? "@loader_path/../../../" : "@loader_path"
266+
args += ["-Xlinker", "-rpath", "-Xlinker", rpath]
267+
}
266268
}
267269
args += ["@\(self.linkFileListPath.pathString)"]
268270

Sources/CoreCommands/Options.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,10 @@ public struct LinkerOptions: ParsableArguments {
524524
/// If should link the Swift stdlib statically.
525525
@Flag(name: .customLong("static-swift-stdlib"), inversion: .prefixedNo, help: "Link Swift stdlib statically")
526526
public var shouldLinkStaticSwiftStdlib: Bool = false
527+
528+
/// Disables adding $ORIGIN/@loader_path to the rpath, useful when deploying
529+
@Flag(name: .customLong("disable-local-rpath"), help: "Disable adding $ORIGIN/@loader_path to the rpath by default")
530+
public var shouldDisableLocalRpath: Bool = false
527531
}
528532

529533
// MARK: - Extensions

Sources/CoreCommands/SwiftTool.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,7 @@ public final class SwiftTool {
683683
architectures: options.build.architectures,
684684
workers: options.build.jobs ?? UInt32(ProcessInfo.processInfo.activeProcessorCount),
685685
shouldLinkStaticSwiftStdlib: options.linker.shouldLinkStaticSwiftStdlib,
686+
shouldDisableLocalRpath: options.linker.shouldDisableLocalRpath,
686687
canRenameEntrypointFunctionName: driverSupport.checkSupportedFrontendFlags(
687688
flags: ["entry-point-function-name"],
688689
toolchain: toolchain,

Sources/SPMBuildCore/BuildParameters.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ public struct BuildParameters: Encodable {
190190
/// If should link the Swift stdlib statically.
191191
public var shouldLinkStaticSwiftStdlib: Bool
192192

193+
/// Disables adding $ORIGIN/@loader_path to the rpath, useful when deploying
194+
public var shouldDisableLocalRpath: Bool
195+
193196
/// Which compiler sanitizers should be enabled
194197
public var sanitizers: EnabledSanitizers
195198

@@ -362,6 +365,7 @@ public struct BuildParameters: Encodable {
362365
architectures: [String]? = nil,
363366
workers: UInt32 = UInt32(ProcessInfo.processInfo.activeProcessorCount),
364367
shouldLinkStaticSwiftStdlib: Bool = false,
368+
shouldDisableLocalRpath: Bool = false,
365369
shouldEnableManifestCaching: Bool = false,
366370
canRenameEntrypointFunctionName: Bool = false,
367371
shouldCreateDylibForDynamicProducts: Bool = true,
@@ -424,6 +428,7 @@ public struct BuildParameters: Encodable {
424428
self.architectures = architectures
425429
self.workers = workers
426430
self.shouldLinkStaticSwiftStdlib = shouldLinkStaticSwiftStdlib
431+
self.shouldDisableLocalRpath = shouldDisableLocalRpath
427432
self.shouldEnableManifestCaching = shouldEnableManifestCaching
428433
self.shouldCreateDylibForDynamicProducts = shouldCreateDylibForDynamicProducts
429434
self.canRenameEntrypointFunctionName = canRenameEntrypointFunctionName
@@ -487,6 +492,7 @@ public struct BuildParameters: Encodable {
487492
architectures: nil,
488493
workers: self.workers,
489494
shouldLinkStaticSwiftStdlib: self.shouldLinkStaticSwiftStdlib,
495+
shouldDisableLocalRpath: self.shouldDisableLocalRpath,
490496
shouldEnableManifestCaching: self.shouldEnableManifestCaching,
491497
canRenameEntrypointFunctionName: self.canRenameEntrypointFunctionName,
492498
shouldCreateDylibForDynamicProducts: self.shouldCreateDylibForDynamicProducts,

Sources/swift-bootstrap/main.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ struct SwiftBootstrapBuildTool: ParsableCommand {
118118
case error
119119
}
120120

121+
/// Disables adding $ORIGIN/@loader_path to the rpath, useful when deploying
122+
@Flag(name: .customLong("disable-local-rpath"), help: "Disable adding $ORIGIN/@loader_path to the rpath by default")
123+
public var shouldDisableLocalRpath: Bool = false
124+
121125
private var buildSystem: BuildSystemProvider.Kind {
122126
#if os(macOS)
123127
// Force the Xcode build system if we want to build more than one arch.
@@ -188,7 +192,8 @@ struct SwiftBootstrapBuildTool: ParsableCommand {
188192
buildFlags: self.buildFlags,
189193
manifestBuildFlags: self.manifestFlags,
190194
useIntegratedSwiftDriver: self.useIntegratedSwiftDriver,
191-
explicitTargetDependencyImportCheck: self.explicitTargetDependencyImportCheck
195+
explicitTargetDependencyImportCheck: self.explicitTargetDependencyImportCheck,
196+
shouldDisableLocalRpath: self.shouldDisableLocalRpath
192197
)
193198
} catch _ as Diagnostics {
194199
throw ExitCode.failure
@@ -232,7 +237,8 @@ struct SwiftBootstrapBuildTool: ParsableCommand {
232237
buildFlags: BuildFlags,
233238
manifestBuildFlags: [String],
234239
useIntegratedSwiftDriver: Bool,
235-
explicitTargetDependencyImportCheck: TargetDependencyImportCheckingMode
240+
explicitTargetDependencyImportCheck: TargetDependencyImportCheckingMode,
241+
shouldDisableLocalRpath: Bool
236242
) throws {
237243
let buildSystem = try createBuildSystem(
238244
packagePath: packagePath,
@@ -244,6 +250,7 @@ struct SwiftBootstrapBuildTool: ParsableCommand {
244250
manifestBuildFlags: manifestBuildFlags,
245251
useIntegratedSwiftDriver: useIntegratedSwiftDriver,
246252
explicitTargetDependencyImportCheck: explicitTargetDependencyImportCheck,
253+
shouldDisableLocalRpath: shouldDisableLocalRpath,
247254
logLevel: logLevel
248255
)
249256
try buildSystem.build(subset: .allExcludingTests)
@@ -259,6 +266,7 @@ struct SwiftBootstrapBuildTool: ParsableCommand {
259266
manifestBuildFlags: [String],
260267
useIntegratedSwiftDriver: Bool,
261268
explicitTargetDependencyImportCheck: TargetDependencyImportCheckingMode,
269+
shouldDisableLocalRpath: Bool,
262270
logLevel: Basics.Diagnostic.Severity
263271
) throws -> BuildSystem {
264272

@@ -277,6 +285,7 @@ struct SwiftBootstrapBuildTool: ParsableCommand {
277285
targetTriple: self.targetToolchain.targetTriple,
278286
flags: buildFlags,
279287
architectures: architectures,
288+
shouldDisableLocalRpath: shouldDisableLocalRpath,
280289
useIntegratedSwiftDriver: useIntegratedSwiftDriver,
281290
isXcodeBuildSystemEnabled: buildSystem == .xcode,
282291
explicitTargetDependencyImportCheckingMode: explicitTargetDependencyImportCheck == .error ? .error : .none,

Tests/BuildTests/BuildPlanTests.swift

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5021,4 +5021,80 @@ final class BuildPlanTests: XCTestCase {
50215021
XCTFail("expected a Swift target")
50225022
}
50235023
}
5024+
5025+
func testBasicSwiftPackageWithoutLocalRpath() throws {
5026+
let fs = InMemoryFileSystem(emptyFiles:
5027+
"/Pkg/Sources/exe/main.swift",
5028+
"/Pkg/Sources/lib/lib.swift"
5029+
)
5030+
5031+
let observability = ObservabilitySystem.makeForTesting()
5032+
let graph = try loadPackageGraph(
5033+
fileSystem: fs,
5034+
manifests: [
5035+
Manifest.createRootManifest(
5036+
displayName: "Pkg",
5037+
path: "/Pkg",
5038+
targets: [
5039+
TargetDescription(name: "exe", dependencies: ["lib"]),
5040+
TargetDescription(name: "lib", dependencies: []),
5041+
]),
5042+
],
5043+
observabilityScope: observability.topScope
5044+
)
5045+
XCTAssertNoDiagnostics(observability.diagnostics)
5046+
5047+
let result = try BuildPlanResult(plan: BuildPlan(
5048+
buildParameters: mockBuildParameters(shouldDisableLocalRpath: true),
5049+
graph: graph,
5050+
fileSystem: fs,
5051+
observabilityScope: observability.topScope
5052+
))
5053+
5054+
result.checkProductsCount(1)
5055+
result.checkTargetsCount(2)
5056+
5057+
let buildPath = result.plan.buildParameters.dataPath.appending(components: "debug")
5058+
5059+
#if os(macOS)
5060+
let linkArguments = [
5061+
result.plan.buildParameters.toolchain.swiftCompilerPath.pathString,
5062+
"-L", buildPath.pathString,
5063+
"-o", buildPath.appending(components: "exe").pathString,
5064+
"-module-name", "exe",
5065+
"-emit-executable",
5066+
"@\(buildPath.appending(components: "exe.product", "Objects.LinkFileList"))",
5067+
"-Xlinker", "-rpath", "-Xlinker", "/fake/path/lib/swift-5.5/macosx",
5068+
"-target", defaultTargetTriple,
5069+
"-Xlinker", "-add_ast_path", "-Xlinker", buildPath.appending(components: "exe.build", "exe.swiftmodule").pathString,
5070+
"-Xlinker", "-add_ast_path", "-Xlinker", buildPath.appending(components: "lib.swiftmodule").pathString,
5071+
"-g",
5072+
]
5073+
#elseif os(Windows)
5074+
let linkArguments = [
5075+
result.plan.buildParameters.toolchain.swiftCompilerPath.pathString,
5076+
"-L", buildPath.pathString,
5077+
"-o", buildPath.appending(components: "exe.exe").pathString,
5078+
"-module-name", "exe",
5079+
"-emit-executable",
5080+
"@\(buildPath.appending(components: "exe.product", "Objects.LinkFileList"))",
5081+
"-target", defaultTargetTriple,
5082+
"-g", "-use-ld=lld", "-Xlinker", "-debug:dwarf",
5083+
]
5084+
#else
5085+
let linkArguments = [
5086+
result.plan.buildParameters.toolchain.swiftCompilerPath.pathString,
5087+
"-L", buildPath.pathString,
5088+
"-o", buildPath.appending(components: "exe").pathString,
5089+
"-module-name", "exe",
5090+
"-emit-executable",
5091+
"@\(buildPath.appending(components: "exe.product", "Objects.LinkFileList"))",
5092+
"-target", defaultTargetTriple,
5093+
"-g"
5094+
]
5095+
#endif
5096+
5097+
XCTAssertEqual(try result.buildProduct(for: "exe").linkArguments(), linkArguments)
5098+
XCTAssertNoDiagnostics(observability.diagnostics)
5099+
}
50245100
}

Tests/BuildTests/MockBuildTestHelper.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ func mockBuildParameters(
7272
toolchain: PackageModel.Toolchain = MockToolchain(),
7373
flags: PackageModel.BuildFlags = PackageModel.BuildFlags(),
7474
shouldLinkStaticSwiftStdlib: Bool = false,
75+
shouldDisableLocalRpath: Bool = false,
7576
canRenameEntrypointFunctionName: Bool = false,
7677
targetTriple: Basics.Triple = hostTriple,
7778
indexStoreMode: BuildParameters.IndexStoreMode = .off,
@@ -89,6 +90,7 @@ func mockBuildParameters(
8990
pkgConfigDirectories: [],
9091
workers: 3,
9192
shouldLinkStaticSwiftStdlib: shouldLinkStaticSwiftStdlib,
93+
shouldDisableLocalRpath: shouldDisableLocalRpath,
9294
canRenameEntrypointFunctionName: canRenameEntrypointFunctionName,
9395
indexStoreMode: indexStoreMode,
9496
useExplicitModuleBuild: useExplicitModuleBuild,

Utilities/bootstrap

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,9 @@ def get_swiftpm_flags(args):
769769
"--configuration", "release",
770770
])
771771

772+
if not '-macosx' in args.build_target and args.command == 'install':
773+
build_flags.append("--disable-local-rpath")
774+
772775
if args.verbose:
773776
build_flags.append("--verbose")
774777

0 commit comments

Comments
 (0)