-
Notifications
You must be signed in to change notification settings - Fork 98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC on linker customization convention #24
Conversation
Although not mentioned in the RFC text, both approaches require files that Cargo doesn't keep track of: custom target specification files or Examples of Cargo project templates: |
teensy3-rs for example has a fairly verbose linker script. It would be nice if it weren’t part of the boilerplate that needs to copied into every project. |
@SimonSapin a build script can be used to remove the need to manually copy that into each project. Example. The end user would still need to configure the linker invocation to pass |
Mmm i consider .cargo/config to be user+project configuration, i.e. not something to be version controlled. A virtual workspace root is the proper place for per-project config. [I wish certain configuration items could only go on virtual root rather than crate to make this clearer, but that's another discussion.] |
+1 on separating user config typically in |
For me, both approaches are unacceptable. Consider this: I'm trying to build something for a series of devices differing only in flash size (or similar irrelevant minutae). This is impossible to do without xargo with either of them AFAICT. |
I like this, but I wanted to note that I hope we can get to a world where we can easily build embedded applications for multiple 'configurations' (what in the C/Make/SCons world I might have called 'targets'). For example, imagine an IoT MQTT/WiFi demo application which can be built for maybe four popular ARM/MIPS developer kits, as well as a Mac/Windows/Linux command line application. As far as the embedded builds go, I see a 'configuration' as being defined by: The board (e.g. TI Stellaris Launchpad) As you say, the linker parameters are a function of the board (when you have external RAM/Flash), the SoC (when you have on-board RAM/Flash) and the application (when you have a need to store stuff in weird sections, like .no_init blocks for pools allocators). If your crate was say, a framework or an RTOS rather than a specific concrete application, then you might have multiple examples which are concrete applications. Again, you should be able to build any of those for any supported configuration. |
Chiming in from the Tock world, this is wonderfully timely, as I'm trying to bump Tock to the latest nightly (and have been struggling immensely with it off and on for the last week) Is there a reason that the contents of |
Thanks everyone for your comments!
Could you elaborate on what "user" and "project" configuration mean to you? In my mind there are only two types of settings in the Cargo world: crate settings and project local settings. Crate settings carry over with the crate regardless of whether it's build as a dependency or as the top crate. Project local settings only apply to the current project that's being built. Cargo.toml has mostly crate settings like the crate name and its dependencies. These are used by Cargo when the crate is build as the top crate or as a dependency. Cargo.toml also contains project local settings like
By virtual workspace do you mean a Cargo workspace or something else? Do note that linker arguments are only relevant to the top / application crate and that dependencies are oblivious to what those linker arguments are.
If by that you mean that Cargo.toml shouldn't contain project local settings like
For the particular example of variable flash size you wouldn't need Xargo if we stick to
The build script would take care of reading the Do you have an example that wouldn't be covered by linker script customization via a build script? I would love to see that as well but I think managing multiple configurations belongs to some other tool that drives Cargo. Cargo should have some defined / preferred way to let that other tool customize linker arguments / rustflags / etc. If you would like to discuss such configuration management please open issue or continue an existing discussion like this one. Discussing the preferred way to customize linker arguments does belong here. I don't think there's any reason other than nobody has requested it. Cargo.toml already contains project local settings as I defined above. So either the stuff in |
To elaborate a bit more on my previous comment: The "project" in project local setting refers to the first Cargo project that you find by searching for a I suppose it's already possible to create such configuration manager. Most (or all?) of the settings in If your use cases is not supported by simply tweaking a linker script then you probably need something like the configuration manager mentioned above. Specially if e.g. you need to use crate A when building for device X but you need crate B when building for device Y. Here crates A and B could be device crates created using svd2rust and your application has been written in a device agnostic way using some HAL. I think the reason why this configuration is in a hidden file is that Cargo looks for the I think I should be more specific about this particular RFC: Should |
@japaric Cabal recently redid things as http://cabal.readthedocs.io/en/latest/nix-local-build.html#configuring-builds-with-cabal-project and I think it's a great model we should emulate.
Hopefully that mapping + docs make sense, and the philosophy of it all is clear. |
After some thought, I agree with @Ericson2314 - .cargo/config should be uncontrolled. I don't really buy @alexcrichton's argument (I'm an embedded programmer and mucking around with the linker is sort of par for the course), but even if you did, I don't see how using a different config file changes the argument. Either Cargo isn't able to control linking, and we need another tool that can, or it is, and the specification should be in Cargo.toml. |
@Ericson2314 Sorry, the linked documentation didn't help me understand their model; it explained details about the syntax but didn't give a high level overview of why things are structured the way they are. If you know an example where that tool is used in an embedded context where linker scripts and/or object files are passed to the linker that would be helpful. Otherwise I don't see how it adds value to the discussion.
It already is in a sense. Nobody checks .cargo/config into their crates' code because Cargo will ignore it when the crate is built as a dependency. The fact that templates are built today as crates that contain a .cargo/config is an implementation detail. You could (a) write the .cargo/config yourself and it wouldn't be version controlled, or (b) use some scaffolding tool that will build the .cargo/config for you.
It can in several different ways:
Letting each dependency inject custom linker arguments is a can of worms IMO. Linker arguments are order sensitive so your application may build today but not tomorrow when you add a dependency that modifies the dependency graph that causes a reordering the linker arguments. Or perhaps you simply bumped the version of a dependency (from crates.io) and that new version decided to pass a linker argument that it's incompatible with your application. Then you also have problem of having more than one dependency passing a linker script to the linker so your linker ends up with more than one linker scripts in its arguments. None of these problems occur if the only place where linker arguments can be specified is at the top crate, which is what the |
Adding my two cents to the Tock perspective. There are two scenarios for us. Building a kernel for a particular boardCurrently, the world of Cargo makes this unfortunate. A board crate depends on a chip crate, and the board crate is the This is all a bit of a mess considering there is only ever one meaningful target for a board, because it is tightly coupled to a chip and a linker script. For this scenario, it really makes the most sense to specify the linker script and arguments to the linker in either Building Rust userland appsThis is a bit more complicated to comment on, both because it's a more complex scenario and because support for Rust in Tock userland is pretty half-baked so far, so we don't have much experience. In practice, we want to compile for many targets at once (userland apps are portable and we bundle them into multi-arch bundles). However, the linker script does not change between architectures. Here, again, the Moreover, it also doesn't semantically make sense to use In principal, we could try to merge that target into Rust master (as Redux has done, I believe) which would potentially obviate this whole discussion for Tock userland processes. |
@alevy Thanks for the input.
Linkers look for linker scripts in the library search path so if you have a So the
and board crates would only contain the
That custom
In that case each application should not have a copy of the linker script; instead a crate like
Are those different from the |
@japaric Thanks those are useful comments above and beyond this discussion. I'll definitely look into those recommendations.
Most definitely. The LLVM output is totally different. So, now that you mention in, I don't think having a pre-compiled sysroot for |
@japaric I haven't realized that these can be tweaked via environment variables. I think all of my use cases are covered (or at least I can't imagine any right now), and it would be ergonomic enough with some simple cargo-x subcommand wrapper. |
add -Z pre-link-arg{,s} to rustc This PR adds two unstable flags to `rustc`: `-Z pre-link-arg` and `-Z pre-link-args`. These are the counterpart of the existing `-C link-arg{,s}` flags and can be used to pass extra arguments at the *beginning* of the linker invocation, before the Rust object files are passed. I have [started] a discussion on the rust-embedded RFCs repo about settling on a convention for passing extra arguments to the linker and there are two options on discussion: `.cargo/config`'s `target.$T.rustflags` and custom target specification files (`{pre,,post}-link-args` fields). However, to compare these two options on equal footing this `-Z pre-link-arg` feature is required. [started]: rust-embedded/wg#24 Therefore I'm requesting landing this `-Z pre-link-arg` flag as an experimental feature to evaluate these two options. cc @brson r? @alexcrichton
add -Z pre-link-arg{,s} to rustc This PR adds two unstable flags to `rustc`: `-Z pre-link-arg` and `-Z pre-link-args`. These are the counterpart of the existing `-C link-arg{,s}` flags and can be used to pass extra arguments at the *beginning* of the linker invocation, before the Rust object files are passed. I have [started] a discussion on the rust-embedded RFCs repo about settling on a convention for passing extra arguments to the linker and there are two options on discussion: `.cargo/config`'s `target.$T.rustflags` and custom target specification files (`{pre,,post}-link-args` fields). However, to compare these two options on equal footing this `-Z pre-link-arg` feature is required. [started]: rust-embedded/wg#24 Therefore I'm requesting landing this `-Z pre-link-arg` flag as an experimental feature to evaluate these two options. cc @brson r? @alexcrichton
add -Z pre-link-arg{,s} to rustc This PR adds two unstable flags to `rustc`: `-Z pre-link-arg` and `-Z pre-link-args`. These are the counterpart of the existing `-C link-arg{,s}` flags and can be used to pass extra arguments at the *beginning* of the linker invocation, before the Rust object files are passed. I have [started] a discussion on the rust-embedded RFCs repo about settling on a convention for passing extra arguments to the linker and there are two options on discussion: `.cargo/config`'s `target.$T.rustflags` and custom target specification files (`{pre,,post}-link-args` fields). However, to compare these two options on equal footing this `-Z pre-link-arg` feature is required. [started]: rust-embedded/wg#24 Therefore I'm requesting landing this `-Z pre-link-arg` flag as an experimental feature to evaluate these two options. cc @brson r? @alexcrichton
@japaric I agree with the "compose" argument you made above. I use this (sort of) in Here is where I "inject": https://github.com/jamesmunns/teensy3-rs/blob/add-feature-flags/teensy3-sys/build.rs#L115-L123 And here is where I "receive": https://github.com/jamesmunns/teensy3-rs-demo/blob/teensy_3_5_test/.cargo/config#L4-L6 |
Is copying the linker script into |
@SimonSapin Not in the simpler scenarios, but if you want to generate a custom linker script in the build script according to whether Cargo features X and/or Y are enabled then it becomes necessary. I think using $OUT_DIR is also good "hygiene"; if you use -L /path/to/src/dir the linker could untentionally use statically libraries or other linker scripts lying in your source directory instead of the ones you meant to use. With -L$OUT_DIR the linker will only use what you explicitly decided to put there and not what you happened to have in your source directory. |
Just noticed that I was pinged here, but I'm not sure what I can add to the discussion since my project involves a custom userland rather than a strictly embedded context, and so I need Xargo no matter where I put my linker args. |
@FenrirWolf I'd like to know whether you can move all the linker arguments from your target definition to .cargo/config at all. In your particular case you are stuck with Xargo because there's no |
@japaric The real Either way, I tested it out and putting the linker arguments in |
I believe that all items listed here have been addressed in one way or another. I am marking this PR for a cleanup sweep. If you would like this RFC to persist, please add a justification of what it still addresses as of the current date. |
I am closing this PR, please feel free to open a new issue if you would like this discussed further. |
Sumary:
Set a convention for passing custom arguments to the linker when using Cargo for
embedded development. This RFC proposes adopting a project local configuration
file,
.cargo/config
, to pass the arguments.Rendered
My ultimate goal here is to remove the Xargo requirement for embedded, at least
for ARM Cortex-M, development. With the
.cargo/config
we can stick to thebuilt-in targets like
thumbv7m-none-eabi
. Then if we makerust-std
components (
core
+compiler-builtins
) available for those built-in targetsvia
rustup
, we can use normal Cargo to build ARM Cortex-M applications.cc @alevy @FenrirWolf your projects are using custom targets to pass arguments
to the linker. Do you think a built-in target +
.cargo/config
file could meetthe needs of your projects?
cc @jamesmunns @thejpster @whitequark thoughts?