Suppress ``link-arg`` in dependency

I’m building a library for FFI users that depends on a sibling library
which is also available through FFI. To illustrate the project layout:

.
├── dependency
│   ├── build.rs
│   ├── Cargo.toml
│   └── src
│       └── lib.rs
└── main
    ├── build.rs
    ├── Cargo.toml
    └── src
        └── lib.rs

Here both main and dependency are libraries of crate-type = ["lib", "cdylib"].
(In the actual product they’re part of a workspace but the problem
occurs without a workspace as well so let’s not complicate matters.)

main depends on dependency like so:

[dependencies]
dependency = { path = "../dependency" }

dependency is a leaf library. Both main and dependency get
their DT_SONAME embedded like so:

$ cat dependency/build.rs
fn main () { println!("cargo:rustc-cdylib-link-arg=-Wl,-soname,libdependency.so.0"); }
$ cat main/build.rs
fn main () { println!("cargo:rustc-cdylib-link-arg=-Wl,-soname,libmain.so.0"); }

(Actually I’m using the cdylib-link-lines crate to accomplish this
but it boils down to the same issue.)

This works fine for libdependency.so. However, when running
cargo run in ./main/, I obtain a libmain.so with the
SONAME of libdependency.so embedded
:

$ readelf -d target/debug/libmain.so |grep SONAME
 0x000000000000000e (SONAME)             Library soname: [libdependency.so.0]

This is obviously wrong, it should be libmain.so.0.. :wink: The reason
for this is that the rustc-cdylib-link-arg lines get executed from
the build.rs of both libraries. Thus both of them end up
getting appended to the rustc command line:

rustc \
    --crate-name main \
    --edition=2021 src/lib.rs \
    --error-format=json \
    --json=diagnostic-rendered-ansi,artifacts,future-incompat \
    --crate-type lib \
    --crate-type cdylib \
    --emit=dep-info,link \
    -C embed-bitcode=no \
    -C debuginfo=2 \
    -C metadata=e0d0d2eeaf7bb2d0 \
    --out-dir /home/phg/src/ugh-cargo/soname/main/target/debug/deps \
    -C incremental=/home/phg/src/ugh-cargo/soname/main/target/debug/incremental \
    -L dependency=/home/phg/src/ugh-cargo/soname/main/target/debug/deps \
    --extern dependency=/home/phg/src/ugh-cargo/soname/main/target/debug/deps/libdependency.rlib \
    -C link-arg=-Wl,-soname,libmain.so.0 \
    -C link-arg=-Wl,-soname,libdependency.so.0

Now since there is only one SONAME field per object file, this
would actually work if the order of link-args were reversed. As
it is, later arguments override earlier ones and bam, libmain.so
wrongly claims it’s libdependency.so.0!

Ideally Cargo would support setting the SONAME directly in
Cargo.toml
.

Alternatively, I’d be happy with a mechanism to suppress the bad -C link-arg in the above example when building libmain.so. However,
conditionally disabling the println! in dependency/build.rs
results in the SONAME being missing from libdependency.so.
Is there a way to filter rustc arguments added by dependencies?

I guess if I could tell cargo to put the output of main/build.rs
last, that would work too.

FWIW I also tried adding to the linker line in .cargo/config.toml
but the values there get prepended to those from build.rs.

EDIT: So do arguments to cargo on the command line (--config='build.rustflags = [ "-C", "link-arg=-Wl,-soname,lib__ARGV__.so.0" ]').

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.