Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support soname for cdylibs #5045

Open
kornelski opened this issue Feb 15, 2018 · 24 comments
Open

Support soname for cdylibs #5045

kornelski opened this issue Feb 15, 2018 · 24 comments
Labels
A-linkage Area: linker issues, dylib, cdylib, shared libraries, so C-feature-request Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted` E-medium Experience: Medium S-needs-design Status: Needs someone to work further on the design for the feature or fix. NOT YET accepted.

Comments

@kornelski
Copy link
Contributor

kornelski commented Feb 15, 2018

rustc supports setting soname via -C link-arg. However, it can't be used from Cargo, since RUSTFLAGS affects all invocations of the compiler, and it could potentially set soname on dependencies.

Some previous discussions about soname support were dismissed based on the fact that Rust's native ABI is not stable. That is not relevant for cdylibs, because the C ABI exposed by cdylibs is stable.

I'm interested in using this feature in cargo-deb. soname is required to build first-class Linux libraries (e.g. for Debian) with Rust.

I think it'd be wonderful if Cargo automatically set soname of cdylib to semver-major when version is >= 1.0.0 (i.e. don't set any for 0.x.x), since soname and semver-major promise basically the same thing. However, a separate Cargo.toml field, command line flag, or env var would work as well.

@gibix
Copy link
Contributor

gibix commented May 23, 2018

I'm interested for the same reason of @kornelski to be able to cross-compile rust libs on gentoo.

@kornelski
Copy link
Contributor Author

The lack of support for linker flags is one of issues preventing librsvg from switching to Cargo. It needs flags like this:

	-version-info @RSVG_LT_VERSION_INFO@ \
	-export-dynamic \
	-no-undefined \
	-export-symbols-regex "^rsvg_.*" 

@sdroege
Copy link
Contributor

sdroege commented Feb 17, 2019

Those are all libtool flags and not direct linker flags that ld or link.exe would handle.

@kornelski
Copy link
Contributor Author

kornelski commented Feb 17, 2019

Ah, ok. Still needs a post build script or something, since the vanilla cdylib crate type doesn't have it.

@lu-zero
Copy link
Contributor

lu-zero commented Mar 8, 2019

@kornelski I'm updating my patch, then we can work on the installing phase together if you like :)

I need it already for crav1e and the relibc developer seem interested as well.

bors added a commit that referenced this issue Mar 27, 2019
Add cargo:rustc-link-arg to pass custom linker arguments

It is useful to produce correct `cdylibs` on platforms such as Linux and
MacOS.

Groundwork to address #5045 in the future.
@federicomenaquintero
Copy link
Contributor

federicomenaquintero commented May 17, 2019

From #6298, am I correct in understanding that the remaining work is to figure out platform-specific linker arguments to define the soname and such?

@lu-zero
Copy link
Contributor

lu-zero commented May 18, 2019

The install phase rfc and this have more details on what is missing.

I might take this weekend to publish my draft applet so we can experiment a bit outside cargo if you want to join me in this :)

@kornelski
Copy link
Contributor Author

kornelski commented May 18, 2019

But this is about cargo build, not cargo install, so the RFC won't help.

For example, cargo-deb needs to be able to build a correct library, without installing it system-wide. Running cargo install as part of package creation would be a very undesirable "leakage" that could pollute the build machine.

@lu-zero
Copy link
Contributor

lu-zero commented May 18, 2019

What I'm preparing is something along the lines of:

cargo c install --prefix=/usr --destdir=/staging/place

No pollution at all :)

@kornelski
Copy link
Contributor Author

kornelski commented May 18, 2019

But isn't that a workaround? It reminds me of ugly hacks like make install. The products are already in target/, they're just built wrong. I don't want to install anything, to any location, I just want to finish building them.

@lu-zero
Copy link
Contributor

lu-zero commented May 18, 2019

It is not.
If you want to build only you just issue a build command.

As a packager I enjoy having a working install target that gets all I need in the right places without having to reinvent the wheel every time. Nobody is forcing you to use what I'm writing :)

@kornelski
Copy link
Contributor Author

Oh, you mean you're writing "cargo-c"? I assumed that c was a typo, and you were suggesting cargo install as the workaround (and that RFC goes way beyond staging build products, into making cargo install a package manger that can't uninstall what it has installed, so I'm very dismayed by it).

@lu-zero
Copy link
Contributor

lu-zero commented May 18, 2019

yes, I try to make an applet to generate all that's needed (.pc files, .h files, etc) and install it without to have to repeat myself too much (currently we are having a small vlc workshop so I might or might not get to publish it this weekend)

@lu-zero
Copy link
Contributor

lu-zero commented Jun 13, 2019

Now I have two ways to help on this:

Ideally I could make a separate crate for the .pc creation as well if somebody needs it.

@h0ru5
Copy link

h0ru5 commented Feb 8, 2020

new to rust/cargo: would there be a possibility to write a plugin that does set the soname as post-production step? (yes, it is a workaround until mainline can do it).

Right now I try to do the same on the side consuming the .so

@lu-zero
Copy link
Contributor

lu-zero commented Feb 9, 2020

it is, you may using cdylib-link-lines (even if it could enjoy an overhaul).

@MartinKolbAtWork
Copy link

I am facing exactly this issue when trying to use Rust-based libraries (i.e. I used the two Rust-based WebAssembly engines Wasmtime and Wasmer) in a C/C++ code-base.

These Rust libraries have no SONAMES, which causes the CMake build to produce wrong binaries.

I opened an issue at CMake, but these folks clearly confirmed that shared libraries without an SONAME entry are a bug that needs to be fixed by the one building the library:
https://gitlab.kitware.com/cmake/cmake/-/issues/22307#note_971562

Could you please continue working on this topic? Otherwise consuming Rust-based libraries with the popular CMake build system will remain awkward.

Hywan added a commit to Hywan/wasmer that referenced this issue Jun 18, 2021
See wasmerio#2429 for more
context. I'm copy-pasting the original comment from @MartinKolbAtWork
here:

> The shared library `libwasmer.so` does not have an `SONAME`
> specified. This can be checked using this command: `objdump -p
> libwasmer.so | grep SONAME`
>
> When `libwasmer.so` is consumed in CMake, the **linker produces a
> wrong output file due to the missing SONAME**.  There is a
> workaround for this in CMake, but according to a reply from the
> CMake folks, the missing SONAME is a bug that must be fixed by the
> library provider:
> https://gitlab.kitware.com/cmake/cmake/-/issues/22307#note_971562
> “_The libwasmer.so file should have a SONAME.  If it doesn't, that's
> a bug in the wasmer package_”
>
>  The problem is **inherent for all Rust builds of cdylibs**:
> rust-lang/cargo#5045 The Rust community
> did not fix this since 2018 (see issue above), but fortunately it’s
> **easy to fix** for library creators. You just need to put the
> following code into the `build.rs` of the library:
>
> ```
> if cfg!(target_os = "linux") {
>     println!("cargo:rustc-cdylib-link-arg=-Wl,-soname,libwasmer.so");
> }
> ```
>
> I tried putting these lines into `lib/c-api/build.rs`, and then
> `libwasmer.so` was built correctly, including a SONAME entry.
Hywan added a commit to Hywan/wasmer that referenced this issue Jun 18, 2021
See wasmerio#2429 for more
context. I'm copy-pasting the original comment from @MartinKolbAtWork
here:

> The shared library `libwasmer.so` does not have an `SONAME`
> specified. This can be checked using this command: `objdump -p
> libwasmer.so | grep SONAME`
>
> When `libwasmer.so` is consumed in CMake, the **linker produces a
> wrong output file due to the missing SONAME**.  There is a
> workaround for this in CMake, but according to a reply from the
> CMake folks, the missing SONAME is a bug that must be fixed by the
> library provider:
> https://gitlab.kitware.com/cmake/cmake/-/issues/22307#note_971562
> “_The libwasmer.so file should have a SONAME.  If it doesn't, that's
> a bug in the wasmer package_”
>
>  The problem is **inherent for all Rust builds of cdylibs**:
> rust-lang/cargo#5045 The Rust community
> did not fix this since 2018 (see issue above), but fortunately it’s
> **easy to fix** for library creators. You just need to put the
> following code into the `build.rs` of the library:
>
> ```
> if cfg!(target_os = "linux") {
>     println!("cargo:rustc-cdylib-link-arg=-Wl,-soname,libwasmer.so");
> }
> ```
>
> I tried putting these lines into `lib/c-api/build.rs`, and then
> `libwasmer.so` was built correctly, including a SONAME entry.
@lu-zero
Copy link
Contributor

lu-zero commented Sep 16, 2022

Ideally you might get around setting the CARGO to cargo capi if cargo-ndk calls normally cargo build cargo install or extend a little cargo-ndk to know about cargo-c and call it instead of cargo if present.

For android you shouldn't have problems not using cargo-c for it.

@weihanglo
Copy link
Member

Out of curious. What's the missing part to make progress on this issue?

From my understanding, rustc-link-arg family in build script solve this issue somehow. We could also simply run something like the following to build a shared library with SONAME:

cargo rustc --crate-type cdylib -- -C link-arg=-Wl,-soname,libmycrate.so

Sorry I am a bit lost on this thread…

@jschwe
Copy link
Contributor

jschwe commented Jan 17, 2023

What's the missing part to make progress on this issue?

For me, it's this part from the opening post (emphasis mine):

I think it'd be wonderful if Cargo automatically set soname of cdylib to semver-major when version is >= 1.0.0 (i.e. don't set any for 0.x.x), since soname and semver-major promise basically the same thing. However, a separate Cargo.toml field, command line flag, or env var would work as well.

So what's missing from my point of view is a decision if cargo could automatically set the soname for cdylibs according to semver, or at least provide an opt-in mechanism for this, which is a bit more user-friendly than setting linker flags.

@phi-gamma
Copy link
Contributor

Another argument for having Cargo set the DT_SONAME: Only Cargo knows
it is linking the final binary and not some dependency. Here’s an
example where the build.rs approach fails: https://gitlab.com/phgsng/buggy-soname
I also outlined the problem on discourse: https://users.rust-lang.org/t/89245

The gist of it is that one library that is built as a cdylib
depends on another which also produces a cdylib. This causes the
build.rs of both libraries to be executed and Cargo ends up
appending the two extra link-args but in the wrong order, so the
wrong SONAME ends up in the shared object. Ideally, Cargo would add
the correct SONAME argument to the linker line exactly once, when
linking the final shared object.

(This is not a contrived usecase but based on a real world product that
is unfortunately proprietary.)

@weihanglo
Copy link
Member

@weihanglo weihanglo added the C-feature-request Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted` label Jun 29, 2023
cathay4t added a commit to cathay4t/nmstate that referenced this issue Oct 20, 2023
Previously, without fix on SONAME[1], when installing rpm generated by
`make rpm`, Fedora will complains:

    error: Failed dependencies:
            libnmstate.so()(64bit) is needed by nmstate-devel

