Description
Use cases
Bare metal embedded development
Linking Rust programs for bare metal targets always (unless there some C in the mix) require passing a linker script to the linker. This linker script specifies the memory layout of the target device and, if omitted, the resulting binary will not work on the target device (the device will not boot or crash during the boot process).
The current way to pass these flags to the linker (using rustc as a proxy) is via the build.rustflags
or target.$triple.rustflags
key in .cargo/config:
# .cargo/config
[target.thumbv7em-none-eabihf]
rustflags = [
"-C", "link-arg=-nostartfiles",
"-C", "link-arg=-Tlayout.ld",
]
This is troublesome because:
- A library can't pass a
.cargo/config
to its dependent crates. Every user of the library will have to manually copy the library.cargo/config
in their binary project.
Other use cases
There are probably other use cases that I don't know about
Straw man proposal
Cargo will learn about a new "build script key": rustc-link-arg
. Cargo will collect all the values under that key and pass those to all its rustc
invocations via the -C link-arg
flag. For example, this build script output:
cargo:rustc-link-arg=-Tlayout.ld
cargo:rustc-link-arg=-nostartfiles
Makes Cargo pass the -C link-arg=-Tlayout.ld -C link-arg=-nostartfiles
to all its rustc
invocations.
As with other cargo:$key
s, Cargo will collect these values from all the dependencies.
Potential problems
- Reduces composability of crates. For instance, what happens if two crates want to inject their own linker scripts? iirc, @nagisa mentioned that this form of "non-composability" is already present today in some other feature hmm ... was it symbol names (
#[export_name]
,#[no_mangle]
)? - Linker arguments are ... linker dependent. So if a crate hard codes some linker arguments for a specific linker then that crate can't be used with any other linker. This doesn't seem like a problem for ELF files because
rustc
only supportsgcc
-style linkers. And if a crate needs to support two or more targets that use different linkers then the build.rs can simply pick different linker arguments based on the value of the$TARGET
env variable. - Linker arguments are order sensitive. Depending on A and B might not be the same as depending on B and A because one combination will generate linker arguments in a different order than the other. We can't do much in this regard other than encourage users to only use order independent flags (the flags needed in the use case presented above are order independent). FWIW, today, build scripts can pass
-l
-style arguments to the linker and those are order sensitive.
cc @nagisa @alexcrichton
@jamesmunns and @cbiffle may be interested as well