Skip to content

Commit c767eae

Browse files
LuigiPiuccoRahixtones111
committed
Automate the build system with a build.rs
This replaces the AoT processing we did to generate the Rust modules locally. It generates them on the fly at build-time, and only for the selected MCUs. The process is mostly the same, just automated, with the addition of what is described in the next paragraph. Some things became unnecessary though, such as the `modrs.patch` and `Makefile`, and therefore were removed. `form` is no longer run, in order to minimize the number of files and directories. The patches were updated to not have the `_svd` key, since that's now handled by the build script. Those that ended up empty were removed. It also updates our `interrupt` macro, adapting it from a newer iteration of `cortex-m-rt`'s and adding logic to make the vector module unnecessary. It would be hard to generate it correctly for the macros crate, since it compiles before the main one where the build logic is hosted. Instead, we generate a macro `__avr_device_trampoline` in the main crate, and `#[interrupt(chip)]` calls into that giving the MCU name, interrupt name and trampoline item to define. This new macro converts the interrupt's name into a `__vector_N` symbol, which the linker understands as being an interrupt, and changes the function's name to it with `#[export_name = "..."]`. CI code was updated as well. Co-authored-by: Rahix <[email protected]> Co-authored-by: tones111 <[email protected]>
1 parent 7b4cb83 commit c767eae

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+716
-391
lines changed

.github/workflows/ci.yml

Lines changed: 12 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -15,65 +15,39 @@ jobs:
1515
- name: Checkout code
1616
uses: actions/checkout@v4
1717

18+
# Rust Dependencies
1819
- name: Install Stable Rust
1920
uses: actions-rust-lang/setup-rust-toolchain@v1
2021
with:
2122
toolchain: stable
22-
23-
# Rust Dependencies
24-
- name: Cache Cargo installed binaries
25-
uses: actions/cache@v4
26-
id: cache-cargo
27-
with:
28-
path: ~/cargo-bin
29-
key: rust-tools-20250106-001
30-
- name: Install svd2rust
31-
if: steps.cache-cargo.outputs.cache-hit != 'true'
32-
run: cargo install svd2rust --version 0.28.0 --locked
33-
- name: Install cargo-form
34-
if: steps.cache-cargo.outputs.cache-hit != 'true'
35-
run: cargo install form --version 0.8.0 --locked
36-
- name: Install atdf2svd
37-
if: steps.cache-cargo.outputs.cache-hit != 'true'
38-
run: cargo install atdf2svd --version 0.5.0 --locked
39-
- name: Install svdtools
40-
if: steps.cache-cargo.outputs.cache-hit != 'true'
41-
run: cargo install svdtools --version 0.4.0 --locked
42-
- name: Copy tools to cache directory
43-
if: steps.cache-cargo.outputs.cache-hit != 'true'
44-
run: |
45-
mkdir ~/cargo-bin
46-
cp ~/.cargo/bin/svd2rust ~/cargo-bin
47-
cp ~/.cargo/bin/form ~/cargo-bin
48-
cp ~/.cargo/bin/atdf2svd ~/cargo-bin
49-
cp ~/.cargo/bin/svdtools ~/cargo-bin
50-
- name: Put new cargo binary directory into path
51-
run: echo "$HOME/cargo-bin" >> $GITHUB_PATH
52-
5323
- name: Install Nightly Rust
5424
uses: actions-rust-lang/setup-rust-toolchain@v1
5525
with:
5626
toolchain: nightly-2025-03-03
57-
components: rustfmt
27+
components: rustfmt,rust-src
5828

5929
# Actual test run
60-
- name: Generate chip description sources
61-
run: make RUSTUP_TOOLCHAIN=nightly-2025-03-03
6230
- name: Test-compile the crate
63-
run: cargo check --all-features
31+
run: cargo check --target avr-none --all-features -Zbuild-std=core
32+
env:
33+
RUSTFLAGS: "-C target-cpu=atmega328p"
6434

6535
# Package artifacts
6636
- name: Generate a cargo package for the macros
67-
run: cd macros/; cargo package --no-verify --allow-dirty
37+
run: cd macros/; cargo package --target avr-none --no-verify --allow-dirty
38+
env:
39+
RUSTFLAGS: "-C target-cpu=atmega328p"
6840
- name: Generate a cargo package for avr-device
69-
run: cargo package --no-verify --allow-dirty
41+
run: cargo package --target avr-none --no-verify --allow-dirty
42+
env:
43+
RUSTFLAGS: "-C target-cpu=atmega328p"
7044

7145
# Upload artifacts
7246
- uses: actions/upload-artifact@v4
7347
with:
7448
name: avr-device
7549
path: |
76-
svd/
50+
target/avr-none/debug/build/avr-device-*/out/svd/
7751
target/package/avr-device-*.crate
7852
macros/target/package/avr-device-macros-*.crate
7953

.gitignore

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,3 @@
22
/macros/target/
33
**/*.rs.bk
44
Cargo.lock
5-
6-
svd/
7-
.deps/
8-
src/devices/*/*
9-
src/generic.rs
10-
__pycache__/

Cargo.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ include = [
1616
"/LICENSE-*",
1717
"/README.md",
1818
"/build.rs",
19+
"/patch/**/*.yaml",
20+
"/vendor/*.atdf",
21+
"/vendor/LICENSE",
22+
"/examples/**/src/*.rs"
1923
]
2024

2125
[package.metadata.docs.rs]
@@ -94,3 +98,13 @@ critical-section = { version = "1.1.1", optional = true }
9498
path = "macros/"
9599
version = "=0.7.0"
96100
optional = true
101+
102+
[build-dependencies]
103+
svd2rust = "=0.36.1"
104+
svdtools = "=0.4.6"
105+
atdf2svd = "=0.5.0"
106+
prettyplease = "=0.2.32"
107+
svd-rs = "=0.14.12"
108+
yaml-rust2 = "=0.10.1"
109+
syn = { version = "=2.0.100", default-features = false, features = ["full", "parsing"] }
110+
anyhow = "1.0"

Makefile

Lines changed: 0 additions & 80 deletions
This file was deleted.

README.md

Lines changed: 59 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -38,48 +38,67 @@ Via the feature you can select which chip you want the register specifications f
3838
| | | | | `attiny2313a` |
3939

4040
## Build Instructions
41-
The version on `crates.io` is pre-built. The following is only necessary when trying to build this crate from source.
42-
43-
You need to have [atdf2svd][] (= 0.5.0), [svd2rust][] (= 0.28), [form][] (>= 0.8), [rustfmt][](for the *nightly* toolchain) and [svdtools][] (= 0.4.0) installed:
44-
```bash
45-
cargo install atdf2svd --version 0.5.0 --locked
46-
cargo install svd2rust --version 0.28.0 --locked
47-
cargo install form
48-
rustup component add --toolchain nightly rustfmt
49-
cargo install svdtools --version 0.4.0 --locked
50-
```
51-
52-
[atdf2svd]: https://github.com/Rahix/atdf2svd
53-
[svd2rust]: https://github.com/rust-embedded/svd2rust
54-
[form]: https://github.com/djmcgill/form
55-
[rustfmt]: https://github.com/rust-lang/rustfmt
56-
[svdtools]: https://github.com/stm32-rs/svdtools
57-
58-
Next, clone this repo and build the device definitions:
59-
```bash
60-
git clone https://github.com/Rahix/avr-device
61-
cd avr-device
62-
make
63-
# You can build for just one specific chip using
64-
# make atmega32u4
65-
# I suggest building documentation as well
66-
cargo +nightly doc --features <chip> --open
67-
```
68-
69-
## Internals
70-
*avr-device* is generated using [`atdf2svd`](https://github.com/Rahix/atdf2svd) and [`svd2rust`](https://github.com/rust-embedded/svd2rust). The vendor-provided *atdf* files can be found in `vendor/`. The intermediate svd files are patched by `svdpatch.py` (Adapted from [`svdpatch.py`](https://github.com/stm32-rs/stm32-rs/blob/master/scripts/svdpatch.py) in [stm32-rs](https://github.com/stm32-rs/stm32-rs)) with device-dependent patches in `patch/`, mainly to improve undescriptive names and missing descriptions.
41+
The PACs (Peripheral Access Crates, or really modules, in our case) **are not**
42+
checked into git. Rather, we generate them at build time, via an automated
43+
process implemented in [`build.rs`](./build.rs). It takes the ATDF files
44+
Microchip (former Atmel) provides plus some patches of our own making as inputs,
45+
and outputs a module generated from those device descriptions. These inputs
46+
**are** checked-in. The process is similar to what the `*bindgen` crates
47+
provide, just has more steps. So, in short, building should be a matter of
48+
selecting the features and running cargo.
7149

7250
### Adding a new Chip
73-
To add a new chip, download the *atdf* from <http://packs.download.atmel.com/> (or [avr-mcu/packs/](https://github.com/avr-rust/avr-mcu/tree/master/packs)) and place it in `vendor/` ***note: file name may need to be modified***. Be sure to name it like the Rust module that should be generated. Next, you need to integrate it into the base crate and build system. Follow what was done in commit [290613454fbd ("Add basic support for ATmega64")](https://github.com/Rahix/avr-device/commit/290613454fbdc5e4ac98e53deccaf74dafc88963). Please adhere to the alphabetical sorting that is present so far.
74-
75-
Next, you **must** create a `<chipname>.yaml` in `patch/` which has at least the following content:
76-
```yaml
77-
_svd: ../svd/<chipname>.svd
78-
```
79-
80-
If more patches need to be applied (most likely!), they should be added into this file as well. The patching format is documented in the [`svdtools` README](https://github.com/stm32-rs/svdtools#device-and-peripheral-yaml-format). Ideally, try to reuse the exisiting patches in `patch/common/` or `patch/timer/`.
81-
82-
Finally, try building the crate for your MCU with `make <chipname>`.
51+
To add a new chip:
52+
53+
1. Download the ATDF from <http://packs.download.atmel.com/> and place it in
54+
`vendor/`. Be sure to name it like the Rust module that should be generated.
55+
2. Add a feature of the same name to `Cargo.toml` (it should enable
56+
`device-selected`);
57+
3. Add any needed patches to a yaml file with the same name under the `patch`
58+
directory, ideally by including some of the snippets present in
59+
`patch/common` and `patch/timer`; The format is decribed
60+
[here](https://github.com/rust-embedded/svdtools#device-and-peripheral-yaml-format),
61+
but it should not include the top-level `_svd` key, as that's handled by the
62+
build system; If patching is unneeded (it's almost always needed!), the file
63+
can be omitted.
64+
4. Include the module into the tree, in [`devices.rs`](./src/devices.rs),
65+
following the format used by other modules in that file;
66+
5. Update [`lib.rs`](./src/lib.rs) to conditionally `use` the new MCU module,
67+
and add it to the lists of selected and available MCUs in the doc comment.
68+
6. Finally, try building the crate for your MCU with
69+
`cargo build --features <mcu>,rt`.
70+
7. Also check the built documentation for inconsistencies, via
71+
`cargo doc --features <mcu>,rt --open` (it will pop up in your browser).
72+
8. Update this README.md, adding the MCU to the table.
73+
74+
## Internals
75+
Since the vendor does not provide SVDs we can pass to [`svd2rust`][], we
76+
generate one via [`atdf2svd`][]. The sequence is as follows:
77+
78+
1. Check which MCUs are known to the crate
79+
([build.rs:get_available_mcus](./build.rs));
80+
2. Select which to build for by checking enabled features
81+
([build.rs:select_mcu](./build.rs));
82+
3. Generate the Rust module ([build.rs:build_mcu_module](./build.rs));
83+
84+
Substeps are:
85+
1. Register inputs with cargo;
86+
2. Get a temporary directory;
87+
3. Apply `atdf2svd`;
88+
4. If a yaml patch exists, use it via [`svdtools`][] and read the new content
89+
/ else, read the content of the unpatched file to continue;
90+
5. Get the output directory;
91+
6. Apply `svd2rust`;
92+
7. Run [`prettyplease`][] on the module to make it readable in [`docs.rs`][];
93+
4. It will be included from `$OUT_DIR/pac/<mcu>.rs` into the path
94+
`avr_device::devices::<mcu>` (private), and re-exported as
95+
`avr_device::<mcu>` (public).
96+
97+
[`atdf2svd`]: https://github.com/Rahix/atdf2svd
98+
[`svd2rust`]: https://github.com/rust-embedded/svd2rust
99+
[`svdtools`]: https://github.com/rust-embedded/svdtools
100+
[`prettyplease`]: https://github.com/dtolnay/prettyplease
101+
[`docs.rs`]: https://docs.rs/avr-device/latest/avr_device
83102

84103
## License
85104
*avr-device* is licensed under either of

0 commit comments

Comments
 (0)