To fix the issue, we updated the nmstate.spec.in to hold:
    * Both Fedora and RHEL specific lines
    * Both official release and snapshot build(snapshot will use
      internet for crates.io access)

Tested on CentOS stream 9, Fedora 38 and Fedora Rawhide(40).

[1]: rust-lang/cargo#5045

Signed-off-by: Gris Ge <fge@redhat.com>
cathay4t added a commit to cathay4t/nmstate that referenced this issue Oct 20, 2023
Previously, without fix on SONAME[1], when installing rpm generated by
`make rpm`, Fedora will complains:

    error: Failed dependencies:
            libnmstate.so()(64bit) is needed by nmstate-devel

To fix the issue, we updated the nmstate.spec.in to hold:
    * Both Fedora and RHEL specific lines
    * Both official release and snapshot build(snapshot will use
      internet for crates.io access)

Tested on CentOS stream 9, Fedora 38 and Fedora Rawhide(40).

Resolves: RHEL-5002

[1]: rust-lang/cargo#5045

Signed-off-by: Gris Ge <fge@redhat.com>
cathay4t added a commit to cathay4t/nmstate that referenced this issue Oct 20, 2023
Previously, without fix on SONAME[1], when installing rpm generated by
`make rpm`, Fedora will complains:

    error: Failed dependencies:
            libnmstate.so()(64bit) is needed by nmstate-devel

