[rustc] Unable to build 'no_std' crate into dylib

Hi folks,

I am having an issue of building a dylib with no_std.

$ cat src/lib.rs
#[no_std]

$ rustc src/lib.rs --crate-type dylib -C prefer-dynamic -o libnostd_dylib.so
error: language item required, but not found: `eh_personality`

error: `#[panic_handler]` function required, but not found

error: aborting due to 2 previous errors

After adding the missing language items, the compilation is fine.

$ cat src/lib.rs
#![no_std]
#![feature(lang_items)]
#[lang = "eh_personality"] extern fn eh_personality() {}
#[panic_handler] fn panic(_info: &core::panic::PanicInfo) -> ! { loop {} }

But linking the product (libnostd_dylib.so) into an executable gives me duplicate language items.

$ cat src/main.rs
use nostd_dylib;
fn main() { }

$ rustc --edition=2021 src/main.rs --crate-type bin -L . --extern nostd_dylib=libnostd_dylib.so -C prefer-dynamic # cargo build also works the same way
warning: unused import: `nostd_dylib`
 --> src/main.rs:1:5
  |
1 | use nostd_dylib;
  |     ^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

error: duplicate lang item in crate `lib` (which `main` depends on): `panic_impl`.
  |
  = note: the lang item is first defined in crate `std` (which `main` depends on)
  = note: first definition in `std` loaded from /home/cjr/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-d6566390077dd5f5.so, /home/cjr/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-d6566390077dd5f5.rlib
  = note: second definition in `lib` loaded from /home/cjr/misc/nostd-dylib/libnostd_dylib.so

error: duplicate lang item in crate `lib` (which `main` depends on): `eh_personality`.
  |
  = note: the lang item is first defined in crate `panic_unwind` (which `std` depends on)
  = note: first definition in `panic_unwind` loaded from /home/cjr/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-a8f484438681c15e.rlib
  = note: second definition in `lib` loaded from /home/cjr/misc/nostd-dylib/libnostd_dylib.so

error: aborting due to 2 previous errors; 1 warning emitted

As others have pointed out (How to build a standard Linux .so library with stable Rust without using std? - Stack Overflow), an end product such as a binary executable needs panic handlers and exception handling routines to run. I can understand that. I may also partially get/accept the point that a shared library could be an end product (perhaps it would be better if someone could name an example).

But what I feel quite confusing is that, most of the time, I know my dylib will be linked by other crates, and those crates (or libstd) will ultimately provide these language items, so how can I produce a no_std dylib without providing these two language items in this crate itself?

If you want your dylib to be compatible with programs that use libstd, you will have to link libstd into this dylib. There is no way around this unfortunately.

Thanks for your reply @bjorn3 ! That wouldn't be a problem. I'm working on a plugin system so I can make sure all dynamic libraries I'm using link with libstd dynamically (and they are built with the exact same compiler toolchain). Rust is a great language and its community is also great. I want to explore the possibility in Rust of implementing a runtime that can hot reload its plugins. Given that, do you have any other recommendations about how to build no_std dylibs?

With all dynamic libraries I mean all dynamic libraries without exception. That is not just the plugins, but also the libnostd_dylib.so that the plugins depend on.

With all dynamic libraries I mean all dynamic libraries without exception. That is not just the plugins, but also the libnostd_dylib.so that the plugins depend on.

Yes, I can make sure of that.

You should use a std Cargo feature, and #[cfg(std)] extern crate std;.

Hi @riking, thanks for your reply! I'm not sure I quite follow your idea. Did you mean to change the line of #![no_std] in src/lib.rs to #[cfg(std)] extern crate std;?