Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upAdd Cortex-M targets to the compiler + binary releases of `core` #1645
Conversation
japaric
reviewed
Jun 8, 2016
| [compiler-rt] relatively easy. However, adding these targets to the compiler will make the setup | ||
| process simpler (less steps, requires less tooling, etc). | ||
|
|
||
| [extensive documentation]: http://japaric.github.io/copper |
This comment has been minimized.
This comment has been minimized.
japaric
reviewed
Jun 8, 2016
| example, instead of a single `cortex-m4f` target now there would be a `cortex-m4f` target for the | ||
| soft-float CC and a `cortex-m4f-hf` target for the hard-float CC. | ||
|
|
||
| ## Less targets |
This comment has been minimized.
This comment has been minimized.
japaric
Jun 8, 2016
Author
Member
The more I explored this alternative the more I grew convinced that this alternative is actually better than the main proposal. Let's see what others think.
This comment has been minimized.
This comment has been minimized.
JinShil
Sep 15, 2016
•
Contributor
I'm assuming your comment is referring to the "Use the hard-float CC instead of the soft-float one" alternative and not the "Less targets" alternative. If so, I agree. I don't see any reason why all variants cannot be named and require the user unambiguously specify which ABI they wish to compiler for.
This comment has been minimized.
This comment has been minimized.
nrc
added
the
T-dev-tools
label
Jun 8, 2016
This comment has been minimized.
This comment has been minimized.
|
I’ve been meaning to try and get Rust running on a BBC micro:bit (when they become more available for sale) or a Teensy. They both have an ARM Cortex-M. These CPUs seem popular in 32-bit microcontrollers. Implementing this RFC would significantly lower the barrier to entry to Rust for hardware hobbyists. (Think projects that might use C/C++ on an Arduino.) |
This comment has been minimized.
This comment has been minimized.
|
Rust runs on the Teensy already, actually. |
This comment has been minimized.
This comment has been minimized.
|
Yes, but getting to hello world (or blinking LED) is fairly involved: you have to define you own target JSON file, compile |
This comment has been minimized.
This comment has been minimized.
JayKickliter
commented
Jun 8, 2016
For a hobby project, I can live with having to build libcore and maintain my own toolchain. My coworkers, some of whom have never heard of Rust, do mind. I see this as lowering the barrier of entry for using Rust in commercial ARM-based embedded projects. This is the number one barrier I have to adopting Rust at my job. |
alexcrichton
reviewed
Jun 9, 2016
| *freestanding*. A freestanding crate is a crate that doesn't depend on an underlying OS, kernel or | ||
| runtime. Currently, this is the full list of freestanding crates: | ||
|
|
||
| - `alloc` |
This comment has been minimized.
This comment has been minimized.
alexcrichton
Jun 9, 2016
Member
Unfortunately I believe that alloc (and then transitively collections) depends on the libc crate right now, which may not be compile-able for these kinds of targets.
Although I've always wanted to remove the dependency here for this exact reason... We're just not quite poised yet to make that work. Also that being said it doesn't really affect this RFC, just a minor nit
This comment has been minimized.
This comment has been minimized.
japaric
Jun 9, 2016
Author
Member
Hmm, the crates listed here compile just fine for Cortex-M processors. (See Xargo). I haven't (yet) tried to write a program (for these targets) that uses alloc + collections. But, liballoc doesn't seem to contain any undefined reference to a libc symbol (AFAICT):
$ arm-none-eabi-nm -u liballoc-bdc8710db91bbbe1.rlib
alloc-bdc8710db91bbbe1.0.o:
U __aeabi_memcpy
U __aeabi_unwind_cpp_pr0
U __rust_allocate
U __rust_deallocate
U __rust_reallocate
U __rust_reallocate_inplace
U __rust_usable_size
U _ZN4core9panicking5panic17h322e6888d03463ddE
This comment has been minimized.
This comment has been minimized.
FenrirWolf
Jun 14, 2016
__rust_allocate and friends are defined in alloc_system, which itself depends on libc for unix systems at least.
This comment has been minimized.
This comment has been minimized.
japaric
Jun 14, 2016
Author
Member
__rust_allocate and friends are left undefined on purpose. That way one can define custom allocators.
This comment has been minimized.
This comment has been minimized.
|
Thanks for the well written RFC @japaric! I'm pretty excited about making bare-metal development as easy as possible, and it definitely sounds like avoiding compiler-rt and custom targets is a great boon to doing just that right now. My only hesitation on this would be figuring out the names of all these targets (there's quite a few!). I think it's fine to have a bunch, especially if this covers a massive portion of the embedded market. Between the detailed design and your alternative though, things get interesting. So today we actually do somewhat try to encode the CPU into the target itself, for example arm vs armv7 targets as well as i586 vs i686. The main motivation behind that is that dealing with Along those lines I'd be in favor of adding a target-per-CPU that we want to support, but the naming definitely seems like it may get tricky. Do you know if there are canonical names for these targets elsewhere? For example do the gcc toolchains pick reasonable target names or are they all just configured slightly differently? |
This comment has been minimized.
This comment has been minimized.
gcc uses a single triple for all these CPUs:
So one simply links to the appropriate one. Parenthesis: This sounds like a lot of setup steps but embedded C development usually involves an IDE. When using an IDE, there's only a single setup step: you graphically select your microcontroller (this is even more specific than selecting a CPU!) and the IDE takes cares of passing all the right flags to gcc, building and caching libraries, supplying the linker script and starup files, etc. For example, see the demo video here, you can skip to the minute 2.
FWIW, I was looking at the differences between all the CPUs from the POV of LLVM optimzations (you can do this by grepping for "cortex-m" in Rust llvm sources). And, AFAICT, there doesn't seem to be any difference in codegen between the alternative
If targets like
I know you have considered this format before but for binary releases ( |
This comment has been minimized.
This comment has been minimized.
|
Most of this looks relatively uncontroversial to me (and may not need an RFC). The target triples you are specifying look really weird though: From a quick skim the only other major change I see is the definition of a You are overriding |
This comment has been minimized.
This comment has been minimized.
|
Note that thumbv6m has no support for atomic operations at all. This means that liballoc and all crates that depend on it will not work on that architecture. You will only be able to use libcore with it. |
This comment has been minimized.
This comment has been minimized.
|
I love the idea of a The Rust OSDev community has been battling with these issues for a while, and a way to say "here's a |
This comment has been minimized.
This comment has been minimized.
|
Ideally you would just pass a All bare-metal rust projects that I've seen so far seem to simply not bother linking in compiler-rt, and instead just use a bare libcore. While this will usually work, it can cause linker errors if you try to perform some operations that aren't supported natively by LLVM, such as 64-bit division on 32-bit ARM. |
This comment has been minimized.
This comment has been minimized.
|
@Amanieu many OS-devs also need to turn off floating point, which requires a custom patch to libcore, so unless that ends up landing upstream, rustup probably can't do it yet :/ |
This comment has been minimized.
This comment has been minimized.
These "triples" match directly the CPU name. The alternative section has more standard triples:
Well, the
Actually, I think we could just reuse the
Yeah :-/. You get a "undefined reference to In the meantime, one could fork the alloc + collections crates to bubble up the oom as an error and use that. At least until the Allocator trait lands. |
This comment has been minimized.
This comment has been minimized.
Just disable interrupts while performing the operation and restore them afterwards. |
This comment has been minimized.
This comment has been minimized.
I would consider that a bug.
Possibly. We could just consider |
This comment has been minimized.
This comment has been minimized.
|
If there's a sensible implementation and as that symbol is not in compiler-rt, do you think we should provide an implementation of that symbol in
But the |
This comment has been minimized.
This comment has been minimized.
Hm, I guess as defined right now, I'd consider |
This comment has been minimized.
This comment has been minimized.
|
updated the RFC to re-use the existing rust-std component instead of defining a new rust-core component. (I think GitHub is now notifying subscribers when a new commit is pushed, but just in case) |
This comment has been minimized.
This comment has been minimized.
|
I think that the content of all these targets seems reasonable, as does the distribution strategy of 'rust-std' just containing everything it can for that target (which in this case is not std, but oh well in terms of naming). As before, I'm still hesitant on naming, so I wanted to lay out three possible strategies (two of which are in this RFC) to have it all in one place: CPU-basedProposed in this RFC, this is a pretty ergonomic method of specifying the target to the compiler. Tools (including Cargo/rustup) can easily understand this and we'll "just be adding more targets". The downside of this approach, however, is that it's not necessarily scalable as we probably don't want a target-per-cpu. It's also a divergence from today's targets which at least have some semblance of being a triple and conveying information. Triple-basedListed in the alternatives section, this is not as ergonomic than the previous method but aligns better with today's "triples". The introduction of architectures like "thumbv7m" where the actual target_arch is "arm" is somewhat odd though. Not unheard of though as "i586" is mapped to "x86" and "armv7" is mapped to "arm", just a little odd. The downside of this, though, is that we don't have a great vector today to ship as many artifacts as before (they're all target-based, not target + flags based). Another downside is that to be "the most usable" you'll have to pass a bunch of other flags to get code to optimize correctly.
|
This comment has been minimized.
This comment has been minimized.
(Take my opinion with a grain of salt since I haven’t actually tried to do this yet, but) I’d nitpick "not impossible" rather than "usable". The process of figuring out what to write in that JSON file, then fetching/patching/building your own libcore seems very manual and fragile at the moment. Far from Cargo’s goal of making builds reproducible as much as possible. |
This comment has been minimized.
This comment has been minimized.
|
I'm wary of loosening the definition of what we consider 'target triples' further. The problem of being able to specify all these platform variations is related to this thread about config-specific APIs, activating arbitrary cpu features. Also related to std-aware cargo which will need to understand that changing certain features may force a rebuild of std (e.g. when you activate SSE4 you rebuild std with SSE4). It seems to me that we need a concept of a target + some additional configuration. |
brson
referenced this pull request
Jul 12, 2016
Closed
Make Cargo aware of standard library dependencies #1133
This comment has been minimized.
This comment has been minimized.
Exactly what the custom json target specs are. Perhaps we could improve this “additional configuration” in a way which would allow extending other target specifications, but otherwise seems to me like we’re already set on that regard. I do not disagree that the experience of using this “additional configuration” needs improvements, though. |
This comment has been minimized.
This comment has been minimized.
parched
commented
Jul 14, 2016
|
I don't think using CPU based is a good idea as it doesn't scale well and rustc doesn't use it for any of the other architectures. Keeping with standard llvm triples we just need to add
If someone wants to add any CPU specific optimizations then it's the same problem/solution as for the the other architectures which we can deal with separately. |
japaric
referenced this pull request
Sep 29, 2016
Closed
Cargo doesn't work out of the box for Cortex-M micros #9
This comment has been minimized.
This comment has been minimized.
UpdatesI've sent a PR (rust-lang/rust#36874) that adds these target definitions (the A PR (rust-lang/rust#36794) that adds a The question is: Should these Cortex-M targets default to Second question: What should be the default of |
This comment has been minimized.
This comment has been minimized.
|
I don’t really understand what |
This comment has been minimized.
This comment has been minimized.
|
@SimonSapin It means that no dynamic linker is needed to finalize imports (which are usually handled through the many kinds of relocations). |
This comment has been minimized.
This comment has been minimized.
|
Ah never mind, I read @japaric’s last message as recommending |
This comment has been minimized.
This comment has been minimized.
alevy
commented
Oct 2, 2016
|
In principal I'm also 100% in favor of this.
Yes, but that's for a particular relocation model in userspace. For the most part, I have seen scenarios where it makes a ton of sense to use PIC for bare-metal. What about |
This comment has been minimized.
This comment has been minimized.
Yes, absolutely. There are rare cases where one would want to have an unwinder on -M, but many -M targets have less RAM than the unwinder requires for its operation in the first place.
Definitely static. -M targets don't have an MMU, so in general, even if there would be startup code that can relocate them, they would always get relocated into one place (or one of two places, for SoCs that let you map either flash or RAM starting at zero). The complexity of such startup code, or the increase in overall code size cannot be justified. |
This comment has been minimized.
This comment has been minimized.
|
@alevy @whitequark Thanks both for the input! @alevy Sorry, I haven't updated the RFC body but we are leaning towards the alternative that defines 4 targets. Now, about your question, there are two targets you could use for Cortex-M4/7 devices: |
This comment has been minimized.
This comment has been minimized.
|
The target definitions have landed upstream in rust-lang/rust#36874 Thanks everyone for participating in the discussion! We couldn't have arrived at the current target definitions without everyone's input. @alexcrichton what do we do with this RFC? It wasn't needed for just the target definitions (though it was very helpful!) and we are unlikely to do the binary release / rust-core component part. Should I update it to just talk about the new targets and then we can merge it in its updated form or should I just close it? (yes, I'd like to save myself the job of updating this ...) |
This comment has been minimized.
This comment has been minimized.
|
@japaric I'm personally ok with closing this as we tend to not have RFCs for new targets, let's see if this works... @rfcbot fcp close (as @japaric mentioned above) |
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
Oct 5, 2016
•
|
Team member alexcrichton has proposed to close this. The next step is review by the rest of the tagged teams: No concerns currently listed. See this document for info about what commands tagged team members can give me. |
This comment has been minimized.
This comment has been minimized.
|
I think in situations like this we don't need to wait for the bot - either the author or someone from the team could just close the RFC. |
This comment has been minimized.
This comment has been minimized.
alevy
commented
Oct 7, 2016
|
Not sure if this is the right place to keep talking about, apologize if not... I'm trying out this newly merged feature from nightly on Tock. It basically works, which is great, except by default it's missing a few linker arguments that seem generally important. If I don't explicitly add...
I think these should probably be there by default. We don't have a platform with hardware floating point yet, but I tried compiling one of our cortex-m4 targets with the hardware floating point target for heck of it. I wasn't able to. I ended up with a linker error:
I'm not familiar enough with hardware floating point to intuit what the problem is, but if there is, in general, support for getting floating support right by default, I'll dig in further. |
This comment has been minimized.
This comment has been minimized.
IMO you should use rlibc for that, and not have libc a hard dependency on freestanding targets. |
This comment has been minimized.
This comment has been minimized.
That's a gcc multilib thing that tells gcc to pick the libraries that we compiled with soft ABI. arm-none-eabi-gcc ships with several libc/libm/etc. binaries that were compiled with different profiles (soft ABI, hard ABI, no FPU, etc.). That
Hmm, that sounds like you want to use the IMO, linker flags shouldn't be hard coded in a target definition. Linker flags should be supplied by Cargo / rust / user.
You can add all these linker flags using a build script. See this section of the related documentation. You want to use
Cargo can't inject this right now (cf. #1766) but you can add these using a [target.thumbv7m-none-eabi]
rustflags = ["-C", "link-arg=-mfloat-abi=soft"] |
This comment has been minimized.
This comment has been minimized.
@whitequark I think Tock has C components so they have to link to newlib. But, I agree that our targets shouldn't, by default, link to |
This comment has been minimized.
This comment has been minimized.
alevy
commented
Oct 7, 2016
|
@japaric @whitequark there are no C components. rlibc seems like a reasonable fix for
Yes, that's exactly what I did.
My point is that the targets, as they are, cannot actually compile a rust program with floating point operations. In both soft- and hard-floating point cases, some extra linker flags are needed. I agree it's possible to get around this right now with
Are you saying you think the fix is to change Cargo's default for those targets? I'm not very familiar with how Cargo/rustc separate responsibilities, but if Cargo has precedent for doing that, it seems like a perfectly good solution to me. |
This comment has been minimized.
This comment has been minimized.
hmm, if there are no C components. Why are you passing
The only linker flag I need to use with any of these targets is
Those flags would make linking always fail if you don't have newlib installed, which is a totally
|
This comment has been minimized.
This comment has been minimized.
alevy
commented
Oct 7, 2016
Those libraries are necessary for compiler intrinsics required by ARM. The way GCC has decided to divide things up is to leave those intrinsics to newlibic.
|
This comment has been minimized.
This comment has been minimized.
OK, if what you need are compiler intrinsics then what you really want to use, instead of newlib, is "libcompiler-rt.a" which has been renamed to libcompiler-builtins.rlib recently. As there are no binary release of that .rlib for these targets, you'll have to depend on rustc-builtins (possibly with its "c" Cargo feature enabled) to make Cargo compile the intrinsics for you. As for the other symbols that are not compiler intrinsics. Use |
This comment has been minimized.
This comment has been minimized.
If that means what I think it means, it's going to get very confusing especially with the current nomenclature already distinguishing between |
This comment has been minimized.
This comment has been minimized.
michaelwoerister
commented
Oct 18, 2016
|
@rfcbot reviewed |
1 similar comment
This comment has been minimized.
This comment has been minimized.
|
@rfcbot reviewed |
alexcrichton
added
the
final-comment-period
label
Oct 19, 2016
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
Oct 19, 2016
|
All relevant subteam members have reviewed. No concerns remain. |
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
Oct 29, 2016
|
The final comment period is now complete. |
This comment has been minimized.
This comment has been minimized.
|
Alright, thanks again for all the discussion everyone! Closing. |
japaric commentedJun 8, 2016
It's been long known that one can build Rust program for ARM Cortex-M microcontrollers.
This RFC proposes making these cross compilation targets more first-class by adding them to the
compiler and providing binary releases of standard crates like
corefor them.Rendered
cc @rust-lang/tools
cc @hackndev