To fix the issue, we updated the nmstate.spec.in to hold:
    * Both Fedora and RHEL specific lines
    * Both official release and snapshot build(snapshot will use
      internet for crates.io access)

Tested on CentOS stream 9, Fedora 38 and Fedora Rawhide(40).

Resolves: RHEL-5002

[1]: rust-lang/cargo#5045

Signed-off-by: Gris Ge <fge@redhat.com>
cathay4t added a commit to cathay4t/nmstate that referenced this issue Oct 20, 2023
Previously, without fix on SONAME[1], when installing rpm generated by
`make rpm`, Fedora will complains:

    error: Failed dependencies:
            libnmstate.so()(64bit) is needed by nmstate-devel

To fix the issue, we updated the nmstate.spec.in to hold:
    * Both Fedora and RHEL specific lines
    * Both official release and snapshot build(snapshot will use
      internet for crates.io access)

Tested on CentOS stream 9, Fedora 38 and Fedora Rawhide(40).

Also removed copr build for RHEL/CentOS 8 due to no usage.

Resolves: RHEL-5002

[1]: rust-lang/cargo#5045

Signed-off-by: Gris Ge <fge@redhat.com>
cathay4t added a commit to cathay4t/nmstate that referenced this issue Oct 20, 2023
Previously, without fix on SONAME[1], when installing rpm generated by
`make rpm`, Fedora will complains:

    error: Failed dependencies:
            libnmstate.so()(64bit) is needed by nmstate-devel

