Skip to content

[Cargo] let build scripts pass (arbitrary) linker arguments to rustc #1766

Closed
@japaric

Description

@japaric

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:$keys, 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 supports gcc-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

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-dev-toolsRelevant to the development tools team, which will review and decide on the RFC.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions