Skip to content
This repository was archived by the owner on Aug 9, 2022. It is now read-only.

Use cargo rather make to do the generation from the svd files #30

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
**/*.rs.bk
Cargo.lock
svd/esp32.svd
src/
svd/esp32.base.svd.patched
svd/esp32.svd.rs
.cargo/config
11 changes: 10 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,13 @@ license = "MIT OR Apache-2.0"

[dependencies]
bare-metal = "0.2"
vcell = "0.1"
vcell = "0.1"

[build-dependencies]
form = "^0"
svd2rust = "^0"
fmt = "^0"
log = "^0"
env_logger = "^0"
failure = "^0"
ex = "^0"
131 changes: 131 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// OUTPUT=esp32.svd
// BASE=esp32.base.svd
//
// all: clean patch generate form fmt build
//
// clean:
// rm -rf src/
//
// patch:
// rm -f svd/$(OUTPUT)
// svd patch svd/patches/esp32.yaml
// mv svd/$(BASE).patched svd/$(OUTPUT)
//
// generate:
// svd2rust --target none -i svd/$(OUTPUT)
//
// form:
// form -i lib.rs -o src/
// rm lib.rs
//
// fmt:
// cargo fmt
//
// build:
// cargo clean
// cargo build
use ex::{fs, fs::File};
use std::{env,
fmt::Write,
io::{Read, Write as IoWrite},
path::Path,
process::Command};

fn svd2rust(svd_path: &str) -> ex::io::Result<String> {
let mut svd_xml = String::new();
File::open(svd_path)?.read_to_string(&mut svd_xml).unwrap();
let generated = svd2rust::generate(svd_xml.as_str(), svd2rust::Target::None, false).unwrap();

let mut file = File::create("svd/esp32.svd.rs").expect("Couldn't create lib.rs file");
let mut data = String::new();
write!(data, "{}", generated.lib_rs).expect("Could not output code");

let newlined = data.replace("] ", "]\n");
file.write_all(newlined.as_ref()).expect("Could not write code to lib.rs");

Ok(newlined)
}

// Example custom build script.
fn main() -> ex::io::Result<()> {
println!("BEGIN generate_bindings_from_build_rs: {:?}", std::env::current_exe().unwrap());
if env::var("CARGO_MANIFEST_DIR").is_err() {
env::set_var("CARGO_MANIFEST_DIR", env::current_dir().unwrap().to_str().unwrap());
}
let base_dir: String = env::var("CARGO_MANIFEST_DIR").unwrap();

// Tell Cargo that if the given file changes, to rerun this build script.
let svd = format!("{}/svd/esp32.base.svd", base_dir);
let svd_patched = format!("{}/svd/esp32.base.svd.patched", base_dir);
let yaml = format!("{}/svd/patches/esp32.yaml", base_dir);
let svd_final = format!("{}/svd/esp32.svd", base_dir);
let generate_file_sample = format!("{}/src/gpio.rs", base_dir);
let lib_rs = format!("{}/src/lib.rs", base_dir);

println!("cargo:rerun-if-changed={}", svd);
println!("cargo:rerun-if-changed={}", svd_patched);
println!("cargo:rerun-if-changed={}", yaml);
println!("cargo:rerun-if-changed={}", svd_final);
println!("cargo:rerun-if-changed=build.rs");

println!("cargo:rerun-if-changed={}", svd);

if Path::new(generate_file_sample.as_str()).exists() {
let in_m = fs::metadata("svd/esp32.base.svd")?;
let out_m = fs::metadata(generate_file_sample)?;
if in_m.modified()? < out_m.modified()? {
println!("src/* files newer than {}, skipping any regeneration.", svd);
return Ok(());
}
}

// Delete the output if it exists.
if Path::new(&svd_patched).exists() {
fs::remove_file(&svd_patched)?;
}

println!("Patching SVD {} -> {}", svd, svd_final);
// generate patched file.
Command::new("svd").arg("patch").arg(yaml)
.output()
.expect("failed to run svd tool. This is a python tool that should have been installed via: pip3 install --upgrade --user svdtools");
fs::copy(&svd_patched, &svd_final)?;

// println!("Generating rust source from AVD");
let rs = svd2rust(&svd_final)?;

// convert it into the rust form.
println!("Converting sources into commonly accepted rust format.");
if form::create_directory_structure("src", rs).is_err() {
println!("Unable to convert to common rust format.");
}

println!("Formatting rust source files.");
Command::new("cargo").arg("fmt").output().expect("failed to run cargo format");

println!("Cleaning up some lint warnings that are no longer supported in generated cdde.");
clean_up_some_lint_warnings_in_the_generated_code(&lib_rs)?;

// Tell git to ignore changes to the generated src/lib.rs
Command::new("git").arg("update-index")
.arg("--assume-unchanged")
.arg("src/lib.rs")
.output()
.expect("failed to suppress change notification on generated lib.rs");

println!("All done.");
Ok(())
}

fn clean_up_some_lint_warnings_in_the_generated_code(lib_rs: &String) -> ex::io::Result<()> {
let mut lib_src = String::new();
File::open(&lib_rs)?.read_to_string(&mut lib_src).unwrap();
let cleaned_some_invalid_lints = lib_src.replace("#![deny(legacy_directory_ownership)]", "//#![deny(legacy_directory_ownership)]")
.replace("#![deny(plugin_as_library)]", "//#![deny(plugin_as_library)]")
.replace("#![deny(safe_extern_statics)]", "//#![deny(safe_extern_statics)]")
.replace("#![deny(unions_with_drop_fields)]", "//#![deny(unions_with_drop_fields)]");

File::create(&lib_rs)?.write_all(cleaned_some_invalid_lints.as_bytes()).unwrap();

Ok(())
}
25 changes: 25 additions & 0 deletions src/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*.rs
/hinf
/i2c
/i2s
/io_mux
/ledc
/mcpwm
/pcnt
/rmt
/rtc_i2c
/rtccntl
/rtcio
/sens
/slc
/slchost
/spi
/syscon
/timg
/uart
/uhci
/apb_ctrl
/dport
/efuse
/gpio
/gpio_sd
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Just a placeholder. Will be over-written by build.sh when you run cargo build