From 48259c5daf7e812020e24af07b0af10491080499 Mon Sep 17 00:00:00 2001 From: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com> Date: Tue, 23 Jun 2026 23:54:26 -0700 Subject: [PATCH] fix build in linux --- extensions/components/build.rs | 69 +++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 17 deletions(-) diff --git a/extensions/components/build.rs b/extensions/components/build.rs index 5c026a7..7ab87a7 100644 --- a/extensions/components/build.rs +++ b/extensions/components/build.rs @@ -1,4 +1,5 @@ use std::fs; +use std::path::{Path, PathBuf}; use std::process::Command; fn main() { @@ -9,11 +10,7 @@ fn main() { return; } - // Locate the native library: explicit override first, then build via nix. - let Some(lib_dir) = std::env::var("LOGOS_DELIVERY_LIB_DIR") - .ok() - .or_else(nix_build_logos_delivery) - else { + let Some(lib_dir) = locate_lib_dir() else { // Feature is on but the native library is unavailable (e.g. `cargo // check` on a machine without nix). Skip the cfg so the FFI module is // not compiled — this keeps `cargo check` working without producing @@ -45,33 +42,71 @@ fn main() { println!("cargo:rustc-link-lib=dylib=logosdelivery"); } +/// Locate the native library directory as an ABSOLUTE, canonical path. Prefers +/// `LOGOS_DELIVERY_LIB_DIR`, then falls back to building it via nix. Returns +/// `None` when neither is available (e.g. `cargo check` without nix). +fn locate_lib_dir() -> Option { + if let Ok(dir) = std::env::var("LOGOS_DELIVERY_LIB_DIR") { + if let Some(resolved) = resolve_lib_dir(&dir) { + return Some(resolved); + } + println!( + "cargo:warning=LOGOS_DELIVERY_LIB_DIR='{dir}' could not be resolved; \ + falling back to `nix build`" + ); + } + resolve_lib_dir(&nix_build_logos_delivery()?) +} + +/// Resolve a lib dir to an absolute, canonical path. Cargo runs build scripts +/// with the cwd set to the crate dir, but a relative value (e.g. CI's +/// `./result/lib`) is anchored at the flake/workspace root where `nix build` +/// drops `result`. Canonicalizing also follows the `result` symlink to the +/// immutable store path, so the stamped install name / soname stays stable. +fn resolve_lib_dir(dir: &str) -> Option { + let path = Path::new(dir); + let anchored = if path.is_absolute() { + path.to_path_buf() + } else { + let manifest = std::env::var("CARGO_MANIFEST_DIR").ok()?; + Path::new(&find_flake_root(&manifest)?).join(path) + }; + anchored.canonicalize().ok() +} + /// Copy `liblogosdelivery.dylib` into `OUT_DIR` and rewrite its install name to /// the absolute store path. The consumer records that absolute path, so dyld /// loads the original file directly — whose own `@loader_path` RPATH resolves /// `librln.dylib` beside it — with no RPATH needed on the consumer. -fn stamp_absolute_macos(lib_dir: &str, out_dir: &str) { - let src = format!("{lib_dir}/liblogosdelivery.dylib"); +fn stamp_absolute_macos(lib_dir: &Path, out_dir: &str) { + let src = lib_dir.join("liblogosdelivery.dylib"); let dst = format!("{out_dir}/liblogosdelivery.dylib"); - copy_writable(&src, &dst); - run("install_name_tool", &["-id", &src, &dst]); - println!("cargo:rerun-if-changed={src}"); + copy_writable(&src, Path::new(&dst)); + run("install_name_tool", &["-id", path_str(&src), &dst]); + println!("cargo:rerun-if-changed={}", src.display()); } /// Linux equivalent: an absolute `DT_SONAME` is recorded verbatim in the /// consumer's `DT_NEEDED`, so `ld.so` loads it by path with no RPATH. Requires /// `patchelf` at build time (provided by the nix devshell). -fn stamp_absolute_linux(lib_dir: &str, out_dir: &str) { - let src = format!("{lib_dir}/liblogosdelivery.so"); +fn stamp_absolute_linux(lib_dir: &Path, out_dir: &str) { + let src = lib_dir.join("liblogosdelivery.so"); let dst = format!("{out_dir}/liblogosdelivery.so"); - copy_writable(&src, &dst); - run("patchelf", &["--set-soname", &src, &dst]); - println!("cargo:rerun-if-changed={src}"); + copy_writable(&src, Path::new(&dst)); + run("patchelf", &["--set-soname", path_str(&src), &dst]); + println!("cargo:rerun-if-changed={}", src.display()); } -fn copy_writable(src: &str, dst: &str) { +fn path_str(p: &Path) -> &str { + p.to_str() + .unwrap_or_else(|| panic!("non-UTF-8 path: {}", p.display())) +} + +fn copy_writable(src: &Path, dst: &Path) { use std::os::unix::fs::PermissionsExt; - fs::copy(src, dst).unwrap_or_else(|e| panic!("copy {src} -> {dst}: {e}")); + fs::copy(src, dst) + .unwrap_or_else(|e| panic!("copy {} -> {}: {e}", src.display(), dst.display())); // Store-sourced files are read-only; restore owner write so the install // name / soname can be rewritten. fs::set_permissions(dst, fs::Permissions::from_mode(0o644)).unwrap();