Skip to content

Commit 89c24f6

Browse files
authored
fix an isse where usre defined DYLD_LIBRARY_PATH gets ignored (#3773)
motivation: users should be able to set DYLD_LIBRARY_PATH changes: * define new utility named EnvironmentVariables * add prependPath and appendPath helpers to EnvironmentVariables * update call sites that take [String:String] as environment variables to use the new EnvironmentVariables * fix the code in SwiftTestTool that stripped DYLD_LIBRARY_PATH to use EnvironmentVariables::appendPath which gives user's setting preference * add tests for EnvironmentVariables rdar://83607631
1 parent ecc9b05 commit 89c24f6

18 files changed

+200
-58
lines changed

Sources/Basics/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ add_library(Basics
1212
ConcurrencyHelpers.swift
1313
Dictionary+Extensions.swift
1414
DispatchTimeInterval+Extensions.swift
15+
EnvironmentVariables.swift
1516
Errors.swift
1617
FileSystem+Extensions.swift
1718
HTPClient+URLSession.swift
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright (c) 2021 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See http://swift.org/LICENSE.txt for license information
8+
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
import TSCBasic
12+
import Foundation
13+
14+
public typealias EnvironmentVariables = [String: String]
15+
16+
extension EnvironmentVariables {
17+
18+
public static func empty() -> EnvironmentVariables {
19+
return [:]
20+
}
21+
22+
public static func process() -> EnvironmentVariables {
23+
return ProcessInfo.processInfo.environment
24+
}
25+
26+
public mutating func prependPath(_ key: String, value: String) {
27+
var values = value.isEmpty ? [] : [value]
28+
if let existing = self[key], !existing.isEmpty {
29+
values.append(existing)
30+
}
31+
self.setPath(key, values)
32+
}
33+
34+
public mutating func appendPath(_ key: String, value: String) {
35+
var values = value.isEmpty ? [] : [value]
36+
if let existing = self[key], !existing.isEmpty {
37+
values.insert(existing, at: 0)
38+
}
39+
self.setPath(key, values)
40+
}
41+
42+
private mutating func setPath(_ key: String, _ values: [String]) {
43+
#if os(Windows)
44+
let delimiter = ";"
45+
#else
46+
let delimiter = ":"
47+
#endif
48+
self[key] = values.joined(separator: delimiter)
49+
}
50+
}

Sources/Build/SPMSwiftDriverExecutor.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ final class SPMSwiftDriverExecutor: DriverExecutor {
2828

2929
let resolver: ArgsResolver
3030
let fileSystem: FileSystem
31-
let env: [String: String]
31+
let env: EnvironmentVariables
3232

3333
init(resolver: ArgsResolver,
3434
fileSystem: FileSystem,
35-
env: [String: String]) {
35+
env: EnvironmentVariables) {
3636
self.resolver = resolver
3737
self.fileSystem = fileSystem
3838
self.env = env

Sources/Commands/SwiftTestTool.swift

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,11 @@ struct TestToolOptions: ParsableArguments {
5959

6060
return .runSerial
6161
}
62-
62+
6363
@Flag(name: .customLong("skip-build"),
6464
help: "Skip building the test target")
6565
var shouldSkipBuilding: Bool = false
66-
66+
6767
/// If the test target should be built before testing.
6868
var shouldBuildTests: Bool {
6969
!shouldSkipBuilding
@@ -97,7 +97,7 @@ struct TestToolOptions: ParsableArguments {
9797
if !filter.isEmpty {
9898
return .regex(filter)
9999
}
100-
100+
101101
return _testCaseSpecifier.map { .specific($0) } ?? .none
102102
}
103103

@@ -115,7 +115,7 @@ struct TestToolOptions: ParsableArguments {
115115
if let override = testCaseSkipOverride() {
116116
return override
117117
}
118-
118+
119119
return _testCaseSkip.isEmpty
120120
? .none
121121
: .skip(_testCaseSkip)
@@ -197,11 +197,11 @@ public struct SwiftTestTool: SwiftCommand {
197197

198198
@OptionGroup()
199199
var options: TestToolOptions
200-
200+
201201
var shouldEnableCodeCoverage: Bool {
202202
swiftOptions.shouldEnableCodeCoverage
203203
}
204-
204+
205205
public func run(_ swiftTool: SwiftTool) throws {
206206
// Validate commands arguments
207207
try self.validateArguments(observabilityScope: swiftTool.observabilityScope)
@@ -501,25 +501,26 @@ public struct SwiftTestTool: SwiftCommand {
501501
/// - Returns: Array of TestSuite
502502
fileprivate func getTestSuites(fromTestAt path: AbsolutePath, swiftTool: SwiftTool) throws -> [TestSuite] {
503503
// Run the correct tool.
504-
#if os(macOS)
504+
#if os(macOS)
505505
let data: String = try withTemporaryFile { tempFile in
506506
let args = [try xctestHelperPath(swiftTool: swiftTool).pathString, path.pathString, tempFile.path.pathString]
507507
var env = try constructTestEnvironment(toolchain: try swiftTool.getToolchain(), options: swiftOptions, buildParameters: swiftTool.buildParametersForTest())
508508
// Add the sdk platform path if we have it. If this is not present, we
509509
// might always end up failing.
510510
if let sdkPlatformFrameworksPath = Destination.sdkPlatformFrameworkPaths() {
511-
env["DYLD_FRAMEWORK_PATH"] = sdkPlatformFrameworksPath.fwk.pathString
512-
env["DYLD_LIBRARY_PATH"] = sdkPlatformFrameworksPath.lib.pathString
511+
// appending since we prefer the user setting (if set) to the one we inject
512+
env.appendPath("DYLD_FRAMEWORK_PATH", value: sdkPlatformFrameworksPath.fwk.pathString)
513+
env.appendPath("DYLD_LIBRARY_PATH", value: sdkPlatformFrameworksPath.lib.pathString)
513514
}
514515
try Process.checkNonZeroExit(arguments: args, environment: env)
515516
// Read the temporary file's content.
516517
return try localFileSystem.readFileContents(tempFile.path).validDescription ?? ""
517518
}
518-
#else
519+
#else
519520
let env = try constructTestEnvironment(toolchain: try swiftTool.getToolchain(), options: swiftOptions, buildParameters: swiftTool.buildParametersForTest())
520521
let args = [path.description, "--dump-tests-json"]
521522
let data = try Process.checkNonZeroExit(arguments: args, environment: env)
522-
#endif
523+
#endif
523524
// Parse json and return TestSuites.
524525
return try TestSuite.parse(jsonString: data)
525526
}
@@ -542,12 +543,12 @@ public struct SwiftTestTool: SwiftCommand {
542543
throw ExitCode.failure
543544
}
544545
}
545-
546+
546547
if options.shouldGenerateLinuxMain {
547548
observabilityScope.emit(warning: "'--generate-linuxmain' option is deprecated; tests are automatically discovered on all platforms")
548549
}
549550
}
550-
551+
551552
public init() {}
552553
}
553554

@@ -1016,8 +1017,8 @@ fileprivate func constructTestEnvironment(
10161017
toolchain: UserToolchain,
10171018
options: SwiftToolOptions,
10181019
buildParameters: BuildParameters
1019-
) throws -> [String: String] {
1020-
var env = ProcessEnv.vars
1020+
) throws -> EnvironmentVariables {
1021+
var env = EnvironmentVariables.process()
10211022

10221023
// Add the code coverage related variables.
10231024
if options.shouldEnableCodeCoverage {
@@ -1034,7 +1035,7 @@ fileprivate func constructTestEnvironment(
10341035
#if !os(macOS)
10351036
#if os(Windows)
10361037
if let location = toolchain.configuration.xctestPath {
1037-
env["Path"] = "\(location.pathString);\(env["Path"] ?? "")"
1038+
env.prependPath("Path", value: location.pathString)
10381039
}
10391040
#endif
10401041
return env

Sources/LLBuildManifest/BuildManifest.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
99
*/
1010

11+
import Basics
1112
import struct TSCBasic.AbsolutePath
1213

1314
public struct BuildManifest {
@@ -101,7 +102,7 @@ public struct BuildManifest {
101102
inputs: [Node],
102103
outputs: [Node],
103104
arguments: [String],
104-
environment: [String: String] = [:],
105+
environment: EnvironmentVariables = .empty(),
105106
workingDirectory: String? = nil,
106107
allowMissingInputs: Bool = false
107108
) {

Sources/LLBuildManifest/Tools.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
99
*/
1010

11+
import Basics
1112
import class Foundation.ProcessInfo
1213
import TSCBasic
1314

@@ -97,7 +98,7 @@ public struct ShellTool: ToolProtocol {
9798
public var inputs: [Node]
9899
public var outputs: [Node]
99100
public var arguments: [String]
100-
public var environment: [String: String]
101+
public var environment: EnvironmentVariables
101102
public var workingDirectory: String?
102103
public var allowMissingInputs: Bool
103104

@@ -106,7 +107,7 @@ public struct ShellTool: ToolProtocol {
106107
inputs: [Node],
107108
outputs: [Node],
108109
arguments: [String],
109-
environment: [String: String] = [:],
110+
environment: EnvironmentVariables = .empty(),
110111
workingDirectory: String? = nil,
111112
allowMissingInputs: Bool = false
112113
) {

Sources/PackageLoading/ManifestLoader.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -567,14 +567,14 @@ public final class ManifestLoader: ManifestLoaderProtocol {
567567
let manifestPath: AbsolutePath
568568
let manifestContents: [UInt8]
569569
let toolsVersion: ToolsVersion
570-
let env: [String: String]
570+
let env: EnvironmentVariables
571571
let swiftpmVersion: String
572572
let sha256Checksum: String
573573

574574
init (packageIdentity: PackageIdentity,
575575
manifestPath: AbsolutePath,
576576
toolsVersion: ToolsVersion,
577-
env: [String: String],
577+
env: EnvironmentVariables,
578578
swiftpmVersion: String,
579579
fileSystem: FileSystem
580580
) throws {
@@ -598,7 +598,7 @@ public final class ManifestLoader: ManifestLoaderProtocol {
598598
packageIdentity: PackageIdentity,
599599
manifestContents: [UInt8],
600600
toolsVersion: ToolsVersion,
601-
env: [String: String],
601+
env: EnvironmentVariables,
602602
swiftpmVersion: String
603603
) throws -> String {
604604
let stream = BufferedOutputByteStream()

Sources/PackageModel/ToolchainConfiguration.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
99
*/
1010

11+
import Basics
1112
import TSCBasic
1213

1314
/// Toolchain configuration required for evaluation of swift code such as the manifests or plugins
@@ -22,7 +23,7 @@ public struct ToolchainConfiguration {
2223
public var swiftCompilerFlags: [String]
2324

2425
/// Environment to pass to the Swift compiler (defaults to the inherited environment).
25-
public var swiftCompilerEnvironment: [String: String]
26+
public var swiftCompilerEnvironment: EnvironmentVariables
2627

2728
/// SwiftPM library paths.
2829
public var swiftPMLibrariesLocation: SwiftPMLibrariesLocation
@@ -47,7 +48,7 @@ public struct ToolchainConfiguration {
4748
public init(
4849
swiftCompilerPath: AbsolutePath,
4950
swiftCompilerFlags: [String] = [],
50-
swiftCompilerEnvironment: [String: String] = ProcessEnv.vars,
51+
swiftCompilerEnvironment: EnvironmentVariables = .process(),
5152
swiftPMLibrariesLocation: SwiftPMLibrariesLocation? = nil,
5253
sdkRootPath: AbsolutePath? = nil,
5354
xctestPath: AbsolutePath? = nil
@@ -69,7 +70,7 @@ public struct ToolchainConfiguration {
6970
public init(
7071
swiftCompiler: AbsolutePath,
7172
swiftCompilerFlags: [String] = [],
72-
swiftCompilerEnvironment: [String: String] = ProcessEnv.vars,
73+
swiftCompilerEnvironment: EnvironmentVariables = .process(),
7374
libDir: AbsolutePath? = nil,
7475
binDir: AbsolutePath? = nil,
7576
sdkRoot: AbsolutePath? = nil,

Sources/SPMTestSupport/XCTAssertHelpers.swift

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,14 @@
88
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
99
*/
1010

11-
import XCTest
12-
13-
import TSCBasic
14-
import TSCUtility
15-
11+
import Basics
1612
#if os(macOS)
1713
import class Foundation.Bundle
1814
#endif
19-
15+
import TSCBasic
2016
@_exported import TSCTestSupport
17+
import TSCUtility
18+
import XCTest
2119

2220
public func XCTAssertBuilds(
2321
_ path: AbsolutePath,
@@ -28,7 +26,7 @@ public func XCTAssertBuilds(
2826
Xcc: [String] = [],
2927
Xld: [String] = [],
3028
Xswiftc: [String] = [],
31-
env: [String: String]? = nil
29+
env: EnvironmentVariables? = nil
3230
) {
3331
for conf in configurations {
3432
do {
@@ -56,7 +54,7 @@ public func XCTAssertSwiftTest(
5654
_ path: AbsolutePath,
5755
file: StaticString = #file,
5856
line: UInt = #line,
59-
env: [String: String]? = nil
57+
env: EnvironmentVariables? = nil
6058
) {
6159
do {
6260
_ = try SwiftPMProduct.SwiftTest.execute([], packagePath: path, env: env)
@@ -77,7 +75,7 @@ public func XCTAssertBuildFails(
7775
Xcc: [String] = [],
7876
Xld: [String] = [],
7977
Xswiftc: [String] = [],
80-
env: [String: String]? = nil
78+
env: EnvironmentVariables? = nil
8179
) {
8280
do {
8381
_ = try executeSwiftBuild(path, Xcc: Xcc, Xld: Xld, Xswiftc: Xswiftc)

Sources/SPMTestSupport/misc.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ public func executeSwiftBuild(
147147
Xcc: [String] = [],
148148
Xld: [String] = [],
149149
Xswiftc: [String] = [],
150-
env: [String: String]? = nil
150+
env: EnvironmentVariables? = nil
151151
) throws -> (stdout: String, stderr: String) {
152152
let args = swiftArgs(configuration: configuration, extraArgs: extraArgs, Xcc: Xcc, Xld: Xld, Xswiftc: Xswiftc)
153153
return try SwiftPMProduct.SwiftBuild.execute(args, packagePath: packagePath, env: env)
@@ -162,7 +162,7 @@ public func executeSwiftRun(
162162
Xcc: [String] = [],
163163
Xld: [String] = [],
164164
Xswiftc: [String] = [],
165-
env: [String: String]? = nil
165+
env: EnvironmentVariables? = nil
166166
) throws -> (stdout: String, stderr: String) {
167167
var args = swiftArgs(configuration: configuration, extraArgs: extraArgs, Xcc: Xcc, Xld: Xld, Xswiftc: Xswiftc)
168168
args.append(executable)
@@ -177,7 +177,7 @@ public func executeSwiftPackage(
177177
Xcc: [String] = [],
178178
Xld: [String] = [],
179179
Xswiftc: [String] = [],
180-
env: [String: String]? = nil
180+
env: EnvironmentVariables? = nil
181181
) throws -> (stdout: String, stderr: String) {
182182
let args = swiftArgs(configuration: configuration, extraArgs: extraArgs, Xcc: Xcc, Xld: Xld, Xswiftc: Xswiftc)
183183
return try SwiftPMProduct.SwiftPackage.execute(args, packagePath: packagePath, env: env)
@@ -191,7 +191,7 @@ public func executeSwiftTest(
191191
Xcc: [String] = [],
192192
Xld: [String] = [],
193193
Xswiftc: [String] = [],
194-
env: [String: String]? = nil
194+
env: EnvironmentVariables? = nil
195195
) throws -> (stdout: String, stderr: String) {
196196
let args = swiftArgs(configuration: configuration, extraArgs: extraArgs, Xcc: Xcc, Xld: Xld, Xswiftc: Xswiftc)
197197
return try SwiftPMProduct.SwiftTest.execute(args, packagePath: packagePath, env: env)

0 commit comments

Comments
 (0)