Can I pick and choose dynamic and static linking for specific dependencies?

I'm trying to do some research on dynamic linking in Rust without caring about ABI stability. The reason is that I'm building for an embedded Linux target (ramips running OpenWrt), and since we build the entire image at once, ABI mismatches between Rust versions don't matter. However, what does matter is the binary size.

The stdlib takes up about 300-400kB (I think), and there's one dependency shared between all binaries that also weighs in at about 400kB. For 4-8 binaries, this would amount to a saving of up to 6MB or so, which is a huge fraction of the 16MB flash I'm targeting.

However, dynamically linking everything would be unmanageable with OpenWrt's build system. So I need to be able to pick and choose what gets statically compiled and what doesn't.

It's hard to search for, because obviously everyone's mostly interested in ABI stability as a pathway to dynamic linking. But I care about dynamic linking, and not about ABI. Does anyone know of things that people have written about this admittedly niche topic, or experiments for it? It is quite hard to search for, possibly because I don't know the right terms.

Even things that are just hacky proofs-of-concept (not judging!) can be shoehorned into my existing build system, but I have found nothing whatsoever that could even be a starting point.

1 Like

For system/C dependencies that you use via *-sys crates this is controlled on per-crate basis. Unfortunately there's no standard, so you need to check each crate's documentation what env vars or Cargo features it wants.

For Rust-native libraries, there's only -C prefer-dynamic that I know of. I don't think there's a fine-grained control exposed anywhere.

For reuse of your own Rust code there's abi_stable crate that lets you use cdylib/C ABI for a subset of Rust types.

1 Like

This is my situation, but it seems like -C prefer-dynamic is not going to do what I need. Do you know if there's a way to "manipulate" it eg. build other things so that it's forced to choose dynamic linking, but not for everything?

As soon as a single dylib is used as dependency, -Cprefer-dynamic is implicitly enabled. If you want some things dynamically linked and others not, you must ensure that the things you want dynamically linked are available as dylib and the things you want statically linked are only available as rlib. Also be aware that when building dylibs, rlib only dependencies are statically linked into the dylib unless they are either available through another dylib or only available as dylib themself. If an rlib gets linked into multiple dylibs, rustc will refuse to link both dylibs into the same program to prevent symbol conflicts.

1 Like

Do you know how to do this for eg. the stdlib, or an arbitrary crate?

This makes sense, but also makes things tricky, since there are a great many common "leaf" type dependencies. I'll keep it in mind.

For the standard library, no, but if you want to use more than one dylib, you will have to dynamically link it either way. For an arbitrary crate, you will need to change its Cargo.toml. Cargo currently has terrible support for dylibs. I would really love improvements to cargo's dylib support. At the very least automatically forcing crates to be dylibs as necessary to prevent crates being linked into more than one dylib.

You could add a dylib crate that depends on those dependencies that would be duplicated and then add a dependency to this dylib to the other dylibs. Note that declaring a dependency in Cargo.toml is not enough. You also have to reference it in the crate source. extern crate or use is enough.

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.