Skip to content

Commit b911d36

Browse files
authored
Minimal buildsystem (#3)
1 parent 57dbe78 commit b911d36

File tree

15 files changed

+926
-1
lines changed

15 files changed

+926
-1
lines changed

.github/workflows/rust_all.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ jobs:
2828
run: |
2929
rustup component add llvm-tools-preview
3030
rustup target add thumbv7em-none-eabihf
31-
cargo install cbindgen
3231
cargo install cargo-binutils
32+
cargo install cargo-make
33+
cargo install cbindgen
3334
3435
- name: Environment info
3536
run: |
@@ -47,3 +48,10 @@ jobs:
4748
cargo size
4849
cargo build --release
4950
cargo size --release
51+
52+
- name: Minimal buildsystem
53+
working-directory: ${{github.workspace}}/minimal_buildsystem
54+
run: |
55+
cargo make ci_debug
56+
cargo make ci_release
57+
cargo doc

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,18 @@
11
# lowlevel_rust
2+
23
Rust on microcontrollers
4+
5+
# Projects
6+
7+
- Minimal blinky
8+
- Barebones blinky example i.e linker script to main
9+
- Minimal buildsystem
10+
- Initial [cargo-make](https://github.com/sagiegurari/cargo-make) framework to have configurable build options i.e extending `cargo`
11+
12+
# Roadmap
13+
14+
## RTOS
15+
16+
## Debugging
17+
18+
## Tooling
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
[target.thumbv7em-none-eabihf]
2+
# uncomment this to make `cargo run` execute programs on QEMU
3+
# runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
4+
5+
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
6+
# uncomment ONE of these three option to make `cargo run` start a GDB session
7+
# which option to pick depends on your system
8+
# runner = "arm-none-eabi-gdb -q -x openocd.gdb"
9+
# runner = "gdb-multiarch -q -x openocd.gdb"
10+
# runner = "gdb -q -x openocd.gdb"
11+
rustflags = [
12+
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
13+
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
14+
# "-C", "link-arg=--nmagic",
15+
16+
# LLD (shipped with the Rust toolchain) is used as the default linker
17+
# "-C", "link-arg=-Tgcc_arm.ld",
18+
19+
# Generate a .map file
20+
# "-C", "link-args=-Map=minimal_buildsystem.map",
21+
22+
# if you run into problems with LLD switch to the GNU linker by commenting out
23+
# this line
24+
"-C", "linker=arm-none-eabi-ld",
25+
26+
# if you need to link to pre-compiled C libraries provided by a C toolchain
27+
# use GCC as the linker by commenting out both lines above and then
28+
# uncommenting the three lines below
29+
"-C", "linker=arm-none-eabi-gcc",
30+
"-C", "link-arg=-Wl,-Tgcc_arm.ld",
31+
"-C", "link-arg=-Wl,-Map,minimal_buildsystem.map",
32+
"-C", "link-arg=-nostartfiles",
33+
]
34+
35+
[build]
36+
# Pick ONE of these compilation targets
37+
# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
38+
# target = "thumbv7m-none-eabi" # Cortex-M3
39+
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
40+
target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
41+
# target = "thumbv8m.base-none-eabi" # Cortex-M23
42+
# target = "thumbv8m.main-none-eabi" # Cortex-M33 (no FPU)
43+
# target = "thumbv8m.main-none-eabihf" # Cortex-M33 (with FPU)

minimal_buildsystem/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Files
2+
*.map
3+
.vscode/.cortex-debug.*
4+
5+
# Folders
6+
target
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"configurations": [
3+
{
4+
"cwd": "${workspaceFolder}",
5+
"executable": "target/thumbv7em-none-eabihf/debug/minimal_buildsystem",
6+
"configFiles": [
7+
"stm32l4discovery.cfg"
8+
],
9+
"postLaunchCommands": [
10+
"load",
11+
"monitor arm semihosting enable",
12+
],
13+
"name": "Rust Debug",
14+
"request": "launch",
15+
"type": "cortex-debug",
16+
"servertype": "openocd"
17+
},
18+
{
19+
"cwd": "${workspaceFolder}",
20+
"executable": "target/thumbv7em-none-eabihf/release/minimal_buildsystem",
21+
"configFiles": [
22+
"stm32l4discovery.cfg"
23+
],
24+
"postLaunchCommands": [
25+
"load",
26+
"monitor arm semihosting enable",
27+
],
28+
"name": "Rust Release",
29+
"request": "launch",
30+
"type": "cortex-debug",
31+
"servertype": "openocd"
32+
}
33+
]
34+
}

minimal_buildsystem/Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "minimal_buildsystem"
3+
version = "0.1.0"
4+
authors = ["Niket Naidu <coder137@gmail.com>"]
5+
edition = "2021"
6+
readme = "README.md"
7+
8+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
9+
10+
[dependencies]

minimal_buildsystem/Makefile.toml

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Duckscript is used here to convert \ to / for binary output path
2+
[tasks.build_debug]
3+
script_runner = "@duckscript"
4+
script = '''
5+
output = set ${CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY}/debug/${CARGO_MAKE_CRATE_NAME}
6+
output = replace ${output} \\ /
7+
set_env OUTPUT ${output}
8+
exec cargo build
9+
'''
10+
11+
# Duckscript is used here to convert \ to / for binary output path
12+
[tasks.build_release]
13+
script_runner = "@duckscript"
14+
script = '''
15+
output = set ${CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY}/release/${CARGO_MAKE_CRATE_NAME}
16+
output = replace ${output} \\ /
17+
set_env OUTPUT ${output}
18+
exec cargo build --release
19+
'''
20+
21+
[tasks.test]
22+
command = "cargo"
23+
args = ["test", "--target", "${CARGO_MAKE_RUST_TARGET_TRIPLE}"]
24+
25+
[tasks.flash_debug]
26+
script_runner = "@shell"
27+
script = '''
28+
openocd -f board/stm32l4discovery.cfg -c "program ${OUTPUT} verify reset exit"
29+
'''
30+
dependencies = ["build_debug"]
31+
32+
[tasks.ci_debug]
33+
dependencies = [
34+
"build_debug",
35+
"test",
36+
"objcopy_to_binary",
37+
"objcopy_to_hex",
38+
"objdump",
39+
"size",
40+
]
41+
42+
[tasks.ci_release]
43+
dependencies = [
44+
"build_release",
45+
"test",
46+
"objcopy_to_binary",
47+
"objcopy_to_hex",
48+
"objdump",
49+
"size",
50+
]
51+
52+
# Private Tasks
53+
54+
# Requires
55+
# arm-none-eabi-size executable (ARM GCC toolchain)
56+
# OUTPUT env variable (Set by build_*)
57+
[tasks.size]
58+
private = true
59+
command = "arm-none-eabi-size"
60+
args = ["${OUTPUT}"]
61+
62+
# arm-none-eabi-objcopy executable (ARM GCC toolchain)
63+
# OUTPUT env variable (Set by build_*)
64+
[tasks.objcopy_to_binary]
65+
private = true
66+
command = "arm-none-eabi-objcopy"
67+
args = ["-O", "binary", "${OUTPUT}", "${OUTPUT}.bin"]
68+
69+
# arm-none-eabi-objcopy executable (ARM GCC toolchain)
70+
# OUTPUT env variable (Set by build_*)
71+
[tasks.objcopy_to_hex]
72+
private = true
73+
command = "arm-none-eabi-objcopy"
74+
args = ["-O", "ihex", "${OUTPUT}", "${OUTPUT}.hex"]
75+
76+
# arm-none-eabi-objdump executable (ARM GCC toolchain)
77+
# OUTPUT env variable (Set by build_*)
78+
[tasks.objdump]
79+
private = true
80+
script_runner = "@shell"
81+
script = '''
82+
arm-none-eabi-objdump --source --all-headers --demangle --line-numbers --wide ${OUTPUT} > ${OUTPUT}.lst
83+
'''

minimal_buildsystem/README.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
- [Minimal Buildsystem](#minimal-buildsystem)
2+
- [Links](#links)
3+
- [Pre-requisites](#pre-requisites)
4+
- [Build system for Rust](#build-system-for-rust)
5+
- [\[build\_debug | build\_release\]](#build_debug--build_release)
6+
- [test](#test)
7+
- [flash\_debug](#flash_debug)
8+
- [\[ci\_debug | ci\_release\]](#ci_debug--ci_release)
9+
- [doc](#doc)
10+
11+
# Minimal Buildsystem
12+
13+
This code has been tested on
14+
15+
- B-L475-IOT01A board (STM32L475VGT6 ARM Cortex M4 CPU with FPU)
16+
17+
## Links
18+
19+
- [Cargo binutils](https://github.com/rust-embedded/cargo-binutils)
20+
- [Embedded Rust book](https://doc.rust-lang.org/stable/embedded-book/)
21+
- [Lowlevel Embedded Rust book](https://docs.rust-embedded.org/embedonomicon/)
22+
23+
## Pre-requisites
24+
25+
- Pre-requisites from `minimal_blinky`
26+
- cargo install cargo-make
27+
28+
## Build system for Rust
29+
30+
Cargo make is used to build, run and deploy various aspects of this project.
31+
This is because we need configurations for
32+
33+
- Building microcontroller (on-target) code for different supported architectures and toolchains.
34+
- Pre-processing (.c to .rs conversion, code generation)
35+
- Building (convert to .elf)
36+
- Post-processing (.elf size, .bin and .hex generation, flashing after build, CI run)
37+
- Unit-testing functionality (off-target) using host toolchain
38+
- Documentation generation
39+
40+
Commands can be run using
41+
42+
```bash
43+
cargo make [command]
44+
```
45+
46+
### [build_debug | build_release]
47+
48+
Makes a debug or release build of the project using the microcontroller target
49+
50+
See `.cargo/config.toml`, **build.target** field
51+
52+
### test
53+
54+
Make a build of the project using the default system host toolchain and target
55+
56+
Run `rustup default` to see your system host toolchain
57+
Run `rustup target list` to see the system host target installed for your toolchain
58+
59+
### flash_debug
60+
61+
Uses openocd to flash your generated `/debug/*.elf` file to the STM32 microcontroller
62+
63+
### [ci_debug | ci_release]
64+
65+
Single command that does the following in order
66+
67+
- Build on-target code [debug | release]
68+
- Size of on-target code
69+
- Executes unit-tests and mocks using an off-target build
70+
- Convert `*.elf` to `*.bin`
71+
- Convert `*.elf` to `*.hex`
72+
- Dump `*.elf` symbols to `*.lst`
73+
74+
### doc
75+
76+
This is not added to `cargo make`
77+
78+
Invoke cargo doc from the root

minimal_buildsystem/build.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//! This build script copies the `memory.x` file from the crate root into
2+
//! a directory where the linker can always find it at build time.
3+
//! For many projects this is optional, as the linker always searches the
4+
//! project root directory -- wherever `Cargo.toml` is. However, if you
5+
//! are using a workspace or have a more complicated build setup, this
6+
//! build script becomes required. Additionally, by requesting that
7+
//! Cargo re-run the build script whenever `memory.x` is changed,
8+
//! updating `memory.x` ensures a rebuild of the application with the
9+
//! new memory settings.
10+
11+
use std::env;
12+
use std::path::PathBuf;
13+
14+
fn reference() {
15+
let out: &PathBuf = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
16+
println!("{}", out.display());
17+
}
18+
19+
fn linker_script() {
20+
println!("cargo:rerun-if-changed=gcc_arm.ld");
21+
}
22+
23+
fn main() {
24+
reference();
25+
linker_script();
26+
}

0 commit comments

Comments
 (0)