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
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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