Skip to content

Commit dfb18f2

Browse files
committed
Implement pkg-config flag deduplication
Should reduce a lot of the noise in Cflags and Libraries. See #455
1 parent 96a0b56 commit dfb18f2

File tree

2 files changed

+127
-6
lines changed

2 files changed

+127
-6
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ glob = "0.3"
4545
itertools = "0.14"
4646
implib = "0.3.5"
4747
object = { version = "0.36.4", default-features = false, features = ["std", "read_core", "pe"] }
48+
pkg-config = "0.3.32"
4849

4950
[features]
5051
default = []

src/pkg_config_gen.rs

Lines changed: 126 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
use crate::build::CApiConfig;
44
use crate::install::InstallPaths;
5-
use std::path::{Component, Path, PathBuf};
5+
use std::{
6+
collections::HashSet,
7+
path::{Component, Path, PathBuf},
8+
};
69

710
fn canonicalize<P: AsRef<Path>>(path: P) -> String {
811
let mut stack = Vec::with_capacity(16);
@@ -57,6 +60,14 @@ fn canonicalize<P: AsRef<Path>>(path: P) -> String {
5760
}
5861
}
5962

63+
use pkg_config;
64+
65+
#[derive(Debug, Clone)]
66+
struct PkgConfigDedupInformation {
67+
requires: Vec<pkg_config::Library>,
68+
requires_private: Vec<pkg_config::Library>,
69+
}
70+
6071
#[derive(Debug, Clone)]
6172
pub struct PkgConfig {
6273
prefix: PathBuf,
@@ -77,6 +88,8 @@ pub struct PkgConfig {
7788
cflags: Vec<String>,
7889

7990
conflicts: Vec<String>,
91+
92+
dedup: PkgConfigDedupInformation,
8093
}
8194

8295
impl PkgConfig {
@@ -99,19 +112,53 @@ impl PkgConfig {
99112
Some(reqs) => reqs.split(',').map(|s| s.trim().to_string()).collect(),
100113
_ => Vec::new(),
101114
};
115+
116+
let requires_libs = {
117+
let cfg = {
118+
let mut c = pkg_config::Config::new();
119+
// This is not sinkholed by cargo-c
120+
c.env_metadata(false);
121+
122+
c
123+
};
124+
125+
// TODO: log which probe fails
126+
requires
127+
.iter()
128+
.flat_map(|req| cfg.probe(req))
129+
.collect::<Vec<_>>()
130+
};
131+
102132
let requires_private = match &capi_config.pkg_config.requires_private {
103133
Some(reqs) => reqs.split(',').map(|s| s.trim().to_string()).collect(),
104134
_ => Vec::new(),
105135
};
106136

137+
let requires_private_libs = {
138+
let cfg = {
139+
let mut c = pkg_config::Config::new();
140+
c.statik(true);
141+
// This is not sinkholed by cargo-c
142+
c.env_metadata(false);
143+
144+
c
145+
};
146+
147+
// TODO: log which probe fails
148+
requires_private
149+
.iter()
150+
.flat_map(|req| cfg.probe(req))
151+
.collect::<Vec<_>>()
152+
};
153+
107154
let mut libdir = PathBuf::new();
108155
libdir.push("${libdir}");
109156
if let Some(subdir) = &capi_config.library.install_subdir {
110157
libdir.push(subdir);
111158
}
112159

113160
let libs = vec![
114-
format!("-L{}", libdir.display()),
161+
format!("-L{}", canonicalize(libdir.display().to_string())),
115162
format!("-l{}", capi_config.library.name),
116163
];
117164

@@ -146,6 +193,11 @@ impl PkgConfig {
146193
cflags: vec![cflags],
147194

148195
conflicts: Vec::new(),
196+
197+
dedup: PkgConfigDedupInformation {
198+
requires: requires_libs,
199+
requires_private: requires_private_libs,
200+
},
149201
}
150202
}
151203

@@ -236,7 +288,75 @@ impl PkgConfig {
236288
self.render_help(String::with_capacity(1024)).unwrap()
237289
}
238290

291+
fn get_libs_cflags(arg: &[pkg_config::Library]) -> (HashSet<String>, HashSet<String>) {
292+
let mut libs: HashSet<String> = HashSet::new();
293+
let mut cflags: HashSet<String> = HashSet::new();
294+
295+
for lib in arg.iter() {
296+
for lib in lib.include_paths.iter() {
297+
libs.insert(format!("-I{}", lib.to_string_lossy()));
298+
}
299+
for lib in lib.link_files.iter() {
300+
libs.insert(lib.to_string_lossy().to_string());
301+
}
302+
for lib in lib.libs.iter() {
303+
libs.insert(format!("-l{}", lib));
304+
}
305+
for lib in lib.link_paths.iter() {
306+
libs.insert(format!("-L{}", lib.to_string_lossy()));
307+
}
308+
for lib in lib.frameworks.iter() {
309+
libs.insert(format!("-framework {}", lib));
310+
}
311+
for lib in lib.framework_paths.iter() {
312+
libs.insert(format!("-F{}", lib.to_string_lossy()));
313+
}
314+
for lib in lib.defines.iter() {
315+
let v = match lib.1 {
316+
Some(v) => format!("-D{}={}", lib.0, v),
317+
None => format!("D{}", lib.0),
318+
};
319+
libs.insert(v);
320+
}
321+
for lib in lib.ld_args.iter() {
322+
cflags.insert(format!("-Wl,{}", lib.join(",")));
323+
}
324+
}
325+
326+
(libs, cflags)
327+
}
328+
329+
fn dedup_libs_cflags(
330+
requires: &[pkg_config::Library],
331+
flags: &[String],
332+
) -> (String, String) {
333+
let (libs, cflags) = PkgConfig::get_libs_cflags(requires);
334+
335+
let libs = flags
336+
.iter()
337+
.filter(|lib| !libs.contains(lib.as_str()))
338+
.map(|lib| lib.as_str())
339+
.collect::<Vec<_>>()
340+
.join(" ");
341+
let cflags = flags
342+
.iter()
343+
.filter(|lib| !cflags.contains(lib.as_str()))
344+
.map(|lib| lib.as_str())
345+
.collect::<Vec<_>>()
346+
.join(" ");
347+
348+
(libs, cflags)
349+
}
350+
239351
fn render_help<W: core::fmt::Write>(&self, mut w: W) -> Result<W, core::fmt::Error> {
352+
// Dedup
353+
// What libs are already known here?
354+
let (dedup_libs, dedup_cflags) =
355+
PkgConfig::dedup_libs_cflags(&self.dedup.requires, &self.libs);
356+
357+
let (dedup_libs_private, dedup_cflags_private) =
358+
PkgConfig::dedup_libs_cflags(&self.dedup.requires_private, &self.libs_private);
359+
240360
writeln!(w, "prefix={}", canonicalize(&self.prefix))?;
241361
writeln!(w, "exec_prefix={}", canonicalize(&self.exec_prefix))?;
242362
writeln!(w, "libdir={}", canonicalize(&self.libdir))?;
@@ -247,15 +367,15 @@ impl PkgConfig {
247367
writeln!(w, "Name: {}", self.name)?;
248368
writeln!(w, "Description: {}", self.description.replace('\n', " "))?; // avoid endlines
249369
writeln!(w, "Version: {}", self.version)?;
250-
writeln!(w, "Libs: {}", self.libs.join(" "))?;
251-
writeln!(w, "Cflags: {}", self.cflags.join(" "))?;
370+
writeln!(w, "Libs: {}", dedup_libs)?;
371+
writeln!(w, "Cflags: {}", dedup_cflags)?;
252372

253373
if !self.libs_private.is_empty() {
254-
writeln!(w, "Libs.private: {}", self.libs_private.join(" "))?;
374+
writeln!(w, "Libs.private: {}", dedup_libs_private)?;
255375
}
256376

257377
if !self.requires.is_empty() {
258-
writeln!(w, "Requires: {}", self.requires.join(", "))?;
378+
writeln!(w, "Requires: {}", dedup_cflags_private)?;
259379
}
260380

261381
if !self.requires_private.is_empty() {

0 commit comments

Comments
 (0)