From bbf6a12b3f81cce788b22b30a810859aa06a0d51 Mon Sep 17 00:00:00 2001 From: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com> Date: Tue, 23 Jun 2026 23:01:10 -0700 Subject: [PATCH] Remove requirement for build.rs in chat-cli --- bin/chat-cli/build.rs | 15 ------ bin/chat-cli/src/main.rs | 67 -------------------------- extensions/components/build.rs | 82 +++++++++++++++++++++++++++----- extensions/components/src/lib.rs | 2 +- 4 files changed, 70 insertions(+), 96 deletions(-) delete mode 100644 bin/chat-cli/build.rs diff --git a/bin/chat-cli/build.rs b/bin/chat-cli/build.rs deleted file mode 100644 index 88db6de..0000000 --- a/bin/chat-cli/build.rs +++ /dev/null @@ -1,15 +0,0 @@ -fn main() { - println!("cargo::rustc-check-cfg=cfg(logos_delivery)"); - - let Some(lib_dir) = std::env::var("DEP_LOGOSDELIVERY_LIB_DIR").ok() else { - return; - }; - - println!("cargo:rustc-cfg=logos_delivery"); - - let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); - match target_os.as_str() { - "macos" | "linux" => println!("cargo:rustc-link-arg=-Wl,-rpath,{lib_dir}"), - _ => {} - } -} diff --git a/bin/chat-cli/src/main.rs b/bin/chat-cli/src/main.rs index bd75484..99b9be3 100644 --- a/bin/chat-cli/src/main.rs +++ b/bin/chat-cli/src/main.rs @@ -179,73 +179,6 @@ where result } -fn run_logos_delivery(cli: Cli) -> Result<()> { - { - eprintln!("Starting logos-delivery node (preset={})...", cli.preset); - eprintln!("This may take a few seconds while connecting to the network."); - - let logos_cfg = P2pConfig { - preset: cli.preset.clone(), - tcp_port: cli.port, - ..Default::default() - }; - let delivery = P2pTransport( - EmbeddedP2pDeliveryService::start(logos_cfg) - .context("failed to start logos-delivery")?, - ); - - eprintln!("Node connected. Initializing chat client..."); - - let data_dir = cli - .db - .as_ref() - .and_then(|p| p.parent()) - .map(|p| p.to_path_buf()) - .unwrap_or_else(|| cli.data.clone()); - - let (client, events) = match cli.db { - Some(ref path) => { - let db_str = path - .to_str() - .context("db path contains non-UTF-8 characters")? - .to_string(); - - logos_chat::ChatClientBuilder::new() - .storage_config(logos_chat::StorageConfig::Encrypted { - path: db_str, - key: "chat-cli".to_string(), - }) - .transport(delivery) - .build() - .map_err(|e| anyhow::anyhow!("{e:?}")) - .context("failed to open persistent client")? - } - None => logos_chat::ChatClientBuilder::new() - .transport(delivery) - .build() - .map_err(|e| anyhow::anyhow!("{e:?}")) - .context("failed to open chat client")?, - }; - - let mut app = ChatApp::new(client, events, &cli.name, &data_dir)?; - - if cli.smoketest { - return Ok(()); - } - - let mut terminal = ui::init().context("failed to initialize terminal")?; - let result = run_app(&mut terminal, &mut app); - ui::restore().context("failed to restore terminal")?; - return result; - } - - #[cfg(not(logos_delivery))] - anyhow::bail!( - "logos-delivery transport is not available in this build.\n\ - Build with LOGOS_DELIVERY_LIB_DIR set to enable it." - ) -} - fn run_app(terminal: &mut ui::Tui, app: &mut ChatApp) -> Result<()> where I: IdentityProvider + Send, diff --git a/extensions/components/build.rs b/extensions/components/build.rs index 71a8a6d..08b8b82 100644 --- a/extensions/components/build.rs +++ b/extensions/components/build.rs @@ -1,32 +1,88 @@ +use std::fs; +use std::process::Command; + fn main() { println!("cargo:rerun-if-env-changed=LOGOS_DELIVERY_LIB_DIR"); println!("cargo::rustc-check-cfg=cfg(logos_delivery)"); - let feature_enabled = std::env::var("CARGO_FEATURE_EMBEDDED_P2P_DELIVERY").is_ok(); - if !feature_enabled { + if std::env::var_os("CARGO_FEATURE_EMBEDDED_P2P_DELIVERY").is_none() { return; } - let lib_dir = std::env::var("LOGOS_DELIVERY_LIB_DIR") + // 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); - - let Some(lib_dir) = lib_dir else { - // Feature is on but no library path — enable compilation, skip linking. - println!("cargo:rustc-cfg=logos_delivery"); + .or_else(nix_build_logos_delivery) + 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 + // unresolved symbols at link time. `EmbeddedP2pDeliveryService` is + // simply absent until the library can be found. return; }; println!("cargo:rustc-cfg=logos_delivery"); - println!("cargo:rustc-link-search=native={lib_dir}"); - println!("cargo:rustc-link-lib=dylib=logosdelivery"); - println!("cargo:LIB_DIR={lib_dir}"); + let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR not set"); let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); + + // The shipped library carries a relocatable install name (@rpath on macOS, + // $ORIGIN soname on Linux), which would force every downstream BINARY to + // inject its own RPATH. Cargo propagates `rustc-link-search` and + // `rustc-link-lib` across crates, but NOT `rustc-link-arg` (the rpath) — so + // that relocatable name is exactly what makes consumers need their own + // build.rs. Instead, stamp a private copy with an ABSOLUTE install name; + // the propagating search + lib directives are then sufficient and consumers + // need zero build-script glue. match target_os.as_str() { - "macos" | "linux" => println!("cargo:rustc-link-arg=-Wl,-rpath,{lib_dir}"), + "macos" => stamp_absolute_macos(&lib_dir, &out_dir), + "linux" => stamp_absolute_linux(&lib_dir, &out_dir), other => panic!("unsupported OS for logos-delivery transport: {other}"), } + + println!("cargo:rustc-link-search=native={out_dir}"); + println!("cargo:rustc-link-lib=dylib=logosdelivery"); +} + +/// 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"); + let dst = format!("{out_dir}/liblogosdelivery.dylib"); + copy_writable(&src, &dst); + run("install_name_tool", &["-id", &src, &dst]); + println!("cargo:rerun-if-changed={src}"); +} + +/// 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"); + let dst = format!("{out_dir}/liblogosdelivery.so"); + copy_writable(&src, &dst); + run("patchelf", &["--set-soname", &src, &dst]); + println!("cargo:rerun-if-changed={src}"); +} + +fn copy_writable(src: &str, dst: &str) { + fs::copy(src, dst).unwrap_or_else(|e| panic!("copy {src} -> {dst}: {e}")); + // Store-sourced files are read-only; make the copy writable so its install + // name / soname can be rewritten. + let mut perms = fs::metadata(dst).unwrap().permissions(); + perms.set_readonly(false); + fs::set_permissions(dst, perms).unwrap(); +} + +fn run(cmd: &str, args: &[&str]) { + let status = Command::new(cmd) + .args(args) + .status() + .unwrap_or_else(|e| panic!("failed to run `{cmd}`: {e}")); + assert!(status.success(), "`{cmd} {args:?}` failed with {status}"); } fn nix_build_logos_delivery() -> Option { @@ -35,7 +91,7 @@ fn nix_build_logos_delivery() -> Option { println!("cargo:rerun-if-changed={flake_root}/flake.lock"); - let output = std::process::Command::new("nix") + let output = Command::new("nix") .args(["build", ".#logos-delivery", "--no-link", "--print-out-paths"]) .current_dir(&flake_root) .output() diff --git a/extensions/components/src/lib.rs b/extensions/components/src/lib.rs index 06d7509..2ef540e 100644 --- a/extensions/components/src/lib.rs +++ b/extensions/components/src/lib.rs @@ -8,5 +8,5 @@ pub use contact_registry::http::{HttpRegistry, HttpRegistryError}; pub use storage::*; pub use wakeup::*; -#[cfg(feature = "embedded_p2p_delivery")] +#[cfg(logos_delivery)] pub use delivery::{EmbeddedP2pDeliveryService, P2pConfig};