Skip to content

Commit 9de94b4

Browse files
Rollup merge of #131651 - Patryk27:avr-unknown-unknown, r=tgross35
Create a generic AVR target: avr-none This commit removes the `avr-unknown-gnu-atmega328` target and replaces it with a more generic `avr-none` variant that must be specialized using `-C target-cpu` (e.g. `-C target-cpu=atmega328p`). Seizing the day, I'm adding myself as the maintainer of this target - I've been already fixing the bugs anyway, might as well make it official 🙂 Related discussions: - #131171 - rust-lang/compiler-team#800 try-job: x86_64-gnu-debug
2 parents f04bbc6 + d5128f9 commit 9de94b4

File tree

19 files changed

+160
-60
lines changed

19 files changed

+160
-60
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1990,6 +1990,7 @@ fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor)
19901990
if let Some(args) = sess.target.pre_link_args.get(&flavor) {
19911991
cmd.verbatim_args(args.iter().map(Deref::deref));
19921992
}
1993+
19931994
cmd.verbatim_args(&sess.opts.unstable_opts.pre_link_args);
19941995
}
19951996

compiler/rustc_codegen_ssa/src/back/linker.rs

+12
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ pub(crate) fn get_linker<'a>(
153153
hinted_static: None,
154154
is_ld: cc == Cc::No,
155155
is_gnu: flavor.is_gnu(),
156+
uses_lld: flavor.uses_lld(),
156157
}) as Box<dyn Linker>,
157158
LinkerFlavor::Msvc(..) => Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>,
158159
LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>,
@@ -361,6 +362,7 @@ struct GccLinker<'a> {
361362
// Link as ld
362363
is_ld: bool,
363364
is_gnu: bool,
365+
uses_lld: bool,
364366
}
365367

366368
impl<'a> GccLinker<'a> {
@@ -552,6 +554,7 @@ impl<'a> Linker for GccLinker<'a> {
552554
self.link_args(&["--entry", "_initialize"]);
553555
}
554556
}
557+
555558
// VxWorks compiler driver introduced `--static-crt` flag specifically for rustc,
556559
// it switches linking for libc and similar system libraries to static without using
557560
// any `#[link]` attributes in the `libc` crate, see #72782 for details.
@@ -567,6 +570,15 @@ impl<'a> Linker for GccLinker<'a> {
567570
{
568571
self.cc_arg("--static-crt");
569572
}
573+
574+
// avr-none doesn't have default ISA, users must specify which specific
575+
// CPU (well, microcontroller) they are targetting using `-Ctarget-cpu`.
576+
//
577+
// Currently this makes sense only when using avr-gcc as a linker, since
578+
// it brings a couple of hand-written important intrinsics from libgcc.
579+
if self.sess.target.arch == "avr" && !self.uses_lld {
580+
self.verbatim_arg(format!("-mmcu={}", self.target_cpu));
581+
}
570582
}
571583

572584
fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool) {

compiler/rustc_target/src/spec/base/avr_gnu.rs renamed to compiler/rustc_target/src/spec/base/avr.rs

-40
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,5 @@
11
use object::elf;
22

3-
use crate::spec::{Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions};
4-
5-
/// A base target for AVR devices using the GNU toolchain.
6-
///
7-
/// Requires GNU avr-gcc and avr-binutils on the host system.
8-
/// FIXME: Remove the second parameter when const string concatenation is possible.
9-
pub(crate) fn target(target_cpu: &'static str, mmcu: &'static str) -> Target {
10-
Target {
11-
arch: "avr".into(),
12-
metadata: crate::spec::TargetMetadata {
13-
description: None,
14-
tier: None,
15-
host_tools: None,
16-
std: None,
17-
},
18-
data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".into(),
19-
llvm_target: "avr-unknown-unknown".into(),
20-
pointer_width: 16,
21-
options: TargetOptions {
22-
env: "gnu".into(),
23-
24-
c_int_width: "16".into(),
25-
cpu: target_cpu.into(),
26-
exe_suffix: ".elf".into(),
27-
28-
linker: Some("avr-gcc".into()),
29-
eh_frame_header: false,
30-
pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[mmcu]),
31-
late_link_args: TargetOptions::link_args(
32-
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
33-
&["-lgcc"],
34-
),
35-
max_atomic_width: Some(16),
36-
atomic_cas: false,
37-
relocation_model: RelocModel::Static,
38-
..TargetOptions::default()
39-
},
40-
}
41-
}
42-
433
/// Resolve the value of the EF_AVR_ARCH field for AVR ELF files, given the
444
/// name of the target CPU / MCU.
455
///

compiler/rustc_target/src/spec/base/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pub(crate) mod aix;
22
pub(crate) mod android;
33
pub(crate) mod apple;
4-
pub(crate) mod avr_gnu;
4+
pub(crate) mod avr;
55
pub(crate) mod bpf;
66
pub(crate) mod cygwin;
77
pub(crate) mod dragonfly;

compiler/rustc_target/src/spec/mod.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ pub mod crt_objects;
6060
mod base;
6161
mod json;
6262

63-
pub use base::avr_gnu::ef_avr_arch;
63+
pub use base::avr::ef_avr_arch;
6464

6565
/// Linker is called through a C/C++ compiler.
6666
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
@@ -1797,7 +1797,7 @@ supported_targets! {
17971797
("riscv64gc-unknown-fuchsia", riscv64gc_unknown_fuchsia),
17981798
("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia),
17991799

1800-
("avr-unknown-gnu-atmega328", avr_unknown_gnu_atmega328),
1800+
("avr-none", avr_none),
18011801

18021802
("x86_64-unknown-l4re-uclibc", x86_64_unknown_l4re_uclibc),
18031803

@@ -3062,7 +3062,10 @@ impl Target {
30623062
&self.post_link_args,
30633063
] {
30643064
for (&flavor, flavor_args) in args {
3065-
check!(!flavor_args.is_empty(), "linker flavor args must not be empty");
3065+
check!(
3066+
!flavor_args.is_empty() || self.arch == "avr",
3067+
"linker flavor args must not be empty"
3068+
);
30663069
// Check that flavors mentioned in link args are compatible with the default flavor.
30673070
match self.linker_flavor {
30683071
LinkerFlavor::Gnu(..) => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use crate::spec::{Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions};
2+
3+
pub(crate) fn target() -> Target {
4+
Target {
5+
arch: "avr".into(),
6+
metadata: crate::spec::TargetMetadata {
7+
description: None,
8+
tier: None,
9+
host_tools: None,
10+
std: None,
11+
},
12+
data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".into(),
13+
llvm_target: "avr-unknown-unknown".into(),
14+
pointer_width: 16,
15+
options: TargetOptions {
16+
c_int_width: "16".into(),
17+
exe_suffix: ".elf".into(),
18+
linker: Some("avr-gcc".into()),
19+
eh_frame_header: false,
20+
pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[]),
21+
late_link_args: TargetOptions::link_args(
22+
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
23+
&["-lgcc"],
24+
),
25+
max_atomic_width: Some(16),
26+
atomic_cas: false,
27+
relocation_model: RelocModel::Static,
28+
need_explicit_cpu: true,
29+
..TargetOptions::default()
30+
},
31+
}
32+
}

compiler/rustc_target/src/spec/targets/avr_unknown_gnu_atmega328.rs

-5
This file was deleted.

src/doc/rustc/src/platform-support.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ target | std | host | notes
301301
[`armv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * | | Bare Armv8-R, hardfloat
302302
[`armv7a-nuttx-eabi`](platform-support/nuttx.md) | ✓ | | ARMv7-A with NuttX
303303
[`armv7a-nuttx-eabihf`](platform-support/nuttx.md) | ✓ | | ARMv7-A with NuttX, hardfloat
304-
`avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core`
304+
`avr-none` | * | | AVR; requires `-Zbuild-std=core` and `-Ctarget-cpu=...`
305305
`bpfeb-unknown-none` | * | | BPF (big endian)
306306
`bpfel-unknown-none` | * | | BPF (little endian)
307307
`csky-unknown-linux-gnuabiv2` | ✓ | | C-SKY abiv2 Linux (little endian)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# `avr-none`
2+
3+
Series of microcontrollers from Atmel: ATmega8, ATmega328p etc.
4+
5+
**Tier: 3**
6+
7+
## Target maintainers
8+
9+
- [Patryk Wychowaniec](https://github.com/Patryk27) <[email protected]>
10+
11+
## Requirements
12+
13+
This target is only cross-compiled; x86-64 Linux, x86-64 macOS and aarch64 macOS
14+
hosts are confirmed to work, but in principle any machine able to run rustc and
15+
avr-gcc should be good.
16+
17+
Compiling for this target requires `avr-gcc` installed, because a couple of
18+
intrinsics (like 32-bit multiplication) rely on [`libgcc`](https://github.com/gcc-mirror/gcc/blob/3269a722b7a03613e9c4e2862bc5088c4a17cc11/libgcc/config/avr/lib1funcs.S)
19+
and can't be provided through `compiler-builtins` yet. This is a limitation that
20+
[we hope to lift in the future](https://github.com/rust-lang/compiler-builtins/issues/711).
21+
22+
You'll also need to setup the `.cargo/config` file - see below for details.
23+
24+
## Building the target
25+
26+
Rust comes with AVR support enabled, you don't have to rebuild the compiler.
27+
28+
## Building Rust programs
29+
30+
Install `avr-gcc`:
31+
32+
```console
33+
# Ubuntu:
34+
$ sudo apt-get install gcc-avr
35+
36+
# Mac:
37+
$ brew tap osx-cross/avr && brew install avr-gcc
38+
39+
# NixOS (takes a couple of minutes, since it's not provided through Hydra):
40+
$ nix shell nixpkgs#pkgsCross.avr.buildPackages.gcc11
41+
```
42+
43+
... setup `.cargo/config` for your project:
44+
45+
```toml
46+
[build]
47+
target = "avr-none"
48+
rustflags = ["-C", "target-cpu=atmega328p"]
49+
50+
[unstable]
51+
build-std = ["core"]
52+
```
53+
54+
... and then simply run:
55+
56+
```console
57+
$ cargo build --release
58+
```
59+
60+
The final binary will be placed into
61+
`./target/avr-none/release/your-project.elf`.
62+
63+
Note that since AVRs have rather small amounts of registers, ROM and RAM, it's
64+
recommended to always use `--release` to avoid running out of space.
65+
66+
Also, please note that specifying `-C target-cpu` is required - here's a list of
67+
the possible variants:
68+
69+
https://github.com/llvm/llvm-project/blob/093d4db2f3c874d4683fb01194b00dbb20e5c713/clang/lib/Basic/Targets/AVR.cpp#L32
70+
71+
## Testing
72+
73+
You can use [`simavr`](https://github.com/buserror/simavr) to emulate the
74+
resulting firmware on your machine:
75+
76+
```console
77+
$ simavr -m atmega328p ./target/avr-none/release/your-project.elf
78+
```
79+
80+
Alternatively, if you want to write a couple of actual `#[test]`s, you can use
81+
[`avr-tester`](https://github.com/Patryk27/avr-tester).

src/tools/compiletest/src/header/tests.rs

+3
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,10 @@ fn profiler_runtime() {
465465
#[test]
466466
fn asm_support() {
467467
let asms = [
468+
#[cfg(bootstrap)]
468469
("avr-unknown-gnu-atmega328", false),
470+
#[cfg(not(bootstrap))]
471+
("avr-none", false),
469472
("i686-unknown-netbsd", true),
470473
("riscv32gc-unknown-linux-gnu", true),
471474
("riscv64imac-unknown-none-elf", true),

src/tools/run-make-support/src/external_deps/rustc.rs

+7
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,13 @@ impl Rustc {
253253
self
254254
}
255255

256+
/// Specify the target CPU.
257+
pub fn target_cpu<S: AsRef<str>>(&mut self, target_cpu: S) -> &mut Self {
258+
let target_cpu = target_cpu.as_ref();
259+
self.cmd.arg(format!("-Ctarget-cpu={target_cpu}"));
260+
self
261+
}
262+
256263
/// Specify the crate type.
257264
pub fn crate_type(&mut self, crate_type: &str) -> &mut Self {
258265
self.cmd.arg("--crate-type");

tests/assembly/asm/avr-modifiers.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@ add-core-stubs
22
//@ assembly-output: emit-asm
3-
//@ compile-flags: --target avr-unknown-gnu-atmega328
3+
//@ compile-flags: --target avr-none -C target-cpu=atmega328p
44
//@ needs-llvm-components: avr
55

66
#![feature(no_core, asm_experimental_arch)]

tests/assembly/asm/avr-types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@ add-core-stubs
22
//@ assembly-output: emit-asm
3-
//@ compile-flags: --target avr-unknown-gnu-atmega328
3+
//@ compile-flags: --target avr-none -C target-cpu=atmega328p
44
//@ needs-llvm-components: avr
55

66
#![feature(no_core, asm_experimental_arch)]

tests/assembly/targets/targets-pe.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
//@ revisions: arm64ec_pc_windows_msvc
1616
//@ [arm64ec_pc_windows_msvc] compile-flags: --target arm64ec-pc-windows-msvc
1717
//@ [arm64ec_pc_windows_msvc] needs-llvm-components: aarch64
18-
//@ revisions: avr_unknown_gnu_atmega328
19-
//@ [avr_unknown_gnu_atmega328] compile-flags: --target avr-unknown-gnu-atmega328
20-
//@ [avr_unknown_gnu_atmega328] needs-llvm-components: avr
18+
//@ revisions: avr_none
19+
//@ [avr_none] compile-flags: --target avr-none -C target-cpu=atmega328p
20+
//@ [avr_none] needs-llvm-components: avr
2121
//@ revisions: bpfeb_unknown_none
2222
//@ [bpfeb_unknown_none] compile-flags: --target bpfeb-unknown-none
2323
//@ [bpfeb_unknown_none] needs-llvm-components: bpf

tests/codegen/asm/avr-clobbers.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@ add-core-stubs
22
//@ assembly-output: emit-asm
3-
//@ compile-flags: --target avr-unknown-gnu-atmega328
3+
//@ compile-flags: --target avr-none -C target-cpu=atmega328p
44
//@ needs-llvm-components: avr
55

66
#![crate_type = "rlib"]

tests/codegen/avr/avr-func-addrspace.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ compile-flags: -Copt-level=3 --target=avr-unknown-gnu-atmega328 --crate-type=rlib -C panic=abort
1+
//@ compile-flags: -Copt-level=3 --target=avr-none -C target-cpu=atmega328p --crate-type=rlib -C panic=abort
22
//@ needs-llvm-components: avr
33

44
// This test validates that function pointers can be stored in global variables

tests/run-make/avr-rjmp-offset/rmake.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ fn main() {
2222
.input("avr-rjmp-offsets.rs")
2323
.opt_level("s")
2424
.panic("abort")
25-
.target("avr-unknown-gnu-atmega328")
25+
.target("avr-none")
26+
// rust-lld has some troubles understanding the -mmcu flag, so for the
27+
// time being let's tell rustc to emit binary that's compatible with the
28+
// target CPU that lld defaults to, i.e. just `avr` (that's simply the
29+
// minimal common instruction set across all AVRs)
30+
.target_cpu("avr")
2631
// normally one links with `avr-gcc`, but this is not available in CI,
2732
// hence this test diverges from the default behavior to enable linking
2833
// at all, which is necessary for the test (to resolve the labels). To
@@ -49,6 +54,7 @@ fn main() {
4954
// of the Rust compiler did produce a label `rjmp .-4` (misses the first
5055
// instruction in the loop).
5156
assert!(disassembly.contains("<main>"), "no main function in output");
57+
5258
disassembly
5359
.trim()
5460
.lines()

tests/ui/feature-gates/feature-gate-abi-avr-interrupt.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//@ needs-llvm-components: avr
2-
//@ compile-flags: --target=avr-unknown-gnu-atmega328 --crate-type=rlib
2+
//@ compile-flags: --target=avr-none -C target-cpu=atmega328p --crate-type=rlib
33
#![no_core]
44
#![feature(no_core, lang_items)]
55
#[lang="sized"]

tests/ui/repr/16-bit-repr-c-enum.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//@ revisions: avr msp430
33
//
44
//@ [avr] needs-llvm-components: avr
5-
//@ [avr] compile-flags: --target=avr-unknown-gnu-atmega328 --crate-type=rlib
5+
//@ [avr] compile-flags: --target=avr-none -C target-cpu=atmega328p --crate-type=rlib
66
//@ [msp430] needs-llvm-components: msp430
77
//@ [msp430] compile-flags: --target=msp430-none-elf --crate-type=rlib
88
#![feature(no_core, lang_items, intrinsics, staged_api, rustc_attrs)]

0 commit comments

Comments
 (0)