# Problem
`xlsynth-sys` downloads managed `libxls` DSOs into its Cargo `OUT_DIR`
and emits native link directives pointing at that directory. This works
for linking, but it is not enough for all Cargo runtime cases.
In particular, downstream crates can use `xlsynth`/`xlsynth-sys` from
their own `build.rs`. Cargo successfully links those build-script
executables against the downloaded `libxls` DSO, but when Cargo later
runs the build script, the dynamic loader may not search the
`xlsynth-sys` `OUT_DIR`. The result is a runtime loader failure like:
```text
error while loading shared libraries: libxls-...so: cannot open shared object file: No such file or directory
```
This can happen even though the DSO was downloaded correctly and linking
succeeded, because the DSO is only present in the sys crate build output
directory, not in a loader-visible Cargo runtime directory.
## Minimal Repro
This issue can be reproduced with a tiny downstream crate whose
`build.rs` depends on `xlsynth`. The important part is that Cargo must
run a host build-script executable that links against the managed
`libxls` DSO downloaded by `xlsynth-sys`.
From a checkout of this repo:
```bash
XLSYNTH_REPO="$PWD"
rm -rf /tmp/xlsynth-buildrs-repro
mkdir -p /tmp/xlsynth-buildrs-repro/src
cat > /tmp/xlsynth-buildrs-repro/Cargo.toml <<EOF
[package]
name = "xlsynth-buildrs-repro"
version = "0.1.0"
edition = "2021"
build = "build.rs"
[build-dependencies]
xlsynth = { path = "$XLSYNTH_REPO/xlsynth" }
EOF
cat > /tmp/xlsynth-buildrs-repro/build.rs <<'EOF'
fn main() {
let _ = xlsynth::xls_parse_typed_value("bits[8]:42").unwrap();
}
EOF
cat > /tmp/xlsynth-buildrs-repro/src/lib.rs <<'EOF'
pub fn marker() {}
EOF
cd /tmp/xlsynth-buildrs-repro
env -u LD_LIBRARY_PATH cargo clean
env -u LD_LIBRARY_PATH cargo check
```
Before this fix, the final command can fail when Cargo runs the
downstream build script:
```text
error while loading shared libraries: libxls-...so: cannot open shared object file: No such file or directory
```
The failure happens even though linking succeeded, because the managed
DSO lives in `xlsynth-sys`’s `OUT_DIR`, which is not reliably searched
by the dynamic loader when Cargo later starts a downstream build-script
executable.
After this fix, the same command succeeds with `LD_LIBRARY_PATH` unset.
That verifies the intended long-term behavior: managed DSOs are staged
into Cargo’s profile `deps` directory, which Cargo already makes
available when running host executables such as build scripts, without
requiring CI-specific or user-specific environment setup.
As an additional sanity check after the successful build, reviewers can
confirm that the managed DSO was staged where Cargo-run host executables
can find it:
```bash
find target/debug/deps -maxdepth 1 -name 'libxls-*' -print
```
# Solution
Stage managed `libxls` DSOs into Cargo’s profile `deps` directory in
addition to keeping them in `xlsynth-sys`’s `OUT_DIR`.
Cargo already includes `target/<profile>/deps` in the dynamic library
search path when it runs Cargo-built host executables such as build
scripts. Placing the managed DSO there makes downstream build-script
executables able to start without requiring users or CI to manually set
`LD_LIBRARY_PATH`.
The change applies to managed DSOs from both the default download flow
and the `DEV_XLS_DSO_WORKSPACE` flow. On Unix, the DSO is symlinked into
`deps`; on non-Unix platforms, it is copied. Stale staged files or
symlinks are replaced.
The README is also updated to clarify that default downloaded artifacts
are staged automatically, while manually supplied `XLS_DSO_PATH` /
`DSLX_STDLIB_PATH` artifacts may still require the caller to make the
DSO discoverable at build/test runtime.
Co-authored-by: Codex noreply@openai.com