Skip to content

Commit dfccfb1

Browse files
authored
[PackageLoading] Fix inconsistent .systemLibrary's pkgBuild parsing (#3080)
* [PackageLoading] Fix inconsistent .systemLibrary's pkgBuild parsing (especially on Arch Linux)
1 parent bfde016 commit dfccfb1

File tree

5 files changed

+105
-81
lines changed

5 files changed

+105
-81
lines changed

Sources/Build/BuildPlan.swift

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1748,21 +1748,38 @@ public class BuildPlan {
17481748
if let flags = pkgConfigCache[target] {
17491749
return flags
17501750
}
1751-
// Otherwise, get the result and cache it.
1752-
guard let result = pkgConfigArgs(for: target, diagnostics: diagnostics) else {
1751+
else {
17531752
pkgConfigCache[target] = ([], [])
1754-
return pkgConfigCache[target]!
1755-
}
1756-
// If there is no pc file on system and we have an available provider, emit a warning.
1757-
if let provider = result.provider, result.couldNotFindConfigFile {
1758-
diagnostics.emit(.pkgConfigHint(pkgConfigName: result.pkgConfigName, installText: provider.installText))
1759-
} else if let error = result.error {
1760-
diagnostics.emit(
1761-
.warning(PkgConfigGenericDiagnostic(error: "\(error)")),
1762-
location: PkgConfigDiagnosticLocation(pcFile: result.pkgConfigName, target: target.name)
1763-
)
17641753
}
1765-
pkgConfigCache[target] = (result.cFlags, result.libs)
1754+
let results = pkgConfigArgs(for: target, diagnostics: diagnostics)
1755+
var ret: [(cFlags: [String], libs: [String])] = []
1756+
for result in results {
1757+
// If there is no pc file on system and we have an available provider, emit a warning.
1758+
if let provider = result.provider, result.couldNotFindConfigFile {
1759+
diagnostics.emit(.pkgConfigHint(pkgConfigName: result.pkgConfigName, installText: provider.installText))
1760+
} else if let error = result.error {
1761+
diagnostics.emit(
1762+
.warning(PkgConfigGenericDiagnostic(error: "\(error)")),
1763+
location: PkgConfigDiagnosticLocation(pcFile: result.pkgConfigName, target: target.name)
1764+
)
1765+
}
1766+
1767+
ret.append((result.cFlags, result.libs))
1768+
}
1769+
1770+
// Build cache
1771+
var cflagsCache: OrderedSet<String> = []
1772+
var libsCache: [String] = []
1773+
for tuple in ret {
1774+
for cFlag in tuple.cFlags {
1775+
cflagsCache.append(cFlag)
1776+
}
1777+
1778+
libsCache.append(contentsOf: tuple.libs)
1779+
}
1780+
1781+
pkgConfigCache[target] = ([String](cflagsCache), libsCache)
1782+
17661783
return pkgConfigCache[target]!
17671784
}
17681785

Sources/PackageLoading/Target+PkgConfig.swift

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -55,45 +55,49 @@ public struct PkgConfigResult {
5555
}
5656

5757
/// Get pkgConfig result for a system library target.
58-
public func pkgConfigArgs(for target: SystemLibraryTarget, diagnostics: DiagnosticsEngine, fileSystem: FileSystem = localFileSystem, brewPrefix: AbsolutePath? = nil) -> PkgConfigResult? {
58+
public func pkgConfigArgs(for target: SystemLibraryTarget, diagnostics: DiagnosticsEngine, fileSystem: FileSystem = localFileSystem, brewPrefix: AbsolutePath? = nil) -> [PkgConfigResult] {
5959
// If there is no pkg config name defined, we're done.
60-
guard let pkgConfigName = target.pkgConfig else { return nil }
60+
guard let pkgConfigNames = target.pkgConfig else { return [] }
6161

6262
// Compute additional search paths for the provider, if any.
6363
let provider = target.providers?.first { $0.isAvailable }
6464
let additionalSearchPaths = provider?.pkgConfigSearchPath(brewPrefixOverride: brewPrefix) ?? []
6565

66+
var ret: [PkgConfigResult] = []
6667
// Get the pkg config flags.
67-
do {
68-
let pkgConfig = try PkgConfig(
69-
name: pkgConfigName,
70-
additionalSearchPaths: additionalSearchPaths,
71-
diagnostics: diagnostics,
72-
fileSystem: fileSystem,
73-
brewPrefix: brewPrefix)
74-
75-
// Run the allow list checker.
76-
let filtered = allowlist(pcFile: pkgConfigName, flags: (pkgConfig.cFlags, pkgConfig.libs))
77-
78-
// Remove any default flags which compiler adds automatically.
79-
let (cFlags, libs) = removeDefaultFlags(cFlags: filtered.cFlags, libs: filtered.libs)
80-
81-
// Set the error if there are any unallowed flags.
82-
var error: Swift.Error?
83-
if !filtered.unallowed.isEmpty {
84-
error = PkgConfigError.prohibitedFlags(filtered.unallowed.joined(separator: ", "))
85-
}
68+
for pkgConfigName in pkgConfigNames.components(separatedBy: " ") {
69+
do {
70+
let pkgConfig = try PkgConfig(
71+
name: pkgConfigName,
72+
additionalSearchPaths: additionalSearchPaths,
73+
diagnostics: diagnostics,
74+
fileSystem: fileSystem,
75+
brewPrefix: brewPrefix)
76+
77+
// Run the allow list checker.
78+
let filtered = allowlist(pcFile: pkgConfigName, flags: (pkgConfig.cFlags, pkgConfig.libs))
79+
80+
// Remove any default flags which compiler adds automatically.
81+
let (cFlags, libs) = removeDefaultFlags(cFlags: filtered.cFlags, libs: filtered.libs)
82+
83+
// Set the error if there are any unallowed flags.
84+
var error: Swift.Error?
85+
if !filtered.unallowed.isEmpty {
86+
error = PkgConfigError.prohibitedFlags(filtered.unallowed.joined(separator: ", "))
87+
}
8688

87-
return PkgConfigResult(
88-
pkgConfigName: pkgConfigName,
89-
cFlags: cFlags,
90-
libs: libs,
91-
error: error,
92-
provider: provider
93-
)
94-
} catch {
95-
return PkgConfigResult(pkgConfigName: pkgConfigName, error: error, provider: provider)
89+
ret.append(PkgConfigResult(
90+
pkgConfigName: pkgConfigName,
91+
cFlags: cFlags,
92+
libs: libs,
93+
error: error,
94+
provider: provider
95+
))
96+
} catch {
97+
ret.append(PkgConfigResult(pkgConfigName: pkgConfigName, error: error, provider: provider))
98+
}
9699
}
100+
return ret
97101
}
98102

99103
extension SystemPackageProviderDescription {

Sources/XCBuildSupport/PIFBuilder.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,7 @@ final class PackagePIFProjectBuilder: PIFProjectBuilder {
658658
var impartedSettings = PIF.BuildSettings()
659659

660660
var cFlags: [String] = []
661-
if let result = pkgConfigArgs(for: systemTarget, diagnostics: diagnostics, fileSystem: fileSystem) {
661+
for result in pkgConfigArgs(for: systemTarget, diagnostics: diagnostics, fileSystem: fileSystem) {
662662
if let error = result.error {
663663
let location = PkgConfigDiagnosticLocation(pcFile: result.pkgConfigName, target: target.name)
664664
diagnostics.emit(warning: "\(error)", location: location)

Sources/Xcodeproj/pbxproj.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ public func xcodeProject(
500500
switch depModule.underlyingTarget {
501501
case let systemTarget as SystemLibraryTarget:
502502
hdrInclPaths.append("$(SRCROOT)/\(systemTarget.path.relative(to: sourceRootDir).pathString)")
503-
if let pkgArgs = pkgConfigArgs(for: systemTarget, diagnostics: diagnostics) {
503+
for pkgArgs in pkgConfigArgs(for: systemTarget, diagnostics: diagnostics) {
504504
targetSettings.common.OTHER_LDFLAGS += pkgArgs.libs
505505
targetSettings.common.OTHER_SWIFT_FLAGS += pkgArgs.cFlags
506506
targetSettings.common.OTHER_CFLAGS += pkgArgs.cFlags

Tests/PackageLoadingTests/PkgConfigTests.swift

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class PkgConfigTests: XCTestCase {
3535
// No pkgConfig name.
3636
do {
3737
let result = pkgConfigArgs(for: SystemLibraryTarget(pkgConfig: ""), diagnostics: diagnostics)
38-
XCTAssertNil(result)
38+
XCTAssertTrue(result.isEmpty)
3939
}
4040

4141
// No pc file.
@@ -48,52 +48,55 @@ class PkgConfigTests: XCTestCase {
4848
.yum(["libFoo-devel"])
4949
]
5050
)
51-
let result = pkgConfigArgs(for: target, diagnostics: diagnostics)!
52-
XCTAssertEqual(result.pkgConfigName, "Foo")
53-
XCTAssertEqual(result.cFlags, [])
54-
XCTAssertEqual(result.libs, [])
55-
switch result.provider {
56-
case .brew(let names)?:
57-
XCTAssertEqual(names, ["libFoo"])
58-
case .apt(let names)?:
59-
XCTAssertEqual(names, ["libFoo-dev"])
60-
case .yum(let names)?:
61-
XCTAssertEqual(names, ["libFoo-devel"])
62-
case nil:
63-
XCTFail("Expected a provider here")
64-
}
65-
XCTAssertTrue(result.couldNotFindConfigFile)
66-
switch result.error {
51+
for result in pkgConfigArgs(for: target, diagnostics: diagnostics) {
52+
XCTAssertEqual(result.pkgConfigName, "Foo")
53+
XCTAssertEqual(result.cFlags, [])
54+
XCTAssertEqual(result.libs, [])
55+
switch result.provider {
56+
case .brew(let names)?:
57+
XCTAssertEqual(names, ["libFoo"])
58+
case .apt(let names)?:
59+
XCTAssertEqual(names, ["libFoo-dev"])
60+
case .yum(let names)?:
61+
XCTAssertEqual(names, ["libFoo-devel"])
62+
case nil:
63+
XCTFail("Expected a provider here")
64+
}
65+
XCTAssertTrue(result.couldNotFindConfigFile)
66+
switch result.error {
6767
case PkgConfigError.couldNotFindConfigFile?: break
6868
default:
69-
XCTFail("Unexpected error \(String(describing: result.error))")
69+
XCTFail("Unexpected error \(String(describing: result.error))")
70+
}
7071
}
7172
}
7273

7374
// Pc file.
7475
try withCustomEnv(["PKG_CONFIG_PATH": inputsDir.pathString]) {
75-
let result = pkgConfigArgs(for: SystemLibraryTarget(pkgConfig: "Foo"), diagnostics: diagnostics)!
76-
XCTAssertEqual(result.pkgConfigName, "Foo")
77-
XCTAssertEqual(result.cFlags, ["-I/path/to/inc", "-I\(inputsDir.pathString)"])
78-
XCTAssertEqual(result.libs, ["-L/usr/da/lib", "-lSystemModule", "-lok"])
79-
XCTAssertNil(result.provider)
80-
XCTAssertNil(result.error)
81-
XCTAssertFalse(result.couldNotFindConfigFile)
76+
for result in pkgConfigArgs(for: SystemLibraryTarget(pkgConfig: "Foo"), diagnostics: diagnostics) {
77+
XCTAssertEqual(result.pkgConfigName, "Foo")
78+
XCTAssertEqual(result.cFlags, ["-I/path/to/inc", "-I\(inputsDir.pathString)"])
79+
XCTAssertEqual(result.libs, ["-L/usr/da/lib", "-lSystemModule", "-lok"])
80+
XCTAssertNil(result.provider)
81+
XCTAssertNil(result.error)
82+
XCTAssertFalse(result.couldNotFindConfigFile)
83+
}
8284
}
8385

8486
// Pc file with prohibited flags.
8587
try withCustomEnv(["PKG_CONFIG_PATH": inputsDir.pathString]) {
86-
let result = pkgConfigArgs(for: SystemLibraryTarget(pkgConfig: "Bar"), diagnostics: diagnostics)!
87-
XCTAssertEqual(result.pkgConfigName, "Bar")
88-
XCTAssertEqual(result.cFlags, ["-I/path/to/inc"])
89-
XCTAssertEqual(result.libs, ["-L/usr/da/lib", "-lSystemModule", "-lok"])
90-
XCTAssertNil(result.provider)
91-
XCTAssertFalse(result.couldNotFindConfigFile)
92-
switch result.error {
93-
case PkgConfigError.prohibitedFlags(let desc)?:
94-
XCTAssertEqual(desc, "-DDenyListed")
95-
default:
96-
XCTFail("unexpected error \(result.error.debugDescription)")
88+
for result in pkgConfigArgs(for: SystemLibraryTarget(pkgConfig: "Bar"), diagnostics: diagnostics) {
89+
XCTAssertEqual(result.pkgConfigName, "Bar")
90+
XCTAssertEqual(result.cFlags, ["-I/path/to/inc"])
91+
XCTAssertEqual(result.libs, ["-L/usr/da/lib", "-lSystemModule", "-lok"])
92+
XCTAssertNil(result.provider)
93+
XCTAssertFalse(result.couldNotFindConfigFile)
94+
switch result.error {
95+
case PkgConfigError.prohibitedFlags(let desc)?:
96+
XCTAssertEqual(desc, "-DDenyListed")
97+
default:
98+
XCTFail("unexpected error \(result.error.debugDescription)")
99+
}
97100
}
98101
}
99102
}

0 commit comments

Comments
 (0)