I have a rust project, it has the following structure:
├─engine
│ │ Cargo.lock
│ │ Cargo.toml
│ │
│ └─src
│ lib.rs
│
├─sandbox
│ │ build.rs
│ │ Cargo.toml
│ │
│ └─src
│ main.rs
│
└─test_static
│ Cargo.toml
│
└─src
lib.rs
The crate sandbox is a bin crate, engine is designed to be a dylib, and test_static is a rlib.
In sandbox/cargo.toml:
[package]
name = "sandbox"
version = "0.1.0"
edition = "2021"
build = "build.rs"
[dependencies]
prefer-dynamic = "0"
engine = { path = "../engine" }
test_static = { path = "../test_static" }
I want to build crate engine as a dylib, test_static as an rlib, and build sandbox, with test_static statically linked and engine dynamically linked.
To achieve my goal, I used the following rustc commands:
rustc --crate-name engine engine\src\lib.rs --crate-type dylib -C prefer-dynamic
rustc --crate-name test_static test_static\src\lib.rs --crate-type rlib
rustc sandbox\src\main.rs --crate-type bin --extern engine='engine.dll' --extern test_static='libtest_static.rlib'
Those commands worked just fine, but I wonder if there is a way to achieve this by Cargo... When using command 'cargo build' in project root directory, I always get a binary that links 2 dependencies statically.
I searched for official docs, RFCs, but I got nothing, seems that the dependencies must be either all-static (by default) or auto-dynamic (using RUSTFLAGS='-C prefer-dynamic', which will cause the rust to build everything dynamically if possible).
Is there any Cargo.toml settings syntax to specify how to link the dependency crate? For example, the build-in libstd, when using RUSTFLAGS='-C prefer-dynamic', the libstd will also be linked dynamically, which is not what I expected.
-C prefer-dynamicdoesn't actually affect how crates are built, only how they're searched for. In addition to that setting (which is how you getstdto be linked dynamically so that it can be resolved to appear exactly once), what you need to do is add this to theCargo.tomlof the dependency which you want to link dynamically (in your case,engine):This will tell Cargo that the crate can only be a Rust DLL (those have an unstable ABI, so you can't use them with code built by a different compiler version or with different compilation settings – the special ugly name prevents you from doing that).
If you want the
enginecrate to be able to exist in both incarnations, you can do what Bevy does with itsdynamicfeature flag that turns the engine into a Rust DLL for fast incremental compiles. Thoroughly explaining its behavior is outside the scope of this answer, but you can check out Bevy'sCargo.tomlon the top-level crate, it's not a very complicated mechanism.