From 626e3a23bc39dffe909c35e5d90c7f0433b2ee90 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Dec 2022 17:29:57 +0000 Subject: [PATCH 1/9] Add `--pkg-config-path` to `LocationOptions` --- Sources/Build/BuildOperation.swift | 5 +++ Sources/Build/BuildPlan.swift | 7 +++- Sources/CoreCommands/BuildSystemSupport.swift | 1 + Sources/CoreCommands/Options.swift | 6 +++ Sources/CoreCommands/SwiftTool.swift | 12 ++++-- Sources/PackageLoading/Target+PkgConfig.swift | 30 ++++++++++---- Sources/PackageModel/BuildEnvironment.swift | 2 +- Sources/SPMBuildCore/BuildParameters.swift | 4 ++ .../PluginContextSerializer.swift | 8 +++- Sources/SPMBuildCore/PluginInvocation.swift | 10 ++++- Sources/XCBuildSupport/PIFBuilder.swift | 23 +++++------ Sources/XCBuildSupport/XcodeBuildSystem.swift | 3 +- Tests/BuildTests/MockBuildTestHelper.swift | 1 + .../PackageLoadingTests/PkgConfigTests.swift | 41 ++++++++++++++++--- .../PluginInvocationTests.swift | 5 ++- .../XCBuildSupportTests/PIFBuilderTests.swift | 3 +- 16 files changed, 121 insertions(+), 40 deletions(-) diff --git a/Sources/Build/BuildOperation.swift b/Sources/Build/BuildOperation.swift index c266fa81eb0..32ed0b69484 100644 --- a/Sources/Build/BuildOperation.swift +++ b/Sources/Build/BuildOperation.swift @@ -95,6 +95,8 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS /// File rules to determine resource handling behavior. private let additionalFileRules: [FileRuleDescription] + private let pkgConfigDirectory: AbsolutePath? + public init( buildParameters: BuildParameters, cacheBuildManifest: Bool, @@ -102,6 +104,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS additionalFileRules: [FileRuleDescription], pluginScriptRunner: PluginScriptRunner, pluginWorkDirectory: AbsolutePath, + pkgConfigDirectory: AbsolutePath?, disableSandboxForPluginCommands: Bool, outputStream: OutputByteStream, logLevel: Basics.Diagnostic.Severity, @@ -118,6 +121,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS self.additionalFileRules = additionalFileRules self.pluginScriptRunner = pluginScriptRunner self.pluginWorkDirectory = pluginWorkDirectory + self.pkgConfigDirectory = pkgConfigDirectory self.disableSandboxForPluginCommands = disableSandboxForPluginCommands self.outputStream = outputStream self.logLevel = logLevel @@ -399,6 +403,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS builtToolsDir: self.buildParameters.buildPath, buildEnvironment: self.buildParameters.buildEnvironment, toolSearchDirectories: [self.buildParameters.toolchain.swiftCompilerPath.parentDirectory], + pkgConfigDirectory: self.pkgConfigDirectory, pluginScriptRunner: self.pluginScriptRunner, observabilityScope: self.observabilityScope, fileSystem: self.fileSystem diff --git a/Sources/Build/BuildPlan.swift b/Sources/Build/BuildPlan.swift index 4009b4bba51..21403bf7088 100644 --- a/Sources/Build/BuildPlan.swift +++ b/Sources/Build/BuildPlan.swift @@ -2416,7 +2416,12 @@ public class BuildPlan: SPMBuildCore.BuildPlan { else { pkgConfigCache[target] = ([], []) } - let results = try pkgConfigArgs(for: target, fileSystem: self.fileSystem, observabilityScope: self.observabilityScope) + let results = try pkgConfigArgs( + for: target, + pkgConfigDirectory: buildParameters.pkgConfigDirectory, + fileSystem: fileSystem, + observabilityScope: observabilityScope + ) var ret: [(cFlags: [String], libs: [String])] = [] for result in results { ret.append((result.cFlags, result.libs)) diff --git a/Sources/CoreCommands/BuildSystemSupport.swift b/Sources/CoreCommands/BuildSystemSupport.swift index c57120a0985..d79657646a8 100644 --- a/Sources/CoreCommands/BuildSystemSupport.swift +++ b/Sources/CoreCommands/BuildSystemSupport.swift @@ -33,6 +33,7 @@ extension SwiftTool { additionalFileRules: FileRuleDescription.swiftpmFileTypes, pluginScriptRunner: self.getPluginScriptRunner(), pluginWorkDirectory: try self.getActiveWorkspace().location.pluginWorkingDirectory, + pkgConfigDirectory: self.options.locations.pkgConfigDirectory, disableSandboxForPluginCommands: self.options.security.shouldDisableSandbox, outputStream: customOutputStream ?? self.outputStream, logLevel: customLogLevel ?? self.logLevel, diff --git a/Sources/CoreCommands/Options.swift b/Sources/CoreCommands/Options.swift index 87d80d306d9..7126bdc7043 100644 --- a/Sources/CoreCommands/Options.swift +++ b/Sources/CoreCommands/Options.swift @@ -86,6 +86,12 @@ public struct LocationOptions: ParsableArguments { @Option(name: .customLong("experimental-destinations-path"), help: .hidden, completion: .directory) var crossCompilationDestinationsDirectory: AbsolutePath? + + @Option( + name: .customLong("pkg-config-path"), + help: "Specify alternate paths to search for pkg-config `.pc` files,", + completion: .directory) + public var pkgConfigDirectory: AbsolutePath? } public struct CachingOptions: ParsableArguments { diff --git a/Sources/CoreCommands/SwiftTool.swift b/Sources/CoreCommands/SwiftTool.swift index 5b2332006b1..5a8d5e1cd84 100644 --- a/Sources/CoreCommands/SwiftTool.swift +++ b/Sources/CoreCommands/SwiftTool.swift @@ -153,6 +153,8 @@ public final class SwiftTool { /// Path to the cross-compilation SDK directory. public let sharedCrossCompilationDestinationsDirectory: AbsolutePath? + public let pkgConfigDirectory: AbsolutePath? + /// Cancellator to handle cancellation of outstanding work when handling SIGINT public let cancellator: Cancellator @@ -296,10 +298,11 @@ public final class SwiftTool { (packageRoot ?? cwd).appending(component: ".build") // make sure common directories are created - self.sharedSecurityDirectory = try getSharedSecurityDirectory(options: self.options, fileSystem: fileSystem) - self.sharedConfigurationDirectory = try getSharedConfigurationDirectory(options: self.options, fileSystem: fileSystem) - self.sharedCacheDirectory = try getSharedCacheDirectory(options: self.options, fileSystem: fileSystem) - self.sharedCrossCompilationDestinationsDirectory = try getSharedCrossCompilationDestinationsDirectory(options: self.options, fileSystem: fileSystem) + self.sharedSecurityDirectory = try getSharedSecurityDirectory(options: options, fileSystem: fileSystem) + self.sharedConfigurationDirectory = try getSharedConfigurationDirectory(options: options, fileSystem: fileSystem) + self.sharedCacheDirectory = try getSharedCacheDirectory(options: options, fileSystem: fileSystem) + self.sharedCrossCompilationDestinationsDirectory = try getSharedCrossCompilationDestinationsDirectory(options: options, fileSystem: fileSystem) + self.pkgConfigDirectory = options.locations.pkgConfigDirectory // set global process logging handler Process.loggingHandler = { self.observabilityScope.emit(debug: $0) } @@ -591,6 +594,7 @@ public final class SwiftTool { archs: options.build.archs, flags: options.build.buildFlags, xcbuildFlags: options.build.xcbuildFlags, + pkgConfigDirectory: options.locations.pkgConfigDirectory, jobs: options.build.jobs ?? UInt32(ProcessInfo.processInfo.activeProcessorCount), shouldLinkStaticSwiftStdlib: options.linker.shouldLinkStaticSwiftStdlib, canRenameEntrypointFunctionName: DriverSupport.checkSupportedFrontendFlags( diff --git a/Sources/PackageLoading/Target+PkgConfig.swift b/Sources/PackageLoading/Target+PkgConfig.swift index 81217d38f03..7d011ebab29 100644 --- a/Sources/PackageLoading/Target+PkgConfig.swift +++ b/Sources/PackageLoading/Target+PkgConfig.swift @@ -58,15 +58,25 @@ public struct PkgConfigResult { } /// Get pkgConfig result for a system library target. -public func pkgConfigArgs(for target: SystemLibraryTarget, brewPrefix: AbsolutePath? = .none, fileSystem: FileSystem, observabilityScope: ObservabilityScope) throws -> [PkgConfigResult] { +public func pkgConfigArgs( + for target: SystemLibraryTarget, + pkgConfigDirectory: AbsolutePath?, + brewPrefix: AbsolutePath? = .none, + fileSystem: FileSystem, + observabilityScope: ObservabilityScope +) throws -> [PkgConfigResult] { // If there is no pkg config name defined, we're done. guard let pkgConfigNames = target.pkgConfig else { return [] } // Compute additional search paths for the provider, if any. let provider = target.providers?.first { $0.isAvailable } - let additionalSearchPaths = try provider?.pkgConfigSearchPath(brewPrefixOverride: brewPrefix) ?? [] + var additionalSearchPaths = try provider?.pkgConfigSearchPath(brewPrefixOverride: brewPrefix) ?? [] + if let pkgConfigDirectory = pkgConfigDirectory { + // Give priority to `pkgConfigPath` passed as an argument to this function. + additionalSearchPaths.insert(pkgConfigDirectory, at: 0) + } - var ret: [PkgConfigResult] = [] + var ret: [PkgConfigResult] = [] // Get the pkg config flags. for pkgConfigName in pkgConfigNames.components(separatedBy: " ") { let result: PkgConfigResult @@ -92,11 +102,11 @@ public func pkgConfigArgs(for target: SystemLibraryTarget, brewPrefix: AbsoluteP } result = PkgConfigResult( - pkgConfigName: pkgConfigName, - cFlags: cFlags, - libs: libs, - error: error, - provider: provider + pkgConfigName: pkgConfigName, + cFlags: cFlags, + libs: libs, + error: error, + provider: provider ) } catch { result = PkgConfigResult(pkgConfigName: pkgConfigName, error: error, provider: provider) @@ -104,7 +114,9 @@ public func pkgConfigArgs(for target: SystemLibraryTarget, brewPrefix: AbsoluteP // If there is no pc file on system and we have an available provider, emit a warning. if let provider = result.provider, result.couldNotFindConfigFile { - observabilityScope.emit(warning: "you may be able to install \(result.pkgConfigName) using your system-packager:\n\(provider.installText)") + observabilityScope.emit( + warning: "you may be able to install \(result.pkgConfigName) using your system-packager:\n\(provider.installText)" + ) } else if let error = result.error { observabilityScope.emit( warning: "\(error)", diff --git a/Sources/PackageModel/BuildEnvironment.swift b/Sources/PackageModel/BuildEnvironment.swift index d99b93db3a4..2efcf13ea32 100644 --- a/Sources/PackageModel/BuildEnvironment.swift +++ b/Sources/PackageModel/BuildEnvironment.swift @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -/// A build environment with which to evaluation conditions. +/// A build environment with which to evaluate conditions. public struct BuildEnvironment: Codable { public let platform: Platform public let configuration: BuildConfiguration? diff --git a/Sources/SPMBuildCore/BuildParameters.swift b/Sources/SPMBuildCore/BuildParameters.swift index 929efc62255..071001045af 100644 --- a/Sources/SPMBuildCore/BuildParameters.swift +++ b/Sources/SPMBuildCore/BuildParameters.swift @@ -137,6 +137,8 @@ public struct BuildParameters: Encodable { /// Extra build flags. public var flags: BuildFlags + public var pkgConfigDirectory: AbsolutePath? + /// How many jobs should llbuild and the Swift compiler spawn public var jobs: UInt32 @@ -231,6 +233,7 @@ public struct BuildParameters: Encodable { archs: [String] = [], flags: BuildFlags, xcbuildFlags: [String] = [], + pkgConfigDirectory: AbsolutePath?, jobs: UInt32 = UInt32(ProcessInfo.processInfo.activeProcessorCount), shouldLinkStaticSwiftStdlib: Bool = false, shouldEnableManifestCaching: Bool = false, @@ -261,6 +264,7 @@ public struct BuildParameters: Encodable { self.triple = triple self.archs = archs self.flags = flags + self.pkgConfigDirectory = pkgConfigDirectory self.xcbuildFlags = xcbuildFlags self.jobs = jobs self.shouldLinkStaticSwiftStdlib = shouldLinkStaticSwiftStdlib diff --git a/Sources/SPMBuildCore/PluginContextSerializer.swift b/Sources/SPMBuildCore/PluginContextSerializer.swift index a121fd9ad63..0ce516a44e1 100644 --- a/Sources/SPMBuildCore/PluginContextSerializer.swift +++ b/Sources/SPMBuildCore/PluginContextSerializer.swift @@ -24,6 +24,7 @@ typealias WireInput = HostToPluginMessage.InputContext internal struct PluginContextSerializer { let fileSystem: FileSystem let buildEnvironment: BuildEnvironment + let pkgConfigDirectory: AbsolutePath? var paths: [WireInput.Path] = [] var pathsToIds: [AbsolutePath: WireInput.Path.Id] = [:] var targets: [WireInput.Target] = [] @@ -105,7 +106,12 @@ internal struct PluginContextSerializer { var ldFlags: [String] = [] // FIXME: What do we do with any diagnostics here? let observabilityScope = ObservabilitySystem({ _, _ in }).topScope - for result in try pkgConfigArgs(for: target, fileSystem: self.fileSystem, observabilityScope: observabilityScope) { + for result in try pkgConfigArgs( + for: target, + pkgConfigDirectory: pkgConfigDirectory, + fileSystem: fileSystem, + observabilityScope: observabilityScope + ) { if let error = result.error { observabilityScope.emit( warning: "\(error)", diff --git a/Sources/SPMBuildCore/PluginInvocation.swift b/Sources/SPMBuildCore/PluginInvocation.swift index 6b8f54e895e..c42dbf029fe 100644 --- a/Sources/SPMBuildCore/PluginInvocation.swift +++ b/Sources/SPMBuildCore/PluginInvocation.swift @@ -44,6 +44,7 @@ extension PluginTarget { /// - workingDirectory: The initial working directory of the invoked plugin. /// - outputDirectory: A directory under which the plugin can write anything it wants to. /// - toolNamesToPaths: A mapping from name of tools available to the plugin to the corresponding absolute paths. + /// - pkgConfigDirectory: A directory for searching `pkg-config` `.pc` files in it. /// - fileSystem: The file system to which all of the paths refers. /// /// - Returns: A PluginInvocationResult that contains the results of invoking the plugin. @@ -58,6 +59,7 @@ extension PluginTarget { toolNamesToTriples: [String: [String]], writableDirectories: [AbsolutePath], readOnlyDirectories: [AbsolutePath], + pkgConfigDirectory: AbsolutePath?, fileSystem: FileSystem, observabilityScope: ObservabilityScope, callbackQueue: DispatchQueue, @@ -75,7 +77,11 @@ extension PluginTarget { // Serialize the plugin action to send as the initial message. let initialMessage: Data do { - var serializer = PluginContextSerializer(fileSystem: fileSystem, buildEnvironment: buildEnvironment) + var serializer = PluginContextSerializer( + fileSystem: fileSystem, + buildEnvironment: buildEnvironment, + pkgConfigDirectory: pkgConfigDirectory + ) let pluginWorkDirId = try serializer.serialize(path: outputDirectory) let toolSearchDirIds = try toolSearchDirectories.map{ try serializer.serialize(path: $0) } let toolNamesToPathIds = try toolNamesToPaths.mapValues{ try serializer.serialize(path: $0) } @@ -318,6 +324,7 @@ extension PackageGraph { builtToolsDir: AbsolutePath, buildEnvironment: BuildEnvironment, toolSearchDirectories: [AbsolutePath], + pkgConfigDirectory: AbsolutePath?, pluginScriptRunner: PluginScriptRunner, observabilityScope: ObservabilityScope, fileSystem: FileSystem @@ -468,6 +475,7 @@ extension PackageGraph { toolNamesToTriples: toolNamesToTriples, writableDirectories: writableDirectories, readOnlyDirectories: readOnlyDirectories, + pkgConfigDirectory: pkgConfigDirectory, fileSystem: fileSystem, observabilityScope: observabilityScope, callbackQueue: delegateQueue, diff --git a/Sources/XCBuildSupport/PIFBuilder.swift b/Sources/XCBuildSupport/PIFBuilder.swift index ab403b29edd..bd68dda0345 100644 --- a/Sources/XCBuildSupport/PIFBuilder.swift +++ b/Sources/XCBuildSupport/PIFBuilder.swift @@ -24,23 +24,15 @@ import SPMBuildCore struct PIFBuilderParameters { /// Whether or not build for testability is enabled. - public let enableTestability: Bool + let enableTestability: Bool /// Whether to create dylibs for dynamic library products. - public let shouldCreateDylibForDynamicProducts: Bool + let shouldCreateDylibForDynamicProducts: Bool /// The path to the library directory of the active toolchain. - public let toolchainLibDir: AbsolutePath + let toolchainLibDir: AbsolutePath - /// Creates a `PIFBuilderParameters` instance. - /// - Parameters: - /// - enableTestability: Whether or not build for testability is enabled. - /// - shouldCreateDylibForDynamicProducts: Whether to create dylibs for dynamic library products. - public init(enableTestability: Bool, shouldCreateDylibForDynamicProducts: Bool, toolchainLibDir: AbsolutePath) { - self.enableTestability = enableTestability - self.shouldCreateDylibForDynamicProducts = shouldCreateDylibForDynamicProducts - self.toolchainLibDir = toolchainLibDir - } + let pkgConfigDirectory: AbsolutePath? } /// PIF object builder for a package graph. @@ -708,7 +700,12 @@ final class PackagePIFProjectBuilder: PIFProjectBuilder { var impartedSettings = PIF.BuildSettings() var cFlags: [String] = [] - for result in try pkgConfigArgs(for: systemTarget, fileSystem: fileSystem, observabilityScope: self.observabilityScope) { + for result in try pkgConfigArgs( + for: systemTarget, + pkgConfigDirectory: parameters.pkgConfigDirectory, + fileSystem: fileSystem, + observabilityScope: observabilityScope + ) { if let error = result.error { self.observabilityScope.emit( warning: "\(error)", diff --git a/Sources/XCBuildSupport/XcodeBuildSystem.swift b/Sources/XCBuildSupport/XcodeBuildSystem.swift index 31fb5efe03c..0ce95d9abc7 100644 --- a/Sources/XCBuildSupport/XcodeBuildSystem.swift +++ b/Sources/XCBuildSupport/XcodeBuildSystem.swift @@ -300,7 +300,8 @@ extension PIFBuilderParameters { self.init( enableTestability: buildParameters.enableTestability, shouldCreateDylibForDynamicProducts: buildParameters.shouldCreateDylibForDynamicProducts, - toolchainLibDir: (try? buildParameters.toolchain.toolchainLibDir) ?? .root + toolchainLibDir: (try? buildParameters.toolchain.toolchainLibDir) ?? .root, + pkgConfigDirectory: buildParameters.pkgConfigDirectory ) } } diff --git a/Tests/BuildTests/MockBuildTestHelper.swift b/Tests/BuildTests/MockBuildTestHelper.swift index 79f97bf39a9..d9852017a19 100644 --- a/Tests/BuildTests/MockBuildTestHelper.swift +++ b/Tests/BuildTests/MockBuildTestHelper.swift @@ -77,6 +77,7 @@ func mockBuildParameters( hostTriple: hostTriple, destinationTriple: destinationTriple, flags: flags, + pkgConfigDirectory: nil, jobs: 3, shouldLinkStaticSwiftStdlib: shouldLinkStaticSwiftStdlib, canRenameEntrypointFunctionName: canRenameEntrypointFunctionName, diff --git a/Tests/PackageLoadingTests/PkgConfigTests.swift b/Tests/PackageLoadingTests/PkgConfigTests.swift index 108a15bff80..d0d94fa3c6c 100644 --- a/Tests/PackageLoadingTests/PkgConfigTests.swift +++ b/Tests/PackageLoadingTests/PkgConfigTests.swift @@ -36,7 +36,12 @@ class PkgConfigTests: XCTestCase { // No pkgConfig name. do { let observability = ObservabilitySystem.makeForTesting() - let result = try pkgConfigArgs(for: SystemLibraryTarget(pkgConfig: ""), fileSystem: fs, observabilityScope: observability.topScope) + let result = try pkgConfigArgs( + for: SystemLibraryTarget(pkgConfig: ""), + pkgConfigDirectory: nil, + fileSystem: fs, + observabilityScope: observability.topScope + ) XCTAssertTrue(result.isEmpty) } @@ -53,7 +58,11 @@ class PkgConfigTests: XCTestCase { .nuget(["Foo"]), ] ) - for result in try pkgConfigArgs(for: target, fileSystem: fs, observabilityScope: observability.topScope) { + for result in try pkgConfigArgs( + for: target, + pkgConfigDirectory: nil, + fileSystem: fs, + observabilityScope: observability.topScope) { XCTAssertEqual(result.pkgConfigName, "Foo") XCTAssertEqual(result.cFlags, []) XCTAssertEqual(result.libs, []) @@ -81,7 +90,12 @@ class PkgConfigTests: XCTestCase { // Pc file. try withCustomEnv(["PKG_CONFIG_PATH": inputsDir.pathString]) { let observability = ObservabilitySystem.makeForTesting() - for result in try pkgConfigArgs(for: SystemLibraryTarget(pkgConfig: "Foo"), fileSystem: fs, observabilityScope: observability.topScope) { + for result in try pkgConfigArgs( + for: SystemLibraryTarget(pkgConfig: "Foo"), + pkgConfigDirectory: nil, + fileSystem: fs, + observabilityScope: observability.topScope + ) { XCTAssertEqual(result.pkgConfigName, "Foo") XCTAssertEqual(result.cFlags, ["-I/path/to/inc", "-I\(inputsDir.pathString)"]) XCTAssertEqual(result.libs, ["-L/usr/da/lib", "-lSystemModule", "-lok"]) @@ -94,7 +108,12 @@ class PkgConfigTests: XCTestCase { // Pc file with prohibited flags. try withCustomEnv(["PKG_CONFIG_PATH": inputsDir.pathString]) { let observability = ObservabilitySystem.makeForTesting() - for result in try pkgConfigArgs(for: SystemLibraryTarget(pkgConfig: "Bar"), fileSystem: fs, observabilityScope: observability.topScope) { + for result in try pkgConfigArgs( + for: SystemLibraryTarget(pkgConfig: "Bar"), + pkgConfigDirectory: nil, + fileSystem: fs, + observabilityScope: observability.topScope + ) { XCTAssertEqual(result.pkgConfigName, "Bar") XCTAssertEqual(result.cFlags, ["-I/path/to/inc"]) XCTAssertEqual(result.libs, ["-L/usr/da/lib", "-lSystemModule", "-lok"]) @@ -112,7 +131,12 @@ class PkgConfigTests: XCTestCase { // Pc file with -framework Framework flag. try withCustomEnv(["PKG_CONFIG_PATH": inputsDir.pathString]) { let observability = ObservabilitySystem.makeForTesting() - for result in try pkgConfigArgs(for: SystemLibraryTarget(pkgConfig: "Framework"), fileSystem: fs, observabilityScope: observability.topScope) { + for result in try pkgConfigArgs( + for: SystemLibraryTarget(pkgConfig: "Framework"), + pkgConfigDirectory: nil, + fileSystem: fs, + observabilityScope: observability.topScope + ) { XCTAssertEqual(result.pkgConfigName, "Framework") XCTAssertEqual(result.cFlags, ["-F/usr/lib"]) XCTAssertEqual(result.libs, ["-F/usr/lib", "-framework", "SystemFramework"]) @@ -132,7 +156,12 @@ class PkgConfigTests: XCTestCase { // Use additionalSearchPaths instead of pkgConfigArgs to test handling // of search paths when loading dependencies. let observability = ObservabilitySystem.makeForTesting() - let result = try PkgConfig(name: "Dependent", additionalSearchPaths: [inputsDir], fileSystem: localFileSystem, observabilityScope: observability.topScope) + let result = try PkgConfig( + name: "Dependent", + additionalSearchPaths: [inputsDir], + fileSystem: localFileSystem, + observabilityScope: observability.topScope + ) XCTAssertEqual(result.name, "Dependent") XCTAssertEqual(result.cFlags, ["-I/path/to/dependent/include", "-I/path/to/dependency/include"]) diff --git a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift b/Tests/SPMBuildCoreTests/PluginInvocationTests.swift index b9aecf5a2c6..9dfef9c313f 100644 --- a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift +++ b/Tests/SPMBuildCoreTests/PluginInvocationTests.swift @@ -194,6 +194,7 @@ class PluginInvocationTests: XCTestCase { builtToolsDir: builtToolsDir, buildEnvironment: BuildEnvironment(platform: .macOS, configuration: .debug), toolSearchDirectories: [UserToolchain.default.swiftCompilerPath.parentDirectory], + pkgConfigDirectory: nil, pluginScriptRunner: pluginRunner, observabilityScope: observability.topScope, fileSystem: fileSystem @@ -885,7 +886,7 @@ class PluginInvocationTests: XCTestCase { outputDir: outputDir, builtToolsDir: builtToolsDir, buildEnvironment: BuildEnvironment(platform: .macOS, configuration: .debug), - toolSearchDirectories: [UserToolchain.default.swiftCompilerPath.parentDirectory], + toolSearchDirectories: [UserToolchain.default.swiftCompilerPath.parentDirectory], pkgConfigDirectory: <#AbsolutePath?#>, pluginScriptRunner: pluginScriptRunner, observabilityScope: observability.topScope, fileSystem: localFileSystem @@ -1181,7 +1182,7 @@ class PluginInvocationTests: XCTestCase { outputDir: outputDir, builtToolsDir: builtToolsDir, buildEnvironment: BuildEnvironment(platform: .macOS, configuration: .debug), - toolSearchDirectories: [UserToolchain.default.swiftCompilerPath.parentDirectory], + toolSearchDirectories: [UserToolchain.default.swiftCompilerPath.parentDirectory], pkgConfigDirectory: <#AbsolutePath?#>, pluginScriptRunner: pluginScriptRunner, observabilityScope: observability.topScope, fileSystem: localFileSystem diff --git a/Tests/XCBuildSupportTests/PIFBuilderTests.swift b/Tests/XCBuildSupportTests/PIFBuilderTests.swift index 3daf14be122..4815654cb81 100644 --- a/Tests/XCBuildSupportTests/PIFBuilderTests.swift +++ b/Tests/XCBuildSupportTests/PIFBuilderTests.swift @@ -2614,7 +2614,8 @@ extension PIFBuilderParameters { PIFBuilderParameters( enableTestability: false, shouldCreateDylibForDynamicProducts: shouldCreateDylibForDynamicProducts, - toolchainLibDir: AbsolutePath(path: "/toolchain/lib") + toolchainLibDir: AbsolutePath(path: "/toolchain/lib"), + pkgConfigDirectory: AbsolutePath(path: "/pkg-config") ) } } From bc0a809de97d8b8952588f992f90893f5ca30941 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Dec 2022 21:15:17 +0000 Subject: [PATCH 2/9] Address PR feedback --- Sources/Build/BuildOperation.swift | 2 +- Sources/Commands/PackageTools/PluginCommand.swift | 1 + Sources/CoreCommands/BuildSystemSupport.swift | 2 +- Sources/CoreCommands/SwiftTool.swift | 3 --- Tests/SPMBuildCoreTests/PluginInvocationTests.swift | 6 ++++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Sources/Build/BuildOperation.swift b/Sources/Build/BuildOperation.swift index 32ed0b69484..8cd3823f7b6 100644 --- a/Sources/Build/BuildOperation.swift +++ b/Sources/Build/BuildOperation.swift @@ -104,8 +104,8 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS additionalFileRules: [FileRuleDescription], pluginScriptRunner: PluginScriptRunner, pluginWorkDirectory: AbsolutePath, - pkgConfigDirectory: AbsolutePath?, disableSandboxForPluginCommands: Bool, + pkgConfigDirectory: AbsolutePath?, outputStream: OutputByteStream, logLevel: Basics.Diagnostic.Severity, fileSystem: TSCBasic.FileSystem, diff --git a/Sources/Commands/PackageTools/PluginCommand.swift b/Sources/Commands/PackageTools/PluginCommand.swift index 561812abe9b..991fad026c4 100644 --- a/Sources/Commands/PackageTools/PluginCommand.swift +++ b/Sources/Commands/PackageTools/PluginCommand.swift @@ -196,6 +196,7 @@ struct PluginCommand: SwiftCommand { toolNamesToTriples: toolNamesToTriples, writableDirectories: writableDirectories, readOnlyDirectories: readOnlyDirectories, + pkgConfigDirectory: swiftTool.options.locations.pkgConfigDirectory, fileSystem: swiftTool.fileSystem, observabilityScope: swiftTool.observabilityScope, callbackQueue: delegateQueue, diff --git a/Sources/CoreCommands/BuildSystemSupport.swift b/Sources/CoreCommands/BuildSystemSupport.swift index d79657646a8..c9a0c6c5dbc 100644 --- a/Sources/CoreCommands/BuildSystemSupport.swift +++ b/Sources/CoreCommands/BuildSystemSupport.swift @@ -33,8 +33,8 @@ extension SwiftTool { additionalFileRules: FileRuleDescription.swiftpmFileTypes, pluginScriptRunner: self.getPluginScriptRunner(), pluginWorkDirectory: try self.getActiveWorkspace().location.pluginWorkingDirectory, - pkgConfigDirectory: self.options.locations.pkgConfigDirectory, disableSandboxForPluginCommands: self.options.security.shouldDisableSandbox, + pkgConfigDirectory: self.options.locations.pkgConfigDirectory, outputStream: customOutputStream ?? self.outputStream, logLevel: customLogLevel ?? self.logLevel, fileSystem: self.fileSystem, diff --git a/Sources/CoreCommands/SwiftTool.swift b/Sources/CoreCommands/SwiftTool.swift index 5a8d5e1cd84..5a0eedbf123 100644 --- a/Sources/CoreCommands/SwiftTool.swift +++ b/Sources/CoreCommands/SwiftTool.swift @@ -153,8 +153,6 @@ public final class SwiftTool { /// Path to the cross-compilation SDK directory. public let sharedCrossCompilationDestinationsDirectory: AbsolutePath? - public let pkgConfigDirectory: AbsolutePath? - /// Cancellator to handle cancellation of outstanding work when handling SIGINT public let cancellator: Cancellator @@ -302,7 +300,6 @@ public final class SwiftTool { self.sharedConfigurationDirectory = try getSharedConfigurationDirectory(options: options, fileSystem: fileSystem) self.sharedCacheDirectory = try getSharedCacheDirectory(options: options, fileSystem: fileSystem) self.sharedCrossCompilationDestinationsDirectory = try getSharedCrossCompilationDestinationsDirectory(options: options, fileSystem: fileSystem) - self.pkgConfigDirectory = options.locations.pkgConfigDirectory // set global process logging handler Process.loggingHandler = { self.observabilityScope.emit(debug: $0) } diff --git a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift b/Tests/SPMBuildCoreTests/PluginInvocationTests.swift index 9dfef9c313f..6156f2f7663 100644 --- a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift +++ b/Tests/SPMBuildCoreTests/PluginInvocationTests.swift @@ -886,7 +886,8 @@ class PluginInvocationTests: XCTestCase { outputDir: outputDir, builtToolsDir: builtToolsDir, buildEnvironment: BuildEnvironment(platform: .macOS, configuration: .debug), - toolSearchDirectories: [UserToolchain.default.swiftCompilerPath.parentDirectory], pkgConfigDirectory: <#AbsolutePath?#>, + toolSearchDirectories: [UserToolchain.default.swiftCompilerPath.parentDirectory], + pkgConfigDirectory: nil, pluginScriptRunner: pluginScriptRunner, observabilityScope: observability.topScope, fileSystem: localFileSystem @@ -1182,7 +1183,8 @@ class PluginInvocationTests: XCTestCase { outputDir: outputDir, builtToolsDir: builtToolsDir, buildEnvironment: BuildEnvironment(platform: .macOS, configuration: .debug), - toolSearchDirectories: [UserToolchain.default.swiftCompilerPath.parentDirectory], pkgConfigDirectory: <#AbsolutePath?#>, + toolSearchDirectories: [UserToolchain.default.swiftCompilerPath.parentDirectory], + pkgConfigDirectory: nil, pluginScriptRunner: pluginScriptRunner, observabilityScope: observability.topScope, fileSystem: localFileSystem From bc2873ef0ec63bc5b28deb8af144b5d0e49254da Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 15 Dec 2022 11:06:13 +0000 Subject: [PATCH 3/9] Allow passing multiple `pkg-config-path` values --- Sources/Build/BuildOperation.swift | 8 ++++---- Sources/Build/BuildPlan.swift | 2 +- Sources/Commands/PackageTools/PluginCommand.swift | 2 +- Sources/CoreCommands/BuildSystemSupport.swift | 2 +- Sources/CoreCommands/Options.swift | 8 ++++++-- Sources/CoreCommands/SwiftTool.swift | 2 +- Sources/PackageLoading/Target+PkgConfig.swift | 13 ++++++++----- Sources/SPMBuildCore/BuildParameters.swift | 13 +++++++------ Sources/SPMBuildCore/PluginContextSerializer.swift | 4 ++-- Sources/SPMBuildCore/PluginInvocation.swift | 8 ++++---- Sources/XCBuildSupport/PIFBuilder.swift | 5 +++-- Sources/XCBuildSupport/XcodeBuildSystem.swift | 2 +- Tests/BuildTests/MockBuildTestHelper.swift | 2 +- Tests/PackageLoadingTests/PkgConfigTests.swift | 10 +++++----- Tests/SPMBuildCoreTests/PluginInvocationTests.swift | 6 +++--- Tests/XCBuildSupportTests/PIFBuilderTests.swift | 2 +- 16 files changed, 49 insertions(+), 40 deletions(-) diff --git a/Sources/Build/BuildOperation.swift b/Sources/Build/BuildOperation.swift index 8cd3823f7b6..f2d8c4032eb 100644 --- a/Sources/Build/BuildOperation.swift +++ b/Sources/Build/BuildOperation.swift @@ -95,7 +95,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS /// File rules to determine resource handling behavior. private let additionalFileRules: [FileRuleDescription] - private let pkgConfigDirectory: AbsolutePath? + private let pkgConfigDirectories: [AbsolutePath] public init( buildParameters: BuildParameters, @@ -105,7 +105,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS pluginScriptRunner: PluginScriptRunner, pluginWorkDirectory: AbsolutePath, disableSandboxForPluginCommands: Bool, - pkgConfigDirectory: AbsolutePath?, + pkgConfigDirectories: [AbsolutePath], outputStream: OutputByteStream, logLevel: Basics.Diagnostic.Severity, fileSystem: TSCBasic.FileSystem, @@ -121,7 +121,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS self.additionalFileRules = additionalFileRules self.pluginScriptRunner = pluginScriptRunner self.pluginWorkDirectory = pluginWorkDirectory - self.pkgConfigDirectory = pkgConfigDirectory + self.pkgConfigDirectories = pkgConfigDirectories self.disableSandboxForPluginCommands = disableSandboxForPluginCommands self.outputStream = outputStream self.logLevel = logLevel @@ -403,7 +403,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS builtToolsDir: self.buildParameters.buildPath, buildEnvironment: self.buildParameters.buildEnvironment, toolSearchDirectories: [self.buildParameters.toolchain.swiftCompilerPath.parentDirectory], - pkgConfigDirectory: self.pkgConfigDirectory, + pkgConfigDirectories: self.pkgConfigDirectories, pluginScriptRunner: self.pluginScriptRunner, observabilityScope: self.observabilityScope, fileSystem: self.fileSystem diff --git a/Sources/Build/BuildPlan.swift b/Sources/Build/BuildPlan.swift index 21403bf7088..ec97064741a 100644 --- a/Sources/Build/BuildPlan.swift +++ b/Sources/Build/BuildPlan.swift @@ -2418,7 +2418,7 @@ public class BuildPlan: SPMBuildCore.BuildPlan { } let results = try pkgConfigArgs( for: target, - pkgConfigDirectory: buildParameters.pkgConfigDirectory, + pkgConfigDirectories: buildParameters.pkgConfigDirectories, fileSystem: fileSystem, observabilityScope: observabilityScope ) diff --git a/Sources/Commands/PackageTools/PluginCommand.swift b/Sources/Commands/PackageTools/PluginCommand.swift index 991fad026c4..a479cf1cd27 100644 --- a/Sources/Commands/PackageTools/PluginCommand.swift +++ b/Sources/Commands/PackageTools/PluginCommand.swift @@ -196,7 +196,7 @@ struct PluginCommand: SwiftCommand { toolNamesToTriples: toolNamesToTriples, writableDirectories: writableDirectories, readOnlyDirectories: readOnlyDirectories, - pkgConfigDirectory: swiftTool.options.locations.pkgConfigDirectory, + pkgConfigDirectories: swiftTool.options.locations.pkgConfigDirectories, fileSystem: swiftTool.fileSystem, observabilityScope: swiftTool.observabilityScope, callbackQueue: delegateQueue, diff --git a/Sources/CoreCommands/BuildSystemSupport.swift b/Sources/CoreCommands/BuildSystemSupport.swift index c9a0c6c5dbc..383a9879a4f 100644 --- a/Sources/CoreCommands/BuildSystemSupport.swift +++ b/Sources/CoreCommands/BuildSystemSupport.swift @@ -34,7 +34,7 @@ extension SwiftTool { pluginScriptRunner: self.getPluginScriptRunner(), pluginWorkDirectory: try self.getActiveWorkspace().location.pluginWorkingDirectory, disableSandboxForPluginCommands: self.options.security.shouldDisableSandbox, - pkgConfigDirectory: self.options.locations.pkgConfigDirectory, + pkgConfigDirectories: self.options.locations.pkgConfigDirectories, outputStream: customOutputStream ?? self.outputStream, logLevel: customLogLevel ?? self.logLevel, fileSystem: self.fileSystem, diff --git a/Sources/CoreCommands/Options.swift b/Sources/CoreCommands/Options.swift index 7126bdc7043..28f1d97b602 100644 --- a/Sources/CoreCommands/Options.swift +++ b/Sources/CoreCommands/Options.swift @@ -89,9 +89,13 @@ public struct LocationOptions: ParsableArguments { @Option( name: .customLong("pkg-config-path"), - help: "Specify alternate paths to search for pkg-config `.pc` files,", + help: + """ + Specify alternate path to search for pkg-config `.pc` files. You can use the option multiple times to + specify more than one path. + """, completion: .directory) - public var pkgConfigDirectory: AbsolutePath? + public var pkgConfigDirectories: [AbsolutePath] } public struct CachingOptions: ParsableArguments { diff --git a/Sources/CoreCommands/SwiftTool.swift b/Sources/CoreCommands/SwiftTool.swift index 5a0eedbf123..88415cefd8b 100644 --- a/Sources/CoreCommands/SwiftTool.swift +++ b/Sources/CoreCommands/SwiftTool.swift @@ -591,7 +591,7 @@ public final class SwiftTool { archs: options.build.archs, flags: options.build.buildFlags, xcbuildFlags: options.build.xcbuildFlags, - pkgConfigDirectory: options.locations.pkgConfigDirectory, + pkgConfigDirectories: options.locations.pkgConfigDirectories, jobs: options.build.jobs ?? UInt32(ProcessInfo.processInfo.activeProcessorCount), shouldLinkStaticSwiftStdlib: options.linker.shouldLinkStaticSwiftStdlib, canRenameEntrypointFunctionName: DriverSupport.checkSupportedFrontendFlags( diff --git a/Sources/PackageLoading/Target+PkgConfig.swift b/Sources/PackageLoading/Target+PkgConfig.swift index 7d011ebab29..bf872f7ea93 100644 --- a/Sources/PackageLoading/Target+PkgConfig.swift +++ b/Sources/PackageLoading/Target+PkgConfig.swift @@ -60,7 +60,7 @@ public struct PkgConfigResult { /// Get pkgConfig result for a system library target. public func pkgConfigArgs( for target: SystemLibraryTarget, - pkgConfigDirectory: AbsolutePath?, + pkgConfigDirectories: [AbsolutePath], brewPrefix: AbsolutePath? = .none, fileSystem: FileSystem, observabilityScope: ObservabilityScope @@ -70,10 +70,13 @@ public func pkgConfigArgs( // Compute additional search paths for the provider, if any. let provider = target.providers?.first { $0.isAvailable } - var additionalSearchPaths = try provider?.pkgConfigSearchPath(brewPrefixOverride: brewPrefix) ?? [] - if let pkgConfigDirectory = pkgConfigDirectory { - // Give priority to `pkgConfigPath` passed as an argument to this function. - additionalSearchPaths.insert(pkgConfigDirectory, at: 0) + + let additionalSearchPaths: [AbsolutePath] + // Give priority to `pkgConfigDirectories` passed as an argument to this function. + if let providerSearchPaths = try provider?.pkgConfigSearchPath(brewPrefixOverride: brewPrefix) { + additionalSearchPaths = pkgConfigDirectories + providerSearchPaths + } else { + additionalSearchPaths = pkgConfigDirectories } var ret: [PkgConfigResult] = [] diff --git a/Sources/SPMBuildCore/BuildParameters.swift b/Sources/SPMBuildCore/BuildParameters.swift index 071001045af..677f3fcb4c1 100644 --- a/Sources/SPMBuildCore/BuildParameters.swift +++ b/Sources/SPMBuildCore/BuildParameters.swift @@ -137,7 +137,8 @@ public struct BuildParameters: Encodable { /// Extra build flags. public var flags: BuildFlags - public var pkgConfigDirectory: AbsolutePath? + /// An array of paths to search for pkg-config `.pc` files. + public var pkgConfigDirectories: [AbsolutePath] /// How many jobs should llbuild and the Swift compiler spawn public var jobs: UInt32 @@ -157,7 +158,7 @@ public struct BuildParameters: Encodable { /// Whether to enable code coverage. public var enableCodeCoverage: Bool - /// Whether to enable generation of `.swiftinterface` files alongside + /// Whether to enable generation of `.swiftinterface` files alongside. /// `.swiftmodule`s. public var enableParseableModuleInterfaces: Bool @@ -170,10 +171,10 @@ public struct BuildParameters: Encodable { /// to a separate process. public var useIntegratedSwiftDriver: Bool - /// Whether to use the explicit module build flow (with the integrated driver) + /// Whether to use the explicit module build flow (with the integrated driver). public var useExplicitModuleBuild: Bool - /// A flag that inidcates this build should check whether targets only import + /// A flag that inidcates this build should check whether targets only import. /// their explicitly-declared dependencies public var explicitTargetDependencyImportCheckingMode: TargetDependencyImportCheckingMode @@ -233,7 +234,7 @@ public struct BuildParameters: Encodable { archs: [String] = [], flags: BuildFlags, xcbuildFlags: [String] = [], - pkgConfigDirectory: AbsolutePath?, + pkgConfigDirectories: [AbsolutePath], jobs: UInt32 = UInt32(ProcessInfo.processInfo.activeProcessorCount), shouldLinkStaticSwiftStdlib: Bool = false, shouldEnableManifestCaching: Bool = false, @@ -264,7 +265,7 @@ public struct BuildParameters: Encodable { self.triple = triple self.archs = archs self.flags = flags - self.pkgConfigDirectory = pkgConfigDirectory + self.pkgConfigDirectories = pkgConfigDirectories self.xcbuildFlags = xcbuildFlags self.jobs = jobs self.shouldLinkStaticSwiftStdlib = shouldLinkStaticSwiftStdlib diff --git a/Sources/SPMBuildCore/PluginContextSerializer.swift b/Sources/SPMBuildCore/PluginContextSerializer.swift index 0ce516a44e1..62310695f6e 100644 --- a/Sources/SPMBuildCore/PluginContextSerializer.swift +++ b/Sources/SPMBuildCore/PluginContextSerializer.swift @@ -24,7 +24,7 @@ typealias WireInput = HostToPluginMessage.InputContext internal struct PluginContextSerializer { let fileSystem: FileSystem let buildEnvironment: BuildEnvironment - let pkgConfigDirectory: AbsolutePath? + let pkgConfigDirectories: [AbsolutePath] var paths: [WireInput.Path] = [] var pathsToIds: [AbsolutePath: WireInput.Path.Id] = [:] var targets: [WireInput.Target] = [] @@ -108,7 +108,7 @@ internal struct PluginContextSerializer { let observabilityScope = ObservabilitySystem({ _, _ in }).topScope for result in try pkgConfigArgs( for: target, - pkgConfigDirectory: pkgConfigDirectory, + pkgConfigDirectories: pkgConfigDirectories, fileSystem: fileSystem, observabilityScope: observabilityScope ) { diff --git a/Sources/SPMBuildCore/PluginInvocation.swift b/Sources/SPMBuildCore/PluginInvocation.swift index c42dbf029fe..d67f75e9d6c 100644 --- a/Sources/SPMBuildCore/PluginInvocation.swift +++ b/Sources/SPMBuildCore/PluginInvocation.swift @@ -59,7 +59,7 @@ extension PluginTarget { toolNamesToTriples: [String: [String]], writableDirectories: [AbsolutePath], readOnlyDirectories: [AbsolutePath], - pkgConfigDirectory: AbsolutePath?, + pkgConfigDirectories: [AbsolutePath], fileSystem: FileSystem, observabilityScope: ObservabilityScope, callbackQueue: DispatchQueue, @@ -80,7 +80,7 @@ extension PluginTarget { var serializer = PluginContextSerializer( fileSystem: fileSystem, buildEnvironment: buildEnvironment, - pkgConfigDirectory: pkgConfigDirectory + pkgConfigDirectories: pkgConfigDirectories ) let pluginWorkDirId = try serializer.serialize(path: outputDirectory) let toolSearchDirIds = try toolSearchDirectories.map{ try serializer.serialize(path: $0) } @@ -324,7 +324,7 @@ extension PackageGraph { builtToolsDir: AbsolutePath, buildEnvironment: BuildEnvironment, toolSearchDirectories: [AbsolutePath], - pkgConfigDirectory: AbsolutePath?, + pkgConfigDirectories: [AbsolutePath], pluginScriptRunner: PluginScriptRunner, observabilityScope: ObservabilityScope, fileSystem: FileSystem @@ -475,7 +475,7 @@ extension PackageGraph { toolNamesToTriples: toolNamesToTriples, writableDirectories: writableDirectories, readOnlyDirectories: readOnlyDirectories, - pkgConfigDirectory: pkgConfigDirectory, + pkgConfigDirectories: pkgConfigDirectories, fileSystem: fileSystem, observabilityScope: observabilityScope, callbackQueue: delegateQueue, diff --git a/Sources/XCBuildSupport/PIFBuilder.swift b/Sources/XCBuildSupport/PIFBuilder.swift index bd68dda0345..b96a6c3e5eb 100644 --- a/Sources/XCBuildSupport/PIFBuilder.swift +++ b/Sources/XCBuildSupport/PIFBuilder.swift @@ -32,7 +32,8 @@ struct PIFBuilderParameters { /// The path to the library directory of the active toolchain. let toolchainLibDir: AbsolutePath - let pkgConfigDirectory: AbsolutePath? + /// An array of paths to search for pkg-config `.pc` files. + let pkgConfigDirectories: [AbsolutePath] } /// PIF object builder for a package graph. @@ -702,7 +703,7 @@ final class PackagePIFProjectBuilder: PIFProjectBuilder { var cFlags: [String] = [] for result in try pkgConfigArgs( for: systemTarget, - pkgConfigDirectory: parameters.pkgConfigDirectory, + pkgConfigDirectories: parameters.pkgConfigDirectories, fileSystem: fileSystem, observabilityScope: observabilityScope ) { diff --git a/Sources/XCBuildSupport/XcodeBuildSystem.swift b/Sources/XCBuildSupport/XcodeBuildSystem.swift index 0ce95d9abc7..7f8740a70c6 100644 --- a/Sources/XCBuildSupport/XcodeBuildSystem.swift +++ b/Sources/XCBuildSupport/XcodeBuildSystem.swift @@ -301,7 +301,7 @@ extension PIFBuilderParameters { enableTestability: buildParameters.enableTestability, shouldCreateDylibForDynamicProducts: buildParameters.shouldCreateDylibForDynamicProducts, toolchainLibDir: (try? buildParameters.toolchain.toolchainLibDir) ?? .root, - pkgConfigDirectory: buildParameters.pkgConfigDirectory + pkgConfigDirectories: buildParameters.pkgConfigDirectories ) } } diff --git a/Tests/BuildTests/MockBuildTestHelper.swift b/Tests/BuildTests/MockBuildTestHelper.swift index d9852017a19..e8193791717 100644 --- a/Tests/BuildTests/MockBuildTestHelper.swift +++ b/Tests/BuildTests/MockBuildTestHelper.swift @@ -77,7 +77,7 @@ func mockBuildParameters( hostTriple: hostTriple, destinationTriple: destinationTriple, flags: flags, - pkgConfigDirectory: nil, + pkgConfigDirectories: [], jobs: 3, shouldLinkStaticSwiftStdlib: shouldLinkStaticSwiftStdlib, canRenameEntrypointFunctionName: canRenameEntrypointFunctionName, diff --git a/Tests/PackageLoadingTests/PkgConfigTests.swift b/Tests/PackageLoadingTests/PkgConfigTests.swift index d0d94fa3c6c..978f2ee94fc 100644 --- a/Tests/PackageLoadingTests/PkgConfigTests.swift +++ b/Tests/PackageLoadingTests/PkgConfigTests.swift @@ -38,7 +38,7 @@ class PkgConfigTests: XCTestCase { let observability = ObservabilitySystem.makeForTesting() let result = try pkgConfigArgs( for: SystemLibraryTarget(pkgConfig: ""), - pkgConfigDirectory: nil, + pkgConfigDirectories: [], fileSystem: fs, observabilityScope: observability.topScope ) @@ -60,7 +60,7 @@ class PkgConfigTests: XCTestCase { ) for result in try pkgConfigArgs( for: target, - pkgConfigDirectory: nil, + pkgConfigDirectories: [], fileSystem: fs, observabilityScope: observability.topScope) { XCTAssertEqual(result.pkgConfigName, "Foo") @@ -92,7 +92,7 @@ class PkgConfigTests: XCTestCase { let observability = ObservabilitySystem.makeForTesting() for result in try pkgConfigArgs( for: SystemLibraryTarget(pkgConfig: "Foo"), - pkgConfigDirectory: nil, + pkgConfigDirectories: [], fileSystem: fs, observabilityScope: observability.topScope ) { @@ -110,7 +110,7 @@ class PkgConfigTests: XCTestCase { let observability = ObservabilitySystem.makeForTesting() for result in try pkgConfigArgs( for: SystemLibraryTarget(pkgConfig: "Bar"), - pkgConfigDirectory: nil, + pkgConfigDirectories: [], fileSystem: fs, observabilityScope: observability.topScope ) { @@ -133,7 +133,7 @@ class PkgConfigTests: XCTestCase { let observability = ObservabilitySystem.makeForTesting() for result in try pkgConfigArgs( for: SystemLibraryTarget(pkgConfig: "Framework"), - pkgConfigDirectory: nil, + pkgConfigDirectories: [], fileSystem: fs, observabilityScope: observability.topScope ) { diff --git a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift b/Tests/SPMBuildCoreTests/PluginInvocationTests.swift index 6156f2f7663..91056c80865 100644 --- a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift +++ b/Tests/SPMBuildCoreTests/PluginInvocationTests.swift @@ -194,7 +194,7 @@ class PluginInvocationTests: XCTestCase { builtToolsDir: builtToolsDir, buildEnvironment: BuildEnvironment(platform: .macOS, configuration: .debug), toolSearchDirectories: [UserToolchain.default.swiftCompilerPath.parentDirectory], - pkgConfigDirectory: nil, + pkgConfigDirectories: [], pluginScriptRunner: pluginRunner, observabilityScope: observability.topScope, fileSystem: fileSystem @@ -887,7 +887,7 @@ class PluginInvocationTests: XCTestCase { builtToolsDir: builtToolsDir, buildEnvironment: BuildEnvironment(platform: .macOS, configuration: .debug), toolSearchDirectories: [UserToolchain.default.swiftCompilerPath.parentDirectory], - pkgConfigDirectory: nil, + pkgConfigDirectories: [], pluginScriptRunner: pluginScriptRunner, observabilityScope: observability.topScope, fileSystem: localFileSystem @@ -1184,7 +1184,7 @@ class PluginInvocationTests: XCTestCase { builtToolsDir: builtToolsDir, buildEnvironment: BuildEnvironment(platform: .macOS, configuration: .debug), toolSearchDirectories: [UserToolchain.default.swiftCompilerPath.parentDirectory], - pkgConfigDirectory: nil, + pkgConfigDirectories: [], pluginScriptRunner: pluginScriptRunner, observabilityScope: observability.topScope, fileSystem: localFileSystem diff --git a/Tests/XCBuildSupportTests/PIFBuilderTests.swift b/Tests/XCBuildSupportTests/PIFBuilderTests.swift index 4815654cb81..c602a50e867 100644 --- a/Tests/XCBuildSupportTests/PIFBuilderTests.swift +++ b/Tests/XCBuildSupportTests/PIFBuilderTests.swift @@ -2615,7 +2615,7 @@ extension PIFBuilderParameters { enableTestability: false, shouldCreateDylibForDynamicProducts: shouldCreateDylibForDynamicProducts, toolchainLibDir: AbsolutePath(path: "/toolchain/lib"), - pkgConfigDirectory: AbsolutePath(path: "/pkg-config") + pkgConfigDirectories: [AbsolutePath(path: "/pkg-config")] ) } } From 4f6ab920e2ee374eb9981c66159c4b99fbb8a93d Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 15 Dec 2022 11:49:49 +0000 Subject: [PATCH 4/9] Add a doc comment, default value for `pkg-config-path` --- Sources/Build/BuildOperation.swift | 1 + Sources/CoreCommands/Options.swift | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Sources/Build/BuildOperation.swift b/Sources/Build/BuildOperation.swift index f2d8c4032eb..26256155cce 100644 --- a/Sources/Build/BuildOperation.swift +++ b/Sources/Build/BuildOperation.swift @@ -95,6 +95,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS /// File rules to determine resource handling behavior. private let additionalFileRules: [FileRuleDescription] + /// Alternative path to search for pkg-config `.pc` files. private let pkgConfigDirectories: [AbsolutePath] public init( diff --git a/Sources/CoreCommands/Options.swift b/Sources/CoreCommands/Options.swift index 28f1d97b602..c63d986ea31 100644 --- a/Sources/CoreCommands/Options.swift +++ b/Sources/CoreCommands/Options.swift @@ -91,11 +91,11 @@ public struct LocationOptions: ParsableArguments { name: .customLong("pkg-config-path"), help: """ - Specify alternate path to search for pkg-config `.pc` files. You can use the option multiple times to + Specify alternative path to search for pkg-config `.pc` files. You can use the option multiple times to specify more than one path. """, completion: .directory) - public var pkgConfigDirectories: [AbsolutePath] + public var pkgConfigDirectories: [AbsolutePath] = [] } public struct CachingOptions: ParsableArguments { From 579d77ef136f8fab5a4a9bab6cda2782d213cae5 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 15 Dec 2022 11:49:56 +0000 Subject: [PATCH 5/9] Clean up doc comments --- Sources/Build/BuildOperation.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/Build/BuildOperation.swift b/Sources/Build/BuildOperation.swift index 26256155cce..8802ba9990c 100644 --- a/Sources/Build/BuildOperation.swift +++ b/Sources/Build/BuildOperation.swift @@ -79,13 +79,13 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS /// The output stream for the build delegate. private let outputStream: OutputByteStream - /// The verbosity level to print out at + /// The verbosity level to use for diagnostics. private let logLevel: Basics.Diagnostic.Severity - /// File system to operate on + /// File system to operate on. private let fileSystem: TSCBasic.FileSystem - /// ObservabilityScope with which to emit diagnostics + /// ObservabilityScope with which to emit diagnostics. private let observabilityScope: ObservabilityScope public var builtTestProducts: [BuiltTestProduct] { From 691fa41a0f0708ff60117ff946eaa66e5aafb807 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 15 Dec 2022 14:36:48 +0000 Subject: [PATCH 6/9] BuildParameters: add a default value for `pkgConfigDirectories` --- Sources/SPMBuildCore/BuildParameters.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SPMBuildCore/BuildParameters.swift b/Sources/SPMBuildCore/BuildParameters.swift index 677f3fcb4c1..2943acf44e6 100644 --- a/Sources/SPMBuildCore/BuildParameters.swift +++ b/Sources/SPMBuildCore/BuildParameters.swift @@ -234,7 +234,7 @@ public struct BuildParameters: Encodable { archs: [String] = [], flags: BuildFlags, xcbuildFlags: [String] = [], - pkgConfigDirectories: [AbsolutePath], + pkgConfigDirectories: [AbsolutePath] = [], jobs: UInt32 = UInt32(ProcessInfo.processInfo.activeProcessorCount), shouldLinkStaticSwiftStdlib: Bool = false, shouldEnableManifestCaching: Bool = false, From ca156445b23e991fca66278ecf13184cb568e6b0 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 15 Dec 2022 15:28:41 +0000 Subject: [PATCH 7/9] Add tests for new `pkgConfigDirectories` property --- .../PackageLoadingTests/PkgConfigTests.swift | 71 ++++++++++++++++--- 1 file changed, 62 insertions(+), 9 deletions(-) diff --git a/Tests/PackageLoadingTests/PkgConfigTests.swift b/Tests/PackageLoadingTests/PkgConfigTests.swift index 978f2ee94fc..f7770cb48f4 100644 --- a/Tests/PackageLoadingTests/PkgConfigTests.swift +++ b/Tests/PackageLoadingTests/PkgConfigTests.swift @@ -29,13 +29,12 @@ extension SystemLibraryTarget { class PkgConfigTests: XCTestCase { let inputsDir = AbsolutePath(path: #file).parentDirectory.appending(components: "Inputs") + let observability = ObservabilitySystem.makeForTesting() + let fs = localFileSystem func testBasics() throws { - let fs = localFileSystem - // No pkgConfig name. do { - let observability = ObservabilitySystem.makeForTesting() let result = try pkgConfigArgs( for: SystemLibraryTarget(pkgConfig: ""), pkgConfigDirectories: [], @@ -47,8 +46,6 @@ class PkgConfigTests: XCTestCase { // No pc file. do { - let observability = ObservabilitySystem.makeForTesting() - let target = SystemLibraryTarget( pkgConfig: "Foo", providers: [ @@ -86,10 +83,11 @@ class PkgConfigTests: XCTestCase { } } } + } + func testEnvVar() throws { // Pc file. try withCustomEnv(["PKG_CONFIG_PATH": inputsDir.pathString]) { - let observability = ObservabilitySystem.makeForTesting() for result in try pkgConfigArgs( for: SystemLibraryTarget(pkgConfig: "Foo"), pkgConfigDirectories: [], @@ -107,7 +105,6 @@ class PkgConfigTests: XCTestCase { // Pc file with prohibited flags. try withCustomEnv(["PKG_CONFIG_PATH": inputsDir.pathString]) { - let observability = ObservabilitySystem.makeForTesting() for result in try pkgConfigArgs( for: SystemLibraryTarget(pkgConfig: "Bar"), pkgConfigDirectories: [], @@ -130,7 +127,6 @@ class PkgConfigTests: XCTestCase { // Pc file with -framework Framework flag. try withCustomEnv(["PKG_CONFIG_PATH": inputsDir.pathString]) { - let observability = ObservabilitySystem.makeForTesting() for result in try pkgConfigArgs( for: SystemLibraryTarget(pkgConfig: "Framework"), pkgConfigDirectories: [], @@ -152,10 +148,67 @@ class PkgConfigTests: XCTestCase { } } + func testExplicitPkgConfigDirectories() throws { + // Pc file. + for result in try pkgConfigArgs( + for: SystemLibraryTarget(pkgConfig: "Foo"), + pkgConfigDirectories: [inputsDir], + fileSystem: fs, + observabilityScope: observability.topScope + ) { + XCTAssertEqual(result.pkgConfigName, "Foo") + XCTAssertEqual(result.cFlags, ["-I/path/to/inc", "-I\(inputsDir.pathString)"]) + XCTAssertEqual(result.libs, ["-L/usr/da/lib", "-lSystemModule", "-lok"]) + XCTAssertNil(result.provider) + XCTAssertNil(result.error) + XCTAssertFalse(result.couldNotFindConfigFile) + } + + // Pc file with prohibited flags. + for result in try pkgConfigArgs( + for: SystemLibraryTarget(pkgConfig: "Bar"), + pkgConfigDirectories: [inputsDir], + fileSystem: fs, + observabilityScope: observability.topScope + ) { + XCTAssertEqual(result.pkgConfigName, "Bar") + XCTAssertEqual(result.cFlags, ["-I/path/to/inc"]) + XCTAssertEqual(result.libs, ["-L/usr/da/lib", "-lSystemModule", "-lok"]) + XCTAssertNil(result.provider) + XCTAssertFalse(result.couldNotFindConfigFile) + switch result.error { + case PkgConfigError.prohibitedFlags(let desc)?: + XCTAssertEqual(desc, "-DDenyListed") + default: + XCTFail("unexpected error \(result.error.debugDescription)") + } + } + + // Pc file with -framework Framework flag. + let observability = ObservabilitySystem.makeForTesting() + for result in try pkgConfigArgs( + for: SystemLibraryTarget(pkgConfig: "Framework"), + pkgConfigDirectories: [inputsDir], + fileSystem: fs, + observabilityScope: observability.topScope + ) { + XCTAssertEqual(result.pkgConfigName, "Framework") + XCTAssertEqual(result.cFlags, ["-F/usr/lib"]) + XCTAssertEqual(result.libs, ["-F/usr/lib", "-framework", "SystemFramework"]) + XCTAssertNil(result.provider) + XCTAssertFalse(result.couldNotFindConfigFile) + switch result.error { + case PkgConfigError.prohibitedFlags(let desc)?: + XCTAssertEqual(desc, "-DDenyListed") + default: + XCTFail("unexpected error \(result.error.debugDescription)") + } + } + } + func testDependencies() throws { // Use additionalSearchPaths instead of pkgConfigArgs to test handling // of search paths when loading dependencies. - let observability = ObservabilitySystem.makeForTesting() let result = try PkgConfig( name: "Dependent", additionalSearchPaths: [inputsDir], From 2427ee991e8f2c684677dda02b6ed3220ec02d0c Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 15 Dec 2022 17:54:43 +0000 Subject: [PATCH 8/9] Add a function test, update `CHANGELOG.md` --- CHANGELOG.md | 9 +++++++++ Sources/CoreCommands/Options.swift | 2 +- Tests/FunctionalTests/MiscellaneousTests.swift | 9 ++++++++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0da7767cd8..b1a3f38edd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ Note: This is in reverse chronological order, so newer entries are added to the top. +Swift Next +----------- +* [#5949] + + New `--pkg-config-path` option on `build`, `test`, and `run` commands has been + introduced as an alternative to passing `PKG_CONFIG_PATH` environment variable. + It allows specifying alternative path to search for `.pc` files used by + `pkg-config`. Use the option multiple times to specify more than one path. + Swift 5.8 ----------- diff --git a/Sources/CoreCommands/Options.swift b/Sources/CoreCommands/Options.swift index c63d986ea31..838893326e0 100644 --- a/Sources/CoreCommands/Options.swift +++ b/Sources/CoreCommands/Options.swift @@ -91,7 +91,7 @@ public struct LocationOptions: ParsableArguments { name: .customLong("pkg-config-path"), help: """ - Specify alternative path to search for pkg-config `.pc` files. You can use the option multiple times to + Specify alternative path to search for pkg-config `.pc` files. Use the option multiple times to specify more than one path. """, completion: .directory) diff --git a/Tests/FunctionalTests/MiscellaneousTests.swift b/Tests/FunctionalTests/MiscellaneousTests.swift index 9bdebaafcc7..60561d635c2 100644 --- a/Tests/FunctionalTests/MiscellaneousTests.swift +++ b/Tests/FunctionalTests/MiscellaneousTests.swift @@ -197,7 +197,6 @@ class MiscellaneousTestCase: XCTestCase { #endif } - func testOverridingDeploymentTargetUsingSwiftCompilerArgument() throws { #if !os(macOS) try XCTSkipIf(true, "test is only supported on macOS") @@ -240,6 +239,14 @@ class MiscellaneousTestCase: XCTestCase { _ = try executeSwiftBuild(moduleUser, env: env) XCTAssertFileExists(moduleUser.appending(components: ".build", triple.platformBuildPathComponent(), "debug", "SystemModuleUserClang")) + + // Clean up the build directory before re-running the build with + // different arguments. + _ = try executeSwiftPackage(moduleUser, extraArgs: ["clean"]) + + _ = try executeSwiftBuild(moduleUser, extraArgs: ["--pkg-config-path", fixturePath.pathString]) + + XCTAssertFileExists(moduleUser.appending(components: ".build", triple.platformBuildPathComponent(), "debug", "SystemModuleUserClang")) } } From 01fda9ceabeb6a5a8446c3485a684bfd23acba25 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 19 Dec 2022 20:02:16 +0000 Subject: [PATCH 9/9] Update CHANGELOG.md --- CHANGELOG.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1a3f38edd7..c0a4c747638 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ Note: This is in reverse chronological order, so newer entries are added to the top. -Swift Next +Swift 5.8 ----------- + * [#5949] New `--pkg-config-path` option on `build`, `test`, and `run` commands has been @@ -9,9 +10,6 @@ Swift Next It allows specifying alternative path to search for `.pc` files used by `pkg-config`. Use the option multiple times to specify more than one path. -Swift 5.8 ------------ - * [#5874] 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.