wg
wg copied to clipboard
Support linker scripts in Cargo.toml / build.rs
As per https://github.com/rust-embedded/wg/pull/24#issuecomment-464469319_, I'm opening a new issue.
The current recommendation for making custom linker scripts is to create a .cargo/config file and add a reference to the linker script there. The previous discussion identified a number of issues with this:
- It puts configuration data in a file that's ostensibly not going to be checked in
- It's difficult to change it on a per-device basis
Additionally, I would like to add some more issues I see with it, particularly with workspaces:
- The build depends on the directory you're in. For example, here the data section moved, which was a subtle bug to track down:
$ cargo build -p kernel --target riscv32imac-unknown-none-elf
$ riscv64-unknown-elf-readelf -S target/riscv32imac-unknown-none-elf/debug/kernel
There are 24 section headers, starting at offset 0x117724:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .rodata PROGBITS 000100e0 0000e0 002f38 00 AM 0 0 16
[ 2] .text PROGBITS 00014000 004000 00ebe2 00 AX 0 0 2
[ 3] .trap PROGBITS 00022be2 012be2 000104 00 AX 0 0 1
[ 4] .data PROGBITS 00023000 013000 002bc8 00 WA 0 0 4
[ 5] .sdata PROGBITS 00025bc8 015bc8 000004 00 WA 0 0 4
...
$ cd kernel
$ cargo build -p kernel --target riscv32imac-unknown-none-elf
$ riscv64-unknown-elf-readelf -S ../target/riscv32imac-unknown-none-elf/debug/kernel There are 21 section headers, starting at offset 0xfd404:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS ffd00000 001000 00c0c0 00 AX 0 0 4
[ 2] .rodata PROGBITS ffd0c0c0 00d0c0 002f34 00 AM 0 0 16
[ 3] .data PROGBITS ffd80000 010000 002bcc 00 WA 0 0 4096
[ 4] .bss NOBITS ffd82bcc 012bcc 000210 00 WA 0 0 4
...
$
- It is required to copy the linker args on a per-target basis. For example, duplicate arguments need to be made for
riscv32imac-unknown-none-elfandriscv32i-unknown-none-elf, even though they're identical. - It isn't possible to do a
cargo build --target riscv32imac-unknown-nonefrom the root, since cargo appears to ignore the.cargo/configsetting.
Some of these could be fixed if cargo read .cargo/config from the crate root, which may be an acceptible workaround, however it seems to me that's just working around the problem.
I think it would be much better if cargo supported setting the linker flags from e.g. build.rs so they can be set on a per-crate basis, possibly based on the build environment in something like a CI infrastructure.
Big :+1: from me, but this should probably be filed as a Cargo issue at https://github.com/rust-lang/cargo
I'm probably misunderstanding something, but it's absolutely possible to check in .cargo/config, and cargo will read it just fine. Cargo walks the path from the current working directory upwards to find .cargo/config.
I'm 100% on board with a build-script mechanism to set linker flags though.
My understanding is that, you need to check in .cargo/config in a workspace targeting multiple architectures at once. Consider a workspace containing:
- x86_64 testing application
- An ARM micrcocontroller testing firmware
- A serialization crate to send data back and forth, compiled for both x86_64 and ARM.
Setting the architecture to .cargo/config is required for the x86_64 testing application and firmware crate for cargo build, without an explicit target architecture to "do the right thing".
I created an issue in the cargo repository: https://github.com/rust-lang/cargo/issues/7984