-
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] svd2rust
workspace generation
#338
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
# Svd2Rust workspace generation | ||
|
||
- Feature Name: svd2rust_ws_gen | ||
- Start Date: 2019-02-07 | ||
- RFC PR: (leave this empty) | ||
- Rust Issue: (leave this empty) | ||
|
||
|
||
## Summary | ||
|
||
`svd2rust` is a tool to generate Rust code from svd-files. | ||
This allows easier development of embedded code for certain platforms and µ-controllers. | ||
There is a lot of code that is generated, sometimes upwards of a million lines of Rust. | ||
Currently `svd2rust` does this as a single crate, using modules to seperate different peripherals from each other. | ||
|
||
This RFC proposes a change to `svd2rust` to generate a workspace of crates, instead of just a single one. | ||
|
||
## Motivation | ||
|
||
Splitting up the code that is generated allows for ergonomics improvements in several dimensions. | ||
|
||
|
||
1. Users would be able to pick-and-choose crates they want to use, i.e. only supporting certain peripherals | ||
2. Using crates instead of modules allows `rustc` and `cargo` to use multiple codegen units, | ||
making compiles parallel by default, using system resources more effectively. | ||
|
||
Especially decreased compile-times should be considered the primary motivation of this change. | ||
|
||
|
||
## Guide-level explanation | ||
|
||
Changes to `svd2rust` would mostly be under the hood. | ||
As such, interaction with `svd2rust` after the change aren’t much different from how they are now. | ||
|
||
Users can still just pull in a platform crate as a dependency → get all peripherals | ||
|
||
```toml | ||
[project] | ||
# ... | ||
|
||
[dependencies] | ||
acme_mcu8008 = "1.1.0" # Includes _all_ peripherals | ||
``` | ||
|
||
Additionally it’s possible to depend on a specific sub-set of peripherals | ||
|
||
- Pull in common platform crate | ||
- Only get access to specific peripherals | ||
|
||
```toml | ||
[project] | ||
# ... | ||
|
||
[dependencies] | ||
acme_mcu8008_ethernet = "1.1.0" | ||
acme_mcu8008_spi = "1.1.0" | ||
acme_mcu8008_wom = "1.1.0" | ||
``` | ||
|
||
The usage of modules `ethernet`, `spi` and `wom` would then only differ by their top-level import name. | ||
|
||
```rust | ||
use acme_mcu8008::{ethernet, spi, wom}; | ||
|
||
// vs | ||
|
||
use acme_mcu8008_ethernet as ethernet; | ||
use acme_mcu8008_spi as spi; | ||
use acme_mcu8008_wom as wom; | ||
``` | ||
|
||
## Reference-level explanation | ||
|
||
From a high-level perspective there are a few structural changes. | ||
|
||
Each platform has a super-crate, same as now (i.e. `acme_mcu8008`). | ||
Internally it exports (`pub use <peripheral`) all sub-crates. | ||
|
||
All current peripheral modules are turned into sub-crates, | ||
prefixed with the plaform name (i.e. `acme_mcu8008_ethernet`). | ||
|
||
Additionally a `<platform>_commons` crate is generated to avoid circular dependency issues. | ||
This crate would never need to be included by an end-user of the library directly | ||
|
||
## Drawbacks | ||
|
||
A change like this comes with some drawbacks in different domains. | ||
|
||
- Increased complexity of `svd2rust` code generator itself | ||
- How to teach the interaction between the platform super-crate and peripheral-specific crates | ||
- When using `codegen-units=1` in release mode, this could have impact on compile-times | ||
- Possibly lower optimisation potential because of using multiple codegen units | ||
|
||
Especially the last two points would require some proper profiling rather than speculation | ||
to come to a conclusion about how much performance impact (and in what direction) this feature will have. | ||
|
||
|
||
## Rationale and alternatives | ||
|
||
An alternative to generating multiple crates for peripherals was to generate feature flags for each peripheral, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps mention here that both approaches lead to same amount of code being compiled but this proposal has the advantage of parallel compilation of peripheral code. It would be interesting to have numbers on how much parallel compilation helps with overall compile times. |
||
meaning that developers would have to activate feature flags on a HAL crate in order to be able to use certain peripheral modules. | ||
This was partially implemented by [PR #236](https://github.com/rust-embedded/svd2rust/pull/236). | ||
|
||
|
||
## Prior art | ||
|
||
Two partially working implementation for feature gate switching on peripheral modules exist as | ||
[PR #236](https://github.com/rust-embedded/svd2rust/pull/236) and [PR #254](https://github.com/rust-embedded/svd2rust/pull/254). | ||
An unpublished version of `svd2rust` workspace generation exists and highlighted a few issues that have | ||
influenced the design of this RFC. | ||
A tool to handle workspace-synchronised releases has a partially working implementation | ||
[here](https://github.com/spacekookie/cargo-ws-release). | ||
|
||
|
||
## Unresolved questions | ||
|
||
A HAL crate could potentially have dozens of peripheral sub-crates. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the record I have been contacted by the docs.rs team before because svd2rust crates were clogging the build queue so they ended up disabling doc generation for targets other than Linux (normally, I wonder if sequentially building docs for 50 crates w/ 20K LoC each takes longer than building the docs of a single crate w/ 1M LoC. |
||
This will result in a lot more traffic on crates.io, as well as causing a lot more document builds on docs.rs | ||
|
||
We would have to coordinate with both of those teams in order to find a good strategy of how to handle this additional load. | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Presumably today's
Peripherals
singleton struct which contains all peripherals will live in this crate. If one does not want to use that crate to get faster compile times how do they get an instance of sayUSART1
? WillUSART1
gain atake
static constructor whose implementation contains astatic ONCE: bool
to prevent getting several instances of the same peripheral / singleton? That would use more RAM than today's implementation and should be noted.