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

Using dylib as dependency without -Cprefer-dynamic doesn't work #90539

Open
bjorn3 opened this issue Nov 3, 2021 · 7 comments
Open

Using dylib as dependency without -Cprefer-dynamic doesn't work #90539

bjorn3 opened this issue Nov 3, 2021 · 7 comments
Labels
A-linkage Area: linking into static, shared libraries and binaries C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@bjorn3
Copy link
Member

bjorn3 commented Nov 3, 2021

I tried this:

//- a.rs
pub fn foo() {}

//- b.rs
extern crate a;
fn main() {
    a::foo();
}
$ rustc a.rs --crate-type dylib
$ rustc b.rs --crate-type bin --extern a

I expected to see this happen: It compiles and b dynamically links to liba.so which itself statically links to libstd.

Instead, this happened:

error: cannot satisfy dependencies so `std` only shows up once
  |
  = help: having upstream crates all available in one format will likely make this go away

error: cannot satisfy dependencies so `core` only shows up once
  |
  = help: having upstream crates all available in one format will likely make this go away

error: cannot satisfy dependencies so `compiler_builtins` only shows up once
  |
  = help: having upstream crates all available in one format will likely make this go away

error: cannot satisfy dependencies so `rustc_std_workspace_core` only shows up once
  |
  = help: having upstream crates all available in one format will likely make this go away

error: cannot satisfy dependencies so `alloc` only shows up once
  |
  = help: having upstream crates all available in one format will likely make this go away

error: cannot satisfy dependencies so `libc` only shows up once
  |
  = help: having upstream crates all available in one format will likely make this go away

error: cannot satisfy dependencies so `unwind` only shows up once
  |
  = help: having upstream crates all available in one format will likely make this go away

error: cannot satisfy dependencies so `cfg_if` only shows up once
  |
  = help: having upstream crates all available in one format will likely make this go away

error: cannot satisfy dependencies so `hashbrown` only shows up once
  |
  = help: having upstream crates all available in one format will likely make this go away

error: cannot satisfy dependencies so `rustc_std_workspace_alloc` only shows up once
  |
  = help: having upstream crates all available in one format will likely make this go away

error: cannot satisfy dependencies so `rustc_demangle` only shows up once
  |
  = help: having upstream crates all available in one format will likely make this go away

error: cannot satisfy dependencies so `std_detect` only shows up once
  |
  = help: having upstream crates all available in one format will likely make this go away

error: cannot satisfy dependencies so `addr2line` only shows up once
  |
  = help: having upstream crates all available in one format will likely make this go away

error: cannot satisfy dependencies so `gimli` only shows up once
  |
  = help: having upstream crates all available in one format will likely make this go away

error: cannot satisfy dependencies so `object` only shows up once
  |
  = help: having upstream crates all available in one format will likely make this go away

error: cannot satisfy dependencies so `memchr` only shows up once
  |
  = help: having upstream crates all available in one format will likely make this go away

error: cannot satisfy dependencies so `panic_unwind` only shows up once
  |
  = help: having upstream crates all available in one format will likely make this go away

error: aborting due to 17 previous errors

Making it work currently requires passing -Cprefer-dynamic when compiling liba.so.

Meta

rustc --version --verbose:

rustc 1.56.0 (09c42c458 2021-10-18)
binary: rustc
commit-hash: 09c42c45858d5f3aedfa670698275303a3d19afa
commit-date: 2021-10-18
host: x86_64-unknown-linux-gnu
release: 1.56.0
LLVM version: 13.0.0

This seems to have been the reason for a new test in #89836 failing.

@bjorn3 bjorn3 added A-linkage Area: linking into static, shared libraries and binaries T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. C-bug Category: This is a bug. labels Nov 3, 2021
@crazyboycjr
Copy link

crazyboycjr commented Nov 15, 2022

This issue has been one year and I can confirm it with a recent compiler (rustc 1.67.0-nightly (09508489e 2022-11-04)).

$ rustc b.rs --crate-type bin --extern a=liba.so
error: cannot satisfy dependencies so `std` only shows up once
  |
  = help: having upstream crates all available in one format will likely make this go away

error: aborting due to previous error

What's the current state of the issue (about the expected behavior or any plan to fix it)?

Also, I will be grateful if anyone could point me to the source code for the 'fundamental' reason of not being able to have the same dependency show up more than once. I've been stuck by various linkage issues about dynamic libraries in rust for weeks. I've seen people discuss this problem around (#34909 #3573) but could never figure out the underlying reason. @bjorn3 @alexcrichton

@bjorn3
Copy link
Member Author

bjorn3 commented Nov 15, 2022

The same crate not being allowed to show up in more than one linked artifact (dylib or executable) is deliberate. Duplication will lead to either symbol conflicts or symbols being duplicated. Neither of which is acceptable as it will break the guarantee that statics are never duplicated and with it break any crate using global state, including the standard library itself.

This issue however is about rustc deciding to dynamically link libstd despite the fact that it is already included in the dylib. This is something that can and should be fixed.

@crazyboycjr
Copy link

crazyboycjr commented Nov 15, 2022

Now I get it. This sounds quite reasonable and convincing. I also saw the following description about library duplication in this RFC just now.

In the common case duplication of a library in the same process does not tend to have adverse side effects, but some of the more flavorful features tend to interact adversely with duplication such as:

  • Globals with significant addresses (statics). These globals would all be duplicated and have different addresses depending on what library you're talking to.
  • TLS/TLD. Any "thread local" or "task local" notion will be duplicated across each library in the process.

Thanks so much for your explanation @bjorn3!

@DemiMarie
Copy link
Contributor

What if libstd is a dylib?

@bjorn3
Copy link
Member Author

bjorn3 commented Dec 31, 2022

The problem is exactly that libstd is available as both an rlib and dylib. Without -Cprefer-dynamic rustc will pick the rlib and link it into the user dylib and then when attempting to link against this user dylib, it will try to pick the dylib version of libstd instead of the already linked in rlib version. If libstd was only available as either rlib or dylib there shouldn't be any issue.

@lvella
Copy link

lvella commented Jun 27, 2023

This is a rustc bug or a cargo bug? I.e., should this intelligence of deciding whether to use -Cprefer-dynamic be part of rustc or cargo? There is this related cago issue.

What if the dylib has other common dependencies with the binary, won't it cause the same issue?

@bjorn3
Copy link
Member Author

bjorn3 commented Jun 27, 2023

Cargo already passes -Cprefer-dynamic for compiling everything when any crate depended on by your code is only available as dylib. It doesn't do so when compiling a dylib as final artifact though.

This issue is about a rustc bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-linkage Area: linking into static, shared libraries and binaries C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants