Link the Rust standard library dynamically

Hello! I have a set of binaries and libraries written in C++ that I cross compile for different architectures. I only have dynamically linked binaries. I want to rewrite some of them in Rust.

I tried to compile for aarch64-unknown-linux-musl with cargo build --target aarch64-unknown-linux-musl and the following .cargo/config:

[target.aarch64-unknown-linux-musl]
linker = "aarch64-openwrt-linux-gcc"
rustflags = ["-C", "target-feature=-crt-static"]

Running $ readelf -d target/aarch64-unknown-linux-musl/debug/my-bin gives:

Dynamic section at offset 0x28aa0 contains 30 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so]
 0x000000000000000c (INIT)               0x31c8
 0x000000000000000d (FINI)               0x1f204
[...]

I was expecting rust’s libstd.so to be linked dynamically as well, similarly to libgcc_s.so and libc.so or similarly to the libstdc++.so library for C++ binaries:

Dynamic section at offset 0x8ada0 contains 31 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so]

I also tried the suggestion with -C prefer-dynamic from here and it works when not cross compiling. When specifying the target as above, I get a statically linked binary.

Is there an extra flag or compiling option I do not know of? Thank you!

Have you tried with the target aarch64-unknown-linux-gnu? (maybe the musl target is somehow special cased)

This one seems to be working with the following config:

[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"
rustflags = ["-C", "prefer-dynamic"]
$ readelf -d target/aarch64-unknown-linux-gnu/debug/foo

Dynamic section at offset 0x1d50 contains 29 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libstd-ff46ed8df5a75d07.so]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
...

It does the same as for aarch64-unknown-linux-musl if I use -C target-feature=-crt-static though. So the question now would be: why doesn’t -C prefer-dynamic work for the musl target?

Because the aarch64-unknown-linux-musl target has only shipped the static files.

$ ls ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/aarch64-unknown-linux-musl/lib
crt1.o                                      libpanic_abort-258f5d010b656084.rlib
crti.o                                      libpanic_unwind-765c392663bd34b7.rlib
crtn.o                                      libproc_macro-f89fa6bc1543b74b.rlib
liballoc-c47e11e0b4c869e2.rlib              librustc_demangle-85b43da92537c77f.rlib
libbacktrace_sys-1059e0ba7f05fd67.rlib      librustc_std_workspace_core-5a60e280b382f06e.rlib
libcompiler_builtins-566972fa63f867ee.rlib  libstd-b806fbdf01014e64.rlib
libcore-8010f7064010be9c.rlib               libterm-5a3c233fedc016bd.rlib
libgetopts-21c5ddfdf14ab53b.rlib            libtest-d65243ce23c10440.rlib
liblibc-1d32a47a0bdcb0a2.rlib               libunwind-f8a77019eff82b98.rlib

I can see the shared libs here, including libstd-4afe97f61408a5db.so:

$ ls ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib
libarena-04688850ce83cf02.so                librustc_cratesio_shim-0bcbb2f1a3c3be75.so    librustc_lint-a9f668bb4942dbe2.so      librustc_save_analysis-5c307ce22b40f4dd.so  libsyntax_pos-d11e27365735b648.so
libfmt_macros-824ce923212521a7.so           librustc_data_structures-73141599e1e8b12e.so  librustc_macros-4f9577e1874418ad.so    librustc_target-3fdbac8ff03705f1.so         libterm-9e4b9a71ba4208f8.so
libgraphviz-1fb24040f23d691d.so             librustc_driver-481b0661f3590517.so           librustc_metadata-b9a0d646e993e9b6.so  librustc_traits-b4e3b475a5d7000b.so         libtest-b65b615bd7371fd3.so
libLLVM-8-rust-1.37.0-nightly.so            librustc-edb8bf5f8fb148b0.so                  librustc_mir-eb1298f7b1f79572.so       librustc_typeck-150167520cdbc501.so         rustlib
librustc_allocator-998f576aec7ee28f.so      librustc_errors-670cb6d00ba84a59.so           librustc_passes-8f5dadc048680b2b.so    libserialize-e0cad0738957d549.so
librustc_borrowck-f750e3a40b7dae97.so       librustc_fs_util-665c51e58d00add9.so          librustc_plugin-5d27a0dfa773714d.so    libstd-4afe97f61408a5db.so
librustc_codegen_ssa-550042abbb43b8ad.so    librustc_incremental-356c97b918cd8163.so      librustc_privacy-6be0c67f17b5820c.so   libsyntax-976b465cac8907f6.so
librustc_codegen_utils-e97d424bd3d23c52.so  librustc_interface-9a7ca840c266b01a.so        librustc_resolve-811abb8b5c416839.so   libsyntax_ext-3c8bcb2d58aad0cb.so

I ended up using xargo to build my own std with my toolchain. I also had to specify both -C target-feature=-crt-static and -C prefer-dynamic.

$ readelf -d target/aarch64-unknown-linux-musl/release/foo

Dynamic section at offset 0xdc8 contains 25 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libstd.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so]
[...]
$ ls -lh target/aarch64-unknown-linux-musl/release/foo
-rwxrwxr-x. 2 master master 5.7K Jun 12 13:43 target/aarch64-unknown-linux-musl/release/foo
$ ls -lh ~/.xargo/lib/rustlib/aarch64-unknown-linux-musl/lib/libstd.so
-rwxrwxr-x. 1 master master 2.9M Jun 12 13:43 /home/master/.xargo/lib/rustlib/aarch64-unknown-linux-musl/lib/libstd.so

Seems to be ok for now. Thank you!

1 Like

Those are the native shared libraries for x86_64. You need libraries for your specific target – but yes, xargo should work fine for that.

Ah, of course they are. In trying to find the shared libraries for musl I ended up pasting nonsense. You are right, thank you! I can see that the aarch64-unknown-linux-gnu ships the shared libraries, while aarch64-unknown-linux-musl does not.