Skip to content

Commit 1863e35

Browse files
authored
Add --pkg-config-path to LocationOptions (#5949)
Resolves #5815. Having a specific `--pkg-config-path` option for this means we have something that's less fragile and easier to report errors on than `PKG_CONFIG_PATH` environment variable. Added `pkgConfigDirectory` to `LocationOptions`, which is propagated to `BuildPlan` as a function or initializer argument.
1 parent aa08975 commit 1863e35

19 files changed

+212
-54
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ Note: This is in reverse chronological order, so newer entries are added to the
33
Swift 5.8
44
-----------
55

6+
* [#5949]
7+
8+
New `--pkg-config-path` option on `build`, `test`, and `run` commands has been
9+
introduced as an alternative to passing `PKG_CONFIG_PATH` environment variable.
10+
It allows specifying alternative path to search for `.pc` files used by
11+
`pkg-config`. Use the option multiple times to specify more than one path.
12+
613
* [#5874]
714

815
In packages using tools version 5.8 or later, Foundation is no longer implicitly imported into package manifests. If Foundation APIs are used, the module needs to be imported explicitly.

Sources/Build/BuildOperation.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,13 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
7979
/// The output stream for the build delegate.
8080
private let outputStream: OutputByteStream
8181

82-
/// The verbosity level to print out at
82+
/// The verbosity level to use for diagnostics.
8383
private let logLevel: Basics.Diagnostic.Severity
8484

85-
/// File system to operate on
85+
/// File system to operate on.
8686
private let fileSystem: TSCBasic.FileSystem
8787

88-
/// ObservabilityScope with which to emit diagnostics
88+
/// ObservabilityScope with which to emit diagnostics.
8989
private let observabilityScope: ObservabilityScope
9090

9191
public var builtTestProducts: [BuiltTestProduct] {
@@ -95,6 +95,9 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
9595
/// File rules to determine resource handling behavior.
9696
private let additionalFileRules: [FileRuleDescription]
9797

98+
/// Alternative path to search for pkg-config `.pc` files.
99+
private let pkgConfigDirectories: [AbsolutePath]
100+
98101
public init(
99102
buildParameters: BuildParameters,
100103
cacheBuildManifest: Bool,
@@ -103,6 +106,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
103106
pluginScriptRunner: PluginScriptRunner,
104107
pluginWorkDirectory: AbsolutePath,
105108
disableSandboxForPluginCommands: Bool,
109+
pkgConfigDirectories: [AbsolutePath],
106110
outputStream: OutputByteStream,
107111
logLevel: Basics.Diagnostic.Severity,
108112
fileSystem: TSCBasic.FileSystem,
@@ -118,6 +122,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
118122
self.additionalFileRules = additionalFileRules
119123
self.pluginScriptRunner = pluginScriptRunner
120124
self.pluginWorkDirectory = pluginWorkDirectory
125+
self.pkgConfigDirectories = pkgConfigDirectories
121126
self.disableSandboxForPluginCommands = disableSandboxForPluginCommands
122127
self.outputStream = outputStream
123128
self.logLevel = logLevel
@@ -399,6 +404,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
399404
builtToolsDir: self.buildParameters.buildPath,
400405
buildEnvironment: self.buildParameters.buildEnvironment,
401406
toolSearchDirectories: [self.buildParameters.toolchain.swiftCompilerPath.parentDirectory],
407+
pkgConfigDirectories: self.pkgConfigDirectories,
402408
pluginScriptRunner: self.pluginScriptRunner,
403409
observabilityScope: self.observabilityScope,
404410
fileSystem: self.fileSystem

Sources/Build/BuildPlan.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2416,7 +2416,12 @@ public class BuildPlan: SPMBuildCore.BuildPlan {
24162416
else {
24172417
pkgConfigCache[target] = ([], [])
24182418
}
2419-
let results = try pkgConfigArgs(for: target, fileSystem: self.fileSystem, observabilityScope: self.observabilityScope)
2419+
let results = try pkgConfigArgs(
2420+
for: target,
2421+
pkgConfigDirectories: buildParameters.pkgConfigDirectories,
2422+
fileSystem: fileSystem,
2423+
observabilityScope: observabilityScope
2424+
)
24202425
var ret: [(cFlags: [String], libs: [String])] = []
24212426
for result in results {
24222427
ret.append((result.cFlags, result.libs))

Sources/Commands/PackageTools/PluginCommand.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ struct PluginCommand: SwiftCommand {
187187
accessibleTools: accessibleTools,
188188
writableDirectories: writableDirectories,
189189
readOnlyDirectories: readOnlyDirectories,
190+
pkgConfigDirectories: swiftTool.options.locations.pkgConfigDirectories,
190191
fileSystem: swiftTool.fileSystem,
191192
observabilityScope: swiftTool.observabilityScope,
192193
callbackQueue: delegateQueue,

Sources/CoreCommands/BuildSystemSupport.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ extension SwiftTool {
3434
pluginScriptRunner: self.getPluginScriptRunner(),
3535
pluginWorkDirectory: try self.getActiveWorkspace().location.pluginWorkingDirectory,
3636
disableSandboxForPluginCommands: self.options.security.shouldDisableSandbox,
37+
pkgConfigDirectories: self.options.locations.pkgConfigDirectories,
3738
outputStream: customOutputStream ?? self.outputStream,
3839
logLevel: customLogLevel ?? self.logLevel,
3940
fileSystem: self.fileSystem,

Sources/CoreCommands/Options.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,16 @@ public struct LocationOptions: ParsableArguments {
8686

8787
@Option(name: .customLong("experimental-destinations-path"), help: .hidden, completion: .directory)
8888
public var crossCompilationDestinationsDirectory: AbsolutePath?
89+
90+
@Option(
91+
name: .customLong("pkg-config-path"),
92+
help:
93+
"""
94+
Specify alternative path to search for pkg-config `.pc` files. Use the option multiple times to
95+
specify more than one path.
96+
""",
97+
completion: .directory)
98+
public var pkgConfigDirectories: [AbsolutePath] = []
8999
}
90100

91101
public struct CachingOptions: ParsableArguments {

Sources/CoreCommands/SwiftTool.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -297,11 +297,11 @@ public final class SwiftTool {
297297
(packageRoot ?? cwd).appending(component: ".build")
298298

299299
// make sure common directories are created
300-
self.sharedSecurityDirectory = try getSharedSecurityDirectory(options: self.options, fileSystem: fileSystem)
301-
self.sharedConfigurationDirectory = try getSharedConfigurationDirectory(options: self.options, fileSystem: fileSystem)
302-
self.sharedCacheDirectory = try getSharedCacheDirectory(options: self.options, fileSystem: fileSystem)
300+
self.sharedSecurityDirectory = try getSharedSecurityDirectory(options: options, fileSystem: fileSystem)
301+
self.sharedConfigurationDirectory = try getSharedConfigurationDirectory(options: options, fileSystem: fileSystem)
302+
self.sharedCacheDirectory = try getSharedCacheDirectory(options: options, fileSystem: fileSystem)
303303
self.sharedCrossCompilationDestinationsDirectory = try fileSystem.getSharedCrossCompilationDestinationsDirectory(
304-
explicitDirectory: self.options.locations.crossCompilationDestinationsDirectory
304+
explicitDirectory: options.locations.crossCompilationDestinationsDirectory
305305
)
306306

307307
// set global process logging handler
@@ -594,6 +594,7 @@ public final class SwiftTool {
594594
archs: options.build.archs,
595595
flags: options.build.buildFlags,
596596
xcbuildFlags: options.build.xcbuildFlags,
597+
pkgConfigDirectories: options.locations.pkgConfigDirectories,
597598
jobs: options.build.jobs ?? UInt32(ProcessInfo.processInfo.activeProcessorCount),
598599
shouldLinkStaticSwiftStdlib: options.linker.shouldLinkStaticSwiftStdlib,
599600
canRenameEntrypointFunctionName: DriverSupport.checkSupportedFrontendFlags(

Sources/PackageLoading/Target+PkgConfig.swift

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,28 @@ public struct PkgConfigResult {
5858
}
5959

6060
/// Get pkgConfig result for a system library target.
61-
public func pkgConfigArgs(for target: SystemLibraryTarget, brewPrefix: AbsolutePath? = .none, fileSystem: FileSystem, observabilityScope: ObservabilityScope) throws -> [PkgConfigResult] {
61+
public func pkgConfigArgs(
62+
for target: SystemLibraryTarget,
63+
pkgConfigDirectories: [AbsolutePath],
64+
brewPrefix: AbsolutePath? = .none,
65+
fileSystem: FileSystem,
66+
observabilityScope: ObservabilityScope
67+
) throws -> [PkgConfigResult] {
6268
// If there is no pkg config name defined, we're done.
6369
guard let pkgConfigNames = target.pkgConfig else { return [] }
6470

6571
// Compute additional search paths for the provider, if any.
6672
let provider = target.providers?.first { $0.isAvailable }
67-
let additionalSearchPaths = try provider?.pkgConfigSearchPath(brewPrefixOverride: brewPrefix) ?? []
6873

69-
var ret: [PkgConfigResult] = []
74+
let additionalSearchPaths: [AbsolutePath]
75+
// Give priority to `pkgConfigDirectories` passed as an argument to this function.
76+
if let providerSearchPaths = try provider?.pkgConfigSearchPath(brewPrefixOverride: brewPrefix) {
77+
additionalSearchPaths = pkgConfigDirectories + providerSearchPaths
78+
} else {
79+
additionalSearchPaths = pkgConfigDirectories
80+
}
81+
82+
var ret: [PkgConfigResult] = []
7083
// Get the pkg config flags.
7184
for pkgConfigName in pkgConfigNames.components(separatedBy: " ") {
7285
let result: PkgConfigResult
@@ -92,19 +105,21 @@ public func pkgConfigArgs(for target: SystemLibraryTarget, brewPrefix: AbsoluteP
92105
}
93106

94107
result = PkgConfigResult(
95-
pkgConfigName: pkgConfigName,
96-
cFlags: cFlags,
97-
libs: libs,
98-
error: error,
99-
provider: provider
108+
pkgConfigName: pkgConfigName,
109+
cFlags: cFlags,
110+
libs: libs,
111+
error: error,
112+
provider: provider
100113
)
101114
} catch {
102115
result = PkgConfigResult(pkgConfigName: pkgConfigName, error: error, provider: provider)
103116
}
104117

105118
// If there is no pc file on system and we have an available provider, emit a warning.
106119
if let provider = result.provider, result.couldNotFindConfigFile {
107-
observabilityScope.emit(warning: "you may be able to install \(result.pkgConfigName) using your system-packager:\n\(provider.installText)")
120+
observabilityScope.emit(
121+
warning: "you may be able to install \(result.pkgConfigName) using your system-packager:\n\(provider.installText)"
122+
)
108123
} else if let error = result.error {
109124
observabilityScope.emit(
110125
warning: "\(error)",

Sources/PackageModel/BuildEnvironment.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
/// A build environment with which to evaluation conditions.
13+
/// A build environment with which to evaluate conditions.
1414
public struct BuildEnvironment: Codable {
1515
public let platform: Platform
1616
public let configuration: BuildConfiguration?

Sources/SPMBuildCore/BuildParameters.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ public struct BuildParameters: Encodable {
137137
/// Extra build flags.
138138
public var flags: BuildFlags
139139

140+
/// An array of paths to search for pkg-config `.pc` files.
141+
public var pkgConfigDirectories: [AbsolutePath]
142+
140143
/// How many jobs should llbuild and the Swift compiler spawn
141144
public var jobs: UInt32
142145

@@ -155,7 +158,7 @@ public struct BuildParameters: Encodable {
155158
/// Whether to enable code coverage.
156159
public var enableCodeCoverage: Bool
157160

158-
/// Whether to enable generation of `.swiftinterface` files alongside
161+
/// Whether to enable generation of `.swiftinterface` files alongside.
159162
/// `.swiftmodule`s.
160163
public var enableParseableModuleInterfaces: Bool
161164

@@ -168,10 +171,10 @@ public struct BuildParameters: Encodable {
168171
/// to a separate process.
169172
public var useIntegratedSwiftDriver: Bool
170173

171-
/// Whether to use the explicit module build flow (with the integrated driver)
174+
/// Whether to use the explicit module build flow (with the integrated driver).
172175
public var useExplicitModuleBuild: Bool
173176

174-
/// A flag that inidcates this build should check whether targets only import
177+
/// A flag that inidcates this build should check whether targets only import.
175178
/// their explicitly-declared dependencies
176179
public var explicitTargetDependencyImportCheckingMode: TargetDependencyImportCheckingMode
177180

@@ -231,6 +234,7 @@ public struct BuildParameters: Encodable {
231234
archs: [String] = [],
232235
flags: BuildFlags,
233236
xcbuildFlags: [String] = [],
237+
pkgConfigDirectories: [AbsolutePath] = [],
234238
jobs: UInt32 = UInt32(ProcessInfo.processInfo.activeProcessorCount),
235239
shouldLinkStaticSwiftStdlib: Bool = false,
236240
shouldEnableManifestCaching: Bool = false,
@@ -261,6 +265,7 @@ public struct BuildParameters: Encodable {
261265
self.triple = triple
262266
self.archs = archs
263267
self.flags = flags
268+
self.pkgConfigDirectories = pkgConfigDirectories
264269
self.xcbuildFlags = xcbuildFlags
265270
self.jobs = jobs
266271
self.shouldLinkStaticSwiftStdlib = shouldLinkStaticSwiftStdlib

Sources/SPMBuildCore/PluginContextSerializer.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ typealias WireInput = HostToPluginMessage.InputContext
2424
internal struct PluginContextSerializer {
2525
let fileSystem: FileSystem
2626
let buildEnvironment: BuildEnvironment
27+
let pkgConfigDirectories: [AbsolutePath]
2728
var paths: [WireInput.Path] = []
2829
var pathsToIds: [AbsolutePath: WireInput.Path.Id] = [:]
2930
var targets: [WireInput.Target] = []
@@ -105,7 +106,12 @@ internal struct PluginContextSerializer {
105106
var ldFlags: [String] = []
106107
// FIXME: What do we do with any diagnostics here?
107108
let observabilityScope = ObservabilitySystem({ _, _ in }).topScope
108-
for result in try pkgConfigArgs(for: target, fileSystem: self.fileSystem, observabilityScope: observabilityScope) {
109+
for result in try pkgConfigArgs(
110+
for: target,
111+
pkgConfigDirectories: pkgConfigDirectories,
112+
fileSystem: fileSystem,
113+
observabilityScope: observabilityScope
114+
) {
109115
if let error = result.error {
110116
observabilityScope.emit(
111117
warning: "\(error)",

Sources/SPMBuildCore/PluginInvocation.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ extension PluginTarget {
4444
/// - workingDirectory: The initial working directory of the invoked plugin.
4545
/// - outputDirectory: A directory under which the plugin can write anything it wants to.
4646
/// - toolNamesToPaths: A mapping from name of tools available to the plugin to the corresponding absolute paths.
47+
/// - pkgConfigDirectory: A directory for searching `pkg-config` `.pc` files in it.
4748
/// - fileSystem: The file system to which all of the paths refers.
4849
///
4950
/// - Returns: A PluginInvocationResult that contains the results of invoking the plugin.
@@ -57,6 +58,7 @@ extension PluginTarget {
5758
accessibleTools: [String: (path: AbsolutePath, triples: [String]?)],
5859
writableDirectories: [AbsolutePath],
5960
readOnlyDirectories: [AbsolutePath],
61+
pkgConfigDirectories: [AbsolutePath],
6062
fileSystem: FileSystem,
6163
observabilityScope: ObservabilityScope,
6264
callbackQueue: DispatchQueue,
@@ -74,7 +76,11 @@ extension PluginTarget {
7476
// Serialize the plugin action to send as the initial message.
7577
let initialMessage: Data
7678
do {
77-
var serializer = PluginContextSerializer(fileSystem: fileSystem, buildEnvironment: buildEnvironment)
79+
var serializer = PluginContextSerializer(
80+
fileSystem: fileSystem,
81+
buildEnvironment: buildEnvironment,
82+
pkgConfigDirectories: pkgConfigDirectories
83+
)
7884
let pluginWorkDirId = try serializer.serialize(path: outputDirectory)
7985
let toolSearchDirIds = try toolSearchDirectories.map{ try serializer.serialize(path: $0) }
8086
let accessibleTools = try accessibleTools.mapValues { (tool: (AbsolutePath, [String]?)) -> HostToPluginMessage.InputContext.Tool in
@@ -324,6 +330,7 @@ extension PackageGraph {
324330
builtToolsDir: AbsolutePath,
325331
buildEnvironment: BuildEnvironment,
326332
toolSearchDirectories: [AbsolutePath],
333+
pkgConfigDirectories: [AbsolutePath],
327334
pluginScriptRunner: PluginScriptRunner,
328335
observabilityScope: ObservabilityScope,
329336
fileSystem: FileSystem
@@ -464,6 +471,7 @@ extension PackageGraph {
464471
accessibleTools: accessibleTools,
465472
writableDirectories: writableDirectories,
466473
readOnlyDirectories: readOnlyDirectories,
474+
pkgConfigDirectories: pkgConfigDirectories,
467475
fileSystem: fileSystem,
468476
observabilityScope: observabilityScope,
469477
callbackQueue: delegateQueue,

Sources/XCBuildSupport/PIFBuilder.swift

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,16 @@ import SPMBuildCore
2424
struct PIFBuilderParameters {
2525

2626
/// Whether or not build for testability is enabled.
27-
public let enableTestability: Bool
27+
let enableTestability: Bool
2828

2929
/// Whether to create dylibs for dynamic library products.
30-
public let shouldCreateDylibForDynamicProducts: Bool
30+
let shouldCreateDylibForDynamicProducts: Bool
3131

3232
/// The path to the library directory of the active toolchain.
33-
public let toolchainLibDir: AbsolutePath
33+
let toolchainLibDir: AbsolutePath
3434

35-
/// Creates a `PIFBuilderParameters` instance.
36-
/// - Parameters:
37-
/// - enableTestability: Whether or not build for testability is enabled.
38-
/// - shouldCreateDylibForDynamicProducts: Whether to create dylibs for dynamic library products.
39-
public init(enableTestability: Bool, shouldCreateDylibForDynamicProducts: Bool, toolchainLibDir: AbsolutePath) {
40-
self.enableTestability = enableTestability
41-
self.shouldCreateDylibForDynamicProducts = shouldCreateDylibForDynamicProducts
42-
self.toolchainLibDir = toolchainLibDir
43-
}
35+
/// An array of paths to search for pkg-config `.pc` files.
36+
let pkgConfigDirectories: [AbsolutePath]
4437
}
4538

4639
/// PIF object builder for a package graph.
@@ -708,7 +701,12 @@ final class PackagePIFProjectBuilder: PIFProjectBuilder {
708701
var impartedSettings = PIF.BuildSettings()
709702

710703
var cFlags: [String] = []
711-
for result in try pkgConfigArgs(for: systemTarget, fileSystem: fileSystem, observabilityScope: self.observabilityScope) {
704+
for result in try pkgConfigArgs(
705+
for: systemTarget,
706+
pkgConfigDirectories: parameters.pkgConfigDirectories,
707+
fileSystem: fileSystem,
708+
observabilityScope: observabilityScope
709+
) {
712710
if let error = result.error {
713711
self.observabilityScope.emit(
714712
warning: "\(error)",

Sources/XCBuildSupport/XcodeBuildSystem.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,8 @@ extension PIFBuilderParameters {
300300
self.init(
301301
enableTestability: buildParameters.enableTestability,
302302
shouldCreateDylibForDynamicProducts: buildParameters.shouldCreateDylibForDynamicProducts,
303-
toolchainLibDir: (try? buildParameters.toolchain.toolchainLibDir) ?? .root
303+
toolchainLibDir: (try? buildParameters.toolchain.toolchainLibDir) ?? .root,
304+
pkgConfigDirectories: buildParameters.pkgConfigDirectories
304305
)
305306
}
306307
}

Tests/BuildTests/MockBuildTestHelper.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ func mockBuildParameters(
7777
hostTriple: hostTriple,
7878
destinationTriple: destinationTriple,
7979
flags: flags,
80+
pkgConfigDirectories: [],
8081
jobs: 3,
8182
shouldLinkStaticSwiftStdlib: shouldLinkStaticSwiftStdlib,
8283
canRenameEntrypointFunctionName: canRenameEntrypointFunctionName,

0 commit comments

Comments
 (0)