forked from nulang-org/nulang
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.rs
More file actions
78 lines (71 loc) · 2.7 KB
/
Copy pathbuild.rs
File metadata and controls
78 lines (71 loc) · 2.7 KB
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
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
fn main() {
// Only needed when linking against PyO3; skip entirely for builds with
// the "python" feature disabled (`cargo:rerun-if-changed` for the
// feature flag itself so re-enabling it re-triggers this build script).
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_PYTHON");
if env::var_os("CARGO_FEATURE_PYTHON").is_none() {
return;
}
// On some Linux distributions (e.g. Fedora) the libpython3.X.so symlink
// installed by the -devel package is missing while libpython3.X.so.1.0 is
// present. PyO3 emits -lpython3.X and the linker fails because it cannot
// find the unversioned .so name. We work around this by creating a
// libpython3.X.so symlink in OUT_DIR and adding OUT_DIR to the library
// search path.
let out_dir = env::var_os("OUT_DIR")
.map(PathBuf::from)
.expect("OUT_DIR not set");
let version = detect_python_version();
let soname = format!("libpython{}.so", version);
if let Some(lib) = find_python_lib(&version) {
let link = out_dir.join(&soname);
if link.exists() || std::os::unix::fs::symlink(&lib, &link).is_ok() {
println!("cargo:rustc-link-search=native={}", out_dir.display());
println!("cargo:rustc-link-lib=python{}", version);
}
println!("cargo:rerun-if-changed=build.rs");
}
}
fn detect_python_version() -> String {
env::var("PYO3_PYTHON")
.ok()
.and_then(|exe| python_version_from_exe(&exe))
.or_else(|| python_version_from_exe("python3"))
.unwrap_or_else(|| "3.14".to_string())
}
fn python_version_from_exe(exe: &str) -> Option<String> {
let output = Command::new(exe).arg("--version").output().ok()?;
let text = String::from_utf8_lossy(&output.stdout);
let text = if text.trim().is_empty() {
String::from_utf8_lossy(&output.stderr)
} else {
text
};
// "Python 3.14.6" -> "3.14"
let parts: Vec<_> = text.split_whitespace().collect();
parts.get(1).map(|v| {
let mut iter = v.split('.');
let major = iter.next().unwrap_or("3");
let minor = iter.next().unwrap_or("0");
format!("{}.{}", major, minor)
})
}
fn find_python_lib(version: &str) -> Option<PathBuf> {
let search_dirs = ["/usr/lib64", "/lib64", "/usr/lib/x86_64-linux-gnu"];
let candidates = [
format!("libpython{}.so.1.0", version),
format!("libpython{}.so", version),
];
for dir in &search_dirs {
for name in &candidates {
let path = Path::new(dir).join(name);
if path.exists() {
return Some(path);
}
}
}
None
}