1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use std::path::Path;
/// Read an env var, registering it with cargo's rerun-if-env-changed tracking.
fn tracked_var_os(key: &str) -> Option<std::ffi::OsString> {
println!("cargo:rerun-if-env-changed={key}");
std::env::var_os(key)
}
/// Parse a boolean env var. Returns `None` if absent, `Some(bool)` if present.
/// Accepts 1/0/true/false/yes/no (case-insensitive). Panics on unrecognized values.
fn parse_bool_env(key: &str) -> Option<bool> {
let val = tracked_var_os(key)?;
let s = val
.to_str()
.unwrap_or_else(|| panic!("{key} is not valid UTF-8"));
match s.to_ascii_lowercase().as_str() {
"1" | "true" | "yes" => Some(true),
"0" | "false" | "no" => Some(false),
other => panic!("{key}={other}: expected 1/0/true/false/yes/no"),
}
}
fn main() {
let target_os = tracked_var_os("CARGO_CFG_TARGET_OS")
.unwrap()
.into_string()
.unwrap();
match target_os.as_str() {
// On macOS, OpenBSD, and NetBSD the BSD functions live in libc
// (or libSystem on macOS), so no extra library is needed.
"macos" | "openbsd" | "netbsd" => return,
// On FreeBSD, most functions are in libc, but humanize_number,
// pidfile_*, flopen, and expand_number live in libutil.
"freebsd" => {
println!("cargo:rustc-link-lib=util");
return;
}
// Windows and other unsupported platforms: nothing to link.
"windows" => return,
// Everything else (Linux, etc.) needs the libbsd library.
_ => {}
}
// docs.rs builds and CI clippy without libbsd-dev: skip all linking.
if tracked_var_os("DOCS_RS").is_some() {
return;
}
let feat_static = tracked_var_os("CARGO_FEATURE_STATIC").is_some();
let feat_overlay = tracked_var_os("CARGO_FEATURE_OVERLAY").is_some();
let env_static = parse_bool_env("LIBBSD_STATIC");
let no_pkgcfg = tracked_var_os("LIBBSD_NO_PKG_CONFIG").is_some();
let lib_dir = tracked_var_os("LIBBSD_LIB_DIR");
let inc_dir = tracked_var_os("LIBBSD_INCLUDE_DIR");
// Env var wins over feature (openssl-sys semantics).
let statik = env_static.unwrap_or(feat_static);
// Manual override path: bypass pkg-config entirely.
if let Some(dir) = &lib_dir {
println!(
"cargo:rustc-link-search=native={}",
Path::new(dir).display()
);
println!("cargo:libdir={}", Path::new(dir).display());
let kind = if statik { "static" } else { "dylib" };
println!("cargo:rustc-link-lib={kind}=bsd");
if let Some(inc) = &inc_dir {
for p in std::env::split_paths(inc) {
println!("cargo:include={}", p.display());
}
}
return;
}
// No pkg-config, no lib dir: skip linking entirely. This lets
// `cargo clippy` (and similar check-only builds) succeed in downstream
// crates without libbsd-dev installed. Any final binary that actually
// uses symbols from libbsd will need to arrange linkage itself
// (e.g. via RUSTFLAGS="-l bsd" or by setting LIBBSD_LIB_DIR).
if no_pkgcfg {
if let Some(inc) = &inc_dir {
for p in std::env::split_paths(inc) {
println!("cargo:include={}", p.display());
}
}
return;
}
// pkg-config path.
let pkg = if feat_overlay {
"libbsd-overlay"
} else {
"libbsd"
};
let mut cfg = pkg_config::Config::new();
cfg.atleast_version("0.11");
if statik {
cfg.statik(true);
}
let lib = match cfg.probe(pkg) {
Ok(lib) => lib,
Err(e) => {
// pkg-config failed. Warn and skip the link step rather than
// panic, so `cargo clippy` / `cargo check` in downstream crates
// succeed on machines without libbsd-dev. A real binary build
// that actually references libbsd symbols will still fail at
// link time, and the warnings below tell the user how to fix it.
//
// cargo:warning is single-line, so collapse pkg-config's error
// text and emit each line of context as its own warning.
let e = e.to_string().replace('\n', " ");
println!("cargo:warning=libbsd-sys: {pkg} not found via pkg-config: {e}");
println!(
"cargo:warning=libbsd-sys: link step skipped; a real binary build \
will fail at link time."
);
println!(
"cargo:warning=libbsd-sys: install libbsd-dev, set LIBBSD_LIB_DIR=/path/to/lib, \
or set LIBBSD_NO_PKG_CONFIG=1 to silence this warning."
);
return;
}
};
// Re-export paths so downstream build scripts can use them via
// DEP_BSD_INCLUDE / DEP_BSD_LIBDIR.
for p in &lib.include_paths {
println!("cargo:include={}", p.display());
}
for p in &lib.link_paths {
println!("cargo:libdir={}", p.display());
}
}