What I mentioned on the title means we may run a script for cargo run
instead of executing the program itself. I believe this kind of feature, if there are, would somehow being convenience to Rust programmers.
To raise an example, recently I settled in on development on embedded Rust, and made a Rust library. That library is able to search via USB ports for flashers, enumerate all MCUs connected, and finally flash binary programs into them. This simple work is perfect to take place of OpenOCD other than one aspect: I have to wrap, to install my software, and finally type complex commands to do what I need.
As this library also written in Rust, if I could, I may write a program in a file called run.rs
and configure it in Cargo.toml
for any embedded rust applications. Inside that run.rs
I could use
the flasher written, and when I use cargo run
command, binary files are produced before run.rs
is executed, when the binary is flashed instead of executing directly in the operating system. I think this is what run
implies - run on the target MCU chip. It would be far more convenient than having to install my software to do this.
One of my friends suggest another aspect that we may avoid using x.py
file to build rustc
itself by writing a run.rs
script if we could. I don’t know if that’s possible, and if so, it could be awesome.
So is it necessary to customize a run.rs
script, similar to the build.rs
we have?
To who may concern, I expect a run.rs
could contain something like this:
// include library for the run script
use nihao_stm32::{DevicesExt, FlashExt};
use futures::executor::block_on;
// this function is to be executed on your computer, not your chip
fn main() -> std::io::Result<()> {
// include the binary compiled from `src/main.rs` and relevant files
// or we can do this through other run-time approaches
let source = include!("./target/debug/my_program");
// choose the MCU chip via custom library
let mut chip = nihao::devices()?.filter_stm32f103()
.next().expect("have a device plugged in").take()?;
// perform flash and verify operations
block_on!(nihao::Flash::new()
.target(&mut chip)
.erase_all()
.program_entire(&source)
.verify_crc(&source))?;
// methods could block, but that's fine for a `run.rs` script
// the source `src/main.rs` is now executed on the target chip
block_on!(chip.send_continue())?;
Ok(())
} // when this execution is about to finish, it `drop`s all flashers
// and chips in order to free handles and buffers behind them
// the actual running process terminates after `main` having executed.
Or if you want to try inter-chip connections like BLE or serial port, you may wish to flash into two chips without replugging any USB wires. In order to speed-up your development, the flashing methods can even be done asynchronously with non-blocking I/O functions and a proper thread pool or event system to manage them.