diff --git a/CHANGELOG.md b/CHANGELOG.md index a0da7767cd8..c0a4c747638 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ Note: This is in reverse chronological order, so newer entries are added to the Swift 5.8 ----------- +* [#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. + * [#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. diff --git a/Sources/Build/BuildOperation.swift b/Sources/Build/BuildOperation.swift index d7cb58a2b3a..e449d9ba21f 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] { @@ -95,6 +95,9 @@ 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( buildParameters: BuildParameters, cacheBuildManifest: Bool, @@ -103,6 +106,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS pluginScriptRunner: PluginScriptRunner, pluginWorkDirectory: AbsolutePath, disableSandboxForPluginCommands: Bool, + pkgConfigDirectories: [AbsolutePath], outputStream: OutputByteStream, logLevel: Basics.Diagnostic.Severity, fileSystem: TSCBasic.FileSystem, @@ -118,6 +122,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS self.additionalFileRules = additionalFileRules self.pluginScriptRunner = pluginScriptRunner self.pluginWorkDirectory = pluginWorkDirectory + self.pkgConfigDirectories = pkgConfigDirectories self.disableSandboxForPluginCommands = disableSandboxForPluginCommands self.outputStream = outputStream self.logLevel = logLevel @@ -399,6 +404,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS builtToolsDir: self.buildParameters.buildPath, buildEnvironment: self.buildParameters.buildEnvironment, toolSearchDirectories: [self.buildParameters.toolchain.swiftCompilerPath.parentDirectory], + 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 6a02d6bd822..2239d1bbc6d 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, + pkgConfigDirectories: buildParameters.pkgConfigDirectories, + fileSystem: fileSystem, + observabilityScope: observabilityScope + ) var ret: [(cFlags: [String], libs: [String])] = [] for result in results { ret.append((result.cFlags, result.libs)) diff --git a/Sources/Commands/PackageTools/PluginCommand.swift b/Sources/Commands/PackageTools/PluginCommand.swift index afeaceebeb7..ee3eab92571 100644 --- a/Sources/Commands/PackageTools/PluginCommand.swift +++ b/Sources/Commands/PackageTools/PluginCommand.swift @@ -188,6 +188,7 @@ struct PluginCommand: SwiftCommand { toolNamesToTriples: toolNamesToTriples, writableDirectories: writableDirectories, readOnlyDirectories: readOnlyDirectories, + 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 c57120a0985..383a9879a4f 100644 --- a/Sources/CoreCommands/BuildSystemSupport.swift +++ b/Sources/CoreCommands/BuildSystemSupport.swift @@ -34,6 +34,7 @@ extension SwiftTool { pluginScriptRunner: self.getPluginScriptRunner(), pluginWorkDirectory: try self.getActiveWorkspace().location.pluginWorkingDirectory, disableSandboxForPluginCommands: self.options.security.shouldDisableSandbox, + 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 0c2b971d0cc..7e7070921cc 100644 --- a/Sources/CoreCommands/Options.swift +++ b/Sources/CoreCommands/Options.swift @@ -86,6 +86,16 @@ public struct LocationOptions: ParsableArguments { @Option(name: .customLong("experimental-destinations-path"), help: .hidden, completion: .directory) public var crossCompilationDestinationsDirectory: AbsolutePath? + + @Option( + name: .customLong("pkg-config-path"), + help: + """ + Specify alternative path to search for pkg-config `.pc` files. Use the option multiple times to + specify more than one path. + """, + completion: .directory) + public var pkgConfigDirectories: [AbsolutePath] = [] } public struct CachingOptions: ParsableArguments { diff --git a/Sources/CoreCommands/SwiftTool.swift b/Sources/CoreCommands/SwiftTool.swift index de8012a2a21..ec4dd4418f4 100644 --- a/Sources/CoreCommands/SwiftTool.swift +++ b/Sources/CoreCommands/SwiftTool.swift @@ -296,11 +296,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.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 fileSystem.getSharedCrossCompilationDestinationsDirectory( - explicitDirectory: self.options.locations.crossCompilationDestinationsDirectory + explicitDirectory: options.locations.crossCompilationDestinationsDirectory ) // set global process logging handler @@ -593,6 +593,7 @@ public final class SwiftTool { archs: options.build.archs, flags: options.build.buildFlags, xcbuildFlags: options.build.xcbuildFlags, + 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 81217d38f03..bf872f7ea93 100644 --- a/Sources/PackageLoading/Target+PkgConfig.swift +++ b/Sources/PackageLoading/Target+PkgConfig.swift @@ -58,15 +58,28 @@ 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, + pkgConfigDirectories: [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 ret: [PkgConfigResult] = [] + 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] = [] // Get the pkg config flags. for pkgConfigName in pkgConfigNames.components(separatedBy: " ") { let result: PkgConfigResult @@ -92,11 +105,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 +117,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..2943acf44e6 100644 --- a/Sources/SPMBuildCore/BuildParameters.swift +++ b/Sources/SPMBuildCore/BuildParameters.swift @@ -137,6 +137,9 @@ public struct BuildParameters: Encodable { /// Extra build flags. public var flags: BuildFlags + /// 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 @@ -155,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 @@ -168,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 @@ -231,6 +234,7 @@ public struct BuildParameters: Encodable { archs: [String] = [], flags: BuildFlags, xcbuildFlags: [String] = [], + pkgConfigDirectories: [AbsolutePath] = [], jobs: UInt32 = UInt32(ProcessInfo.processInfo.activeProcessorCount), shouldLinkStaticSwiftStdlib: Bool = false, shouldEnableManifestCaching: Bool = false, @@ -261,6 +265,7 @@ public struct BuildParameters: Encodable { self.triple = triple self.archs = archs self.flags = flags + 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 a121fd9ad63..62310695f6e 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 pkgConfigDirectories: [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, + pkgConfigDirectories: pkgConfigDirectories, + 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 1608e0d7f49..64723873c15 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], + pkgConfigDirectories: [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, + pkgConfigDirectories: pkgConfigDirectories + ) 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) } @@ -325,6 +331,7 @@ extension PackageGraph { builtToolsDir: AbsolutePath, buildEnvironment: BuildEnvironment, toolSearchDirectories: [AbsolutePath], + pkgConfigDirectories: [AbsolutePath], pluginScriptRunner: PluginScriptRunner, observabilityScope: ObservabilityScope, fileSystem: FileSystem @@ -466,6 +473,7 @@ extension PackageGraph { toolNamesToTriples: toolNamesToTriples, writableDirectories: writableDirectories, readOnlyDirectories: readOnlyDirectories, + pkgConfigDirectories: pkgConfigDirectories, fileSystem: fileSystem, observabilityScope: observabilityScope, callbackQueue: delegateQueue, diff --git a/Sources/XCBuildSupport/PIFBuilder.swift b/Sources/XCBuildSupport/PIFBuilder.swift index ab403b29edd..b96a6c3e5eb 100644 --- a/Sources/XCBuildSupport/PIFBuilder.swift +++ b/Sources/XCBuildSupport/PIFBuilder.swift @@ -24,23 +24,16 @@ 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 - } + /// An array of paths to search for pkg-config `.pc` files. + let pkgConfigDirectories: [AbsolutePath] } /// PIF object builder for a package graph. @@ -708,7 +701,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, + pkgConfigDirectories: parameters.pkgConfigDirectories, + 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..7f8740a70c6 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, + pkgConfigDirectories: buildParameters.pkgConfigDirectories ) } } diff --git a/Tests/BuildTests/MockBuildTestHelper.swift b/Tests/BuildTests/MockBuildTestHelper.swift index 79f97bf39a9..e8193791717 100644 --- a/Tests/BuildTests/MockBuildTestHelper.swift +++ b/Tests/BuildTests/MockBuildTestHelper.swift @@ -77,6 +77,7 @@ func mockBuildParameters( hostTriple: hostTriple, destinationTriple: destinationTriple, flags: flags, + pkgConfigDirectories: [], jobs: 3, shouldLinkStaticSwiftStdlib: shouldLinkStaticSwiftStdlib, canRenameEntrypointFunctionName: canRenameEntrypointFunctionName, 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")) } } diff --git a/Tests/PackageLoadingTests/PkgConfigTests.swift b/Tests/PackageLoadingTests/PkgConfigTests.swift index 108a15bff80..f7770cb48f4 100644 --- a/Tests/PackageLoadingTests/PkgConfigTests.swift +++ b/Tests/PackageLoadingTests/PkgConfigTests.swift @@ -29,21 +29,23 @@ 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: ""), fileSystem: fs, observabilityScope: observability.topScope) + let result = try pkgConfigArgs( + for: SystemLibraryTarget(pkgConfig: ""), + pkgConfigDirectories: [], + fileSystem: fs, + observabilityScope: observability.topScope + ) XCTAssertTrue(result.isEmpty) } // No pc file. do { - let observability = ObservabilitySystem.makeForTesting() - let target = SystemLibraryTarget( pkgConfig: "Foo", providers: [ @@ -53,7 +55,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, + pkgConfigDirectories: [], + fileSystem: fs, + observabilityScope: observability.topScope) { XCTAssertEqual(result.pkgConfigName, "Foo") XCTAssertEqual(result.cFlags, []) XCTAssertEqual(result.libs, []) @@ -77,11 +83,17 @@ 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"), fileSystem: fs, observabilityScope: observability.topScope) { + for result in try pkgConfigArgs( + for: SystemLibraryTarget(pkgConfig: "Foo"), + pkgConfigDirectories: [], + 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"]) @@ -93,8 +105,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"), + pkgConfigDirectories: [], + 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"]) @@ -111,8 +127,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"), + pkgConfigDirectories: [], + fileSystem: fs, + observabilityScope: observability.topScope + ) { XCTAssertEqual(result.pkgConfigName, "Framework") XCTAssertEqual(result.cFlags, ["-F/usr/lib"]) XCTAssertEqual(result.libs, ["-F/usr/lib", "-framework", "SystemFramework"]) @@ -128,11 +148,73 @@ 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], 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 3af1cdd107c..ff203fa0760 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], + pkgConfigDirectories: [], pluginScriptRunner: pluginRunner, observabilityScope: observability.topScope, fileSystem: fileSystem @@ -886,6 +887,7 @@ class PluginInvocationTests: XCTestCase { builtToolsDir: builtToolsDir, buildEnvironment: BuildEnvironment(platform: .macOS, configuration: .debug), toolSearchDirectories: [UserToolchain.default.swiftCompilerPath.parentDirectory], + pkgConfigDirectories: [], pluginScriptRunner: pluginScriptRunner, observabilityScope: observability.topScope, fileSystem: localFileSystem @@ -1188,6 +1190,7 @@ class PluginInvocationTests: XCTestCase { builtToolsDir: builtToolsDir, buildEnvironment: BuildEnvironment(platform: .macOS, configuration: .debug), toolSearchDirectories: [UserToolchain.default.swiftCompilerPath.parentDirectory], + pkgConfigDirectories: [], pluginScriptRunner: pluginScriptRunner, observabilityScope: observability.topScope, fileSystem: localFileSystem diff --git a/Tests/XCBuildSupportTests/PIFBuilderTests.swift b/Tests/XCBuildSupportTests/PIFBuilderTests.swift index 3daf14be122..c602a50e867 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"), + pkgConfigDirectories: [AbsolutePath(path: "/pkg-config")] ) } }