use std::env; use std::error::Error; use std::process::{Command, Output, Stdio}; fn main() { let dkp_path = env::var("DEVKITPRO").unwrap(); let profile = env::var("PROFILE").unwrap(); let pwd = env::var("CARGO_MANIFEST_DIR").unwrap(); // Link to libctru println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-env-changed=DEVKITPRO"); println!("cargo:rustc-link-search=native={dkp_path}/libctru/lib"); println!( "cargo:rustc-link-lib=static={}", match profile.as_str() { "debug" => "ctrud", _ => "ctru", } ); // Link to static inline fns wrapper println!("cargo:rustc-link-search=native={}", pwd); println!("cargo:rustc-link-lib=static=extern"); match check_libctru_version() { Ok((maj, min, patch)) => { eprintln!("using libctru version {maj}.{min}.{patch}"); // These are accessible by the crate during build with `env!()`. // We might consider exporting some public constants or something. println!("cargo:rustc-env=LIBCTRU_VERSION={maj}.{min}.{patch}"); println!("cargo:rustc-env=LIBCTRU_MAJOR={maj}"); println!("cargo:rustc-env=LIBCTRU_MINOR={min}"); println!("cargo:rustc-env=LIBCTRU_PATCH={patch}"); } Err(err) => println!("cargo:warning=failed to check libctru version: {err}"), } } fn parse_version(version: &str) -> Result<(String, String, String), &str> { let versions: Vec<_> = version .split(|c| c == '.' || c == '-') .map(String::from) .collect(); match &versions[..] { [major, minor, patch, _build] => Ok((major.clone(), minor.clone(), patch.clone())), _ => Err("unexpected number of version segments"), } } fn check_libctru_version() -> Result<(String, String, String), Box> { let pacman = which::which("dkp-pacman").or_else(|_| which::which("pacman"))?; let Output { stdout, .. } = Command::new(&pacman) .args(["--query", "libctru"]) .stderr(Stdio::inherit()) .output()?; let output_str = String::from_utf8_lossy(&stdout); let (_pkg, lib_version) = output_str .split_once(char::is_whitespace) .ok_or("unexpected pacman output format")?; let lib_version = lib_version.trim(); let cargo_pkg_version = env::var("CARGO_PKG_VERSION").unwrap(); let (_, crate_built_version) = cargo_pkg_version .split_once('+') .expect("crate version should have '+' delimeter"); if lib_version != crate_built_version { return Err(format!( "libctru version is {lib_version} but this crate was built for {crate_built_version}" ))?; } let Output { stdout, .. } = Command::new(pacman) .args(["--query", "--list", "libctru"]) .stderr(Stdio::inherit()) .output()?; for line in String::from_utf8_lossy(&stdout).split('\n') { let Some((_pkg, file)) = line.split_once(char::is_whitespace) else { continue; }; println!("cargo:rerun-if-changed={file}"); } let (lib_major, lib_minor, lib_patch) = parse_version(lib_version)?; Ok((lib_major, lib_minor, lib_patch)) }