To fix the issue, we updated the nmstate.spec.in to hold:
    * Both Fedora and RHEL specific lines
    * Both official release and snapshot build(snapshot will use
      internet for crates.io access)

Tested on CentOS stream 9, Fedora 38 and Fedora Rawhide(40).

Also removed copr build for RHEL/CentOS 8 due to no usage.

Resolves: RHEL-5002

[1]: rust-lang/cargo#5045

Signed-off-by: Gris Ge <fge@redhat.com>
cathay4t added a commit to cathay4t/nmstate that referenced this issue Oct 20, 2023
Previously, without fix on SONAME[1], when installing rpm generated by
`make rpm`, Fedora will complains:

    error: Failed dependencies:
            libnmstate.so()(64bit) is needed by nmstate-devel

To fix the issue, we updated the nmstate.spec.in to hold:
    * Both Fedora and RHEL specific lines
    * Both official release and snapshot build(snapshot will use
      internet for crates.io access)

Tested on CentOS stream 9, Fedora 38 and Fedora Rawhide(40).

Also removed copr build for RHEL/CentOS 8 due to no usage.

Resolves: RHEL-5002

[1]: rust-lang/cargo#5045

Signed-off-by: Gris Ge <fge@redhat.com>
cathay4t added a commit to nmstate/nmstate that referenced this issue Oct 20, 2023
Previously, without fix on SONAME[1], when installing rpm generated by
`make rpm`, Fedora will complains:

    error: Failed dependencies:
            libnmstate.so()(64bit) is needed by nmstate-devel

To fix the issue, we updated the nmstate.spec.in to hold:
    * Both Fedora and RHEL specific lines
    * Both official release and snapshot build(snapshot will use
      internet for crates.io access)

Tested on CentOS stream 9, Fedora 38 and Fedora Rawhide(40).

Also removed copr build for RHEL/CentOS 8 due to no usage.

Resolves: RHEL-5002

[1]: rust-lang/cargo#5045

Signed-off-by: Gris Ge <fge@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-linkage Area: linker issues, dylib, cdylib, shared libraries, so C-feature-request Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted` E-medium Experience: Medium S-needs-design Status: Needs someone to work further on the design for the feature or fix. NOT YET accepted.
Projects
None yet
Development

No branches or pull requests