Skip to content

Commit e400a2e

Browse files
committed
Added utility for generating a pkg-config file
1 parent 450ae96 commit e400a2e

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

utils/make-pkgconfig.swift

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#!/usr/bin/env swift
2+
import Foundation
3+
4+
/// Runs the specified program at the provided path.
5+
/// - parameter path: The full path of the executable you
6+
/// wish to run.
7+
/// - parameter args: The arguments you wish to pass to the
8+
/// process.
9+
/// - returns: The standard output of the process, or nil if it was empty.
10+
func run(_ path: String, args: [String] = []) -> String? {
11+
let pipe = Pipe()
12+
let process = Process()
13+
process.launchPath = path
14+
process.arguments = args
15+
process.standardOutput = pipe
16+
process.launch()
17+
process.waitUntilExit()
18+
19+
let data = pipe.fileHandleForReading.readDataToEndOfFile()
20+
guard let result = String(data: data, encoding: .utf8)?
21+
.trimmingCharacters(in: .whitespacesAndNewlines),
22+
!result.isEmpty else { return nil }
23+
return result
24+
}
25+
26+
/// Finds the location of the provided binary on your system.
27+
func which(_ name: String) -> String? {
28+
return run("/usr/bin/which", args: [name])
29+
}
30+
31+
extension String: Error {
32+
/// Replaces all occurrences of characters in the provided set with
33+
/// the provided string.
34+
func replacing(charactersIn characterSet: CharacterSet,
35+
with separator: String) -> String {
36+
let components = self.components(separatedBy: characterSet)
37+
return components.joined(separator: separator)
38+
}
39+
}
40+
41+
func makeFile() throws {
42+
let pkgConfigPath = "/usr/local/lib/pkgconfig"
43+
let pkgConfigDir = URL(fileURLWithPath: pkgConfigPath)
44+
45+
// Make /usr/local/lib/pkgconfig if it doesn't already exist
46+
if !FileManager.default.fileExists(atPath: pkgConfigPath) {
47+
try FileManager.default.createDirectory(at: pkgConfigDir,
48+
withIntermediateDirectories: true)
49+
}
50+
let cllvmPath = pkgConfigDir.appendingPathComponent("cllvm.pc")
51+
52+
/// Ensure we have llvm-config in the PATH
53+
guard let llvmConfig = which("llvm-config") else {
54+
throw "Failed to find llvm-config. Ensure llvm-config is installed and " +
55+
"in your PATH"
56+
}
57+
58+
/// Extract the info we need from llvm-config
59+
60+
print("Found llvm-config at \(llvmConfig)...")
61+
print("Running llvm-config --libs all")
62+
let ldFlags = run(llvmConfig, args: ["--libs", "all"])!
63+
.replacing(charactersIn: .newlines, with: "")
64+
print("Running llvm-config --version")
65+
let version = run(llvmConfig, args: ["--version"])!
66+
.replacing(charactersIn: .newlines, with: "")
67+
68+
// SwiftPM has a whitelisted set of cflags that it understands, and
69+
// unfortunately that includes almost everything but the include dir.
70+
71+
print("Running llvm-config --cflags")
72+
let cFlags = run(llvmConfig, args: ["--cflags"])!
73+
.replacing(charactersIn: .newlines, with: "")
74+
.components(separatedBy: " ")
75+
.filter { $0.hasPrefix("-I") }
76+
.joined(separator: " ")
77+
78+
/// Emit the pkg-config file to the path
79+
80+
let s = [
81+
"Name: cllvm",
82+
"Description: The llvm library",
83+
"Version: \(version)",
84+
"Libs: \(ldFlags)",
85+
"Requires.private:",
86+
"Cflags: \(cFlags)",
87+
].joined(separator: "\n")
88+
89+
try s.write(toFile: cllvmPath.path, atomically: true, encoding: .utf8)
90+
}
91+
92+
do {
93+
try makeFile()
94+
} catch {
95+
print("error: \(error)")
96+
exit(-1)
97+
}

0 commit comments

Comments
 (0)