-
Notifications
You must be signed in to change notification settings - Fork 41
/
Copy pathbuild.rs
118 lines (109 loc) · 3.54 KB
/
build.rs
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
use std::{env, fs, path::{Path, PathBuf}};
struct ProbedLib {
version: String,
include_paths: Vec<PathBuf>,
}
/// Finds libxml2 and optionally return a list of header
/// files from which the bindings can be generated.
fn find_libxml2() -> Option<ProbedLib> {
#![allow(unreachable_code)] // for platform-dependent dead code
if let Ok(ref s) = std::env::var("LIBXML2") {
// println!("{:?}", std::env::vars());
// panic!("set libxml2.");
let p = std::path::Path::new(s);
let fname = std::path::Path::new(
p.file_name()
.unwrap_or_else(|| panic!("no file name in LIBXML2 env ({s})")),
);
assert!(
p.is_file(),
"{}",
&format!("not a file in LIBXML2 env ({s})")
);
println!(
"cargo:rustc-link-lib={}",
fname
.file_stem()
.unwrap()
.to_string_lossy()
.strip_prefix("lib")
.unwrap()
);
println!(
"cargo:rustc-link-search={}",
p.parent()
.expect("no library path in LIBXML2 env")
.to_string_lossy()
);
None
} else {
#[cfg(any(target_family = "unix", target_os = "macos"))]
{
let lib = pkg_config::Config::new()
.probe("libxml-2.0")
.expect("Couldn't find libxml2 via pkg-config");
return Some(ProbedLib {
include_paths: lib.include_paths,
version: lib.version,
})
}
#[cfg(windows)]
{
if vcpkg_dep::find() {
return None
}
}
panic!("Could not find libxml2.")
}
}
fn generate_bindings(header_dirs: Vec<PathBuf>, output_path: &Path) {
let bindings = bindgen::Builder::default()
.header("src/wrapper.h")
.opaque_type("max_align_t")
// invalidate build as soon as the wrapper changes
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.layout_tests(true)
.clang_args(&["-DPKG-CONFIG"])
.clang_args(
header_dirs.iter()
.map(|dir| format!("-I{}", dir.display()))
);
bindings
.generate()
.expect("failed to generate bindings with bindgen")
.write_to_file(output_path)
.expect("Failed to write bindings.rs");
}
fn main() {
let bindings_path = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("bindings.rs");
// declare availability of config variable (without setting it)
println!("cargo::rustc-check-cfg=cfg(libxml_older_than_2_12)");
if let Some(probed_lib) = find_libxml2() {
// if we could find header files, generate fresh bindings from them
generate_bindings(probed_lib.include_paths, &bindings_path);
// and expose the libxml2 version to the code
let version_parts: Vec<i32> = probed_lib.version.split('.')
.map(|part| part.parse::<i32>().unwrap_or(-1)).collect();
let older_than_2_12 = version_parts.len() > 1 && (version_parts[0] < 2 ||
version_parts[0] == 2 && version_parts[1] < 12);
println!("cargo::rustc-check-cfg=cfg(libxml_older_than_2_12)");
if older_than_2_12 {
println!("cargo::rustc-cfg=libxml_older_than_2_12");
}
} else {
// otherwise, use the default bindings on platforms where pkg-config isn't available
fs::copy(PathBuf::from("src/default_bindings.rs"), bindings_path)
.expect("Failed to copy the default bindings to the build directory");
// for now, assume that the library is older than 2.12, because that's what those bindings are computed with
println!("cargo::rustc-cfg=libxml_older_than_2_12");
}
}
#[cfg(target_family = "windows")]
mod vcpkg_dep {
pub fn find() -> bool {
if vcpkg::find_package("libxml2").is_ok() {
return true;
}
false
}
}