Skip to main content

rust_usd_build/
lib.rs

1//! Build-script helpers for downstream crates that link `rust-usd`.
2//!
3//! `rust-usd`'s own `build.rs` emits the rpath args its examples need at
4//! runtime, but `cargo:rustc-link-arg` only applies to the immediate target.
5//! Downstream binaries / examples have to re-emit the same rpaths or the
6//! dynamic loader can't find `libpxr_*.dylib` at startup.
7//!
8//! Add this crate as a build-dependency and call [`emit_runtime_rpath`] from
9//! your own `build.rs`:
10//!
11//! ```ignore
12//! fn main() {
13//!     rust_usd_build::emit_runtime_rpath();
14//! }
15//! ```
16//!
17//! It reads the same environment variables `rust-usd`'s build script does
18//! and is a no-op if none of them are set, so consumers can leave the call
19//! in unconditionally even on CI machines without a USD install.
20
21use std::env;
22use std::path::PathBuf;
23
24/// Emit the `cargo:rustc-link-arg` directives needed for downstream
25/// executables to find OpenUSD's dylibs at runtime via `@rpath`.
26///
27/// Reads `USD_LIB_DIR` (or `USD_INSTALL_DIR/lib`) and the Python framework
28/// vars `USD_LINK_PYTHON` / `USD_PYTHON_FRAMEWORK_DIR` /
29/// `USD_PYTHON_FRAMEWORK` / `USD_PYTHON_LIB_DIR`, and re-emits matching
30/// `-Wl,-rpath` link args. Idempotent if no relevant env vars are set.
31pub fn emit_runtime_rpath() {
32    let lib_dir = resolve_lib_dir();
33    let link_python = env::var("USD_LINK_PYTHON").unwrap_or_else(|_| "framework".into());
34
35    if let Some(lib_dir) = lib_dir {
36        println!("cargo:rustc-link-arg=-Wl,-rpath,{}", lib_dir.display());
37        if let Some(parent) = lib_dir.parent() {
38            println!("cargo:rustc-link-arg=-Wl,-rpath,{}", parent.display());
39        }
40    }
41
42    match link_python.as_str() {
43        "framework" => {
44            if let Ok(fw_dir) = env::var("USD_PYTHON_FRAMEWORK_DIR") {
45                let fw_name = env::var("USD_PYTHON_FRAMEWORK").unwrap_or_else(|_| "Python".into());
46                let inside_fw = PathBuf::from(&fw_dir).join(format!("{}.framework", fw_name));
47                println!("cargo:rustc-link-arg=-Wl,-rpath,{}", inside_fw.display());
48            }
49        }
50        "lib" => {
51            if let Ok(py_lib_dir) = env::var("USD_PYTHON_LIB_DIR") {
52                println!("cargo:rustc-link-arg=-Wl,-rpath,{}", py_lib_dir);
53            }
54        }
55        _ => {}
56    }
57
58    for var in [
59        "USD_LIB_DIR",
60        "USD_INSTALL_DIR",
61        "USD_LINK_PYTHON",
62        "USD_PYTHON_FRAMEWORK_DIR",
63        "USD_PYTHON_FRAMEWORK",
64        "USD_PYTHON_LIB_DIR",
65    ] {
66        println!("cargo:rerun-if-env-changed={}", var);
67    }
68}
69
70fn resolve_lib_dir() -> Option<PathBuf> {
71    if let Ok(dir) = env::var("USD_LIB_DIR") {
72        return Some(PathBuf::from(dir));
73    }
74    if let Ok(install) = env::var("USD_INSTALL_DIR") {
75        return Some(PathBuf::from(install).join("lib"));
76    }
77    if let Ok(prefix) = env::var("PXR_CMAKE_PREFIX") {
78        return Some(PathBuf::from(prefix).join("lib"));
79    }
80    None
81}