From cff4356acca790ce5aed3292f009a6c8ffcc058e Mon Sep 17 00:00:00 2001 From: Bas Zalmstra Date: Sun, 29 Dec 2019 13:33:17 +0100 Subject: [PATCH] feat: add manual generation of abi, runtime-capi When using build.rs files several files get regenerated every build which causes rebuilds even when nothing really changed. This commit changes this behavior to make the user manually run a command when the files should be regenerated. --- .cargo/config | 4 +- .github/workflows/ci.yml | 2 + crates/mun_abi/Cargo.toml | 3 -- crates/mun_abi/src/autogen.rs | 2 + crates/mun_runtime_capi/Cargo.toml | 3 -- crates/mun_runtime_capi/build.rs | 11 ----- crates/mun_runtime_capi/ffi | 2 +- crates/tools/Cargo.toml | 2 + crates/{mun_abi/build.rs => tools/src/abi.rs} | 32 ++++++++----- crates/tools/src/lib.rs | 47 +++++++++---------- crates/tools/src/main.rs | 8 +++- crates/tools/src/runtime_capi.rs | 16 +++++++ crates/tools/src/syntax.rs | 32 +++++++++++++ 13 files changed, 104 insertions(+), 60 deletions(-) delete mode 100644 crates/mun_runtime_capi/build.rs rename crates/{mun_abi/build.rs => tools/src/abi.rs} (64%) create mode 100644 crates/tools/src/runtime_capi.rs create mode 100644 crates/tools/src/syntax.rs diff --git a/.cargo/config b/.cargo/config index 342331279..b9bbf9123 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,3 +1,5 @@ [alias] # Automatically generates the ast and syntax kinds files -gen-syntax = "run --package tools --bin tools -- gen-syntax" +gen-syntax = "run --package tools --bin tools -- gen-syntax" +gen-runtime-capi = "run --package tools --bin tools -- gen-runtime-capi" +gen-abi = "run --package tools --bin tools -- gen-abi" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9bb8cc164..a428b345f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,6 +61,8 @@ jobs: - name: Cargo check uses: actions-rs/cargo@v1 + env: + RUST_BACKTRACE: 1 continue-on-error: ${{ matrix.config.toolchain != 'stable' }} with: command: test diff --git a/crates/mun_abi/Cargo.toml b/crates/mun_abi/Cargo.toml index 211885661..a1a73b1f0 100644 --- a/crates/mun_abi/Cargo.toml +++ b/crates/mun_abi/Cargo.toml @@ -4,8 +4,5 @@ version = "0.2.0" authors = ["The Mun Team "] edition = "2018" -[build-dependencies] -bindgen = "0.51" - [dependencies] md5 = "0.6.1" diff --git a/crates/mun_abi/src/autogen.rs b/crates/mun_abi/src/autogen.rs index d673ae8c1..8a9e862b8 100644 --- a/crates/mun_abi/src/autogen.rs +++ b/crates/mun_abi/src/autogen.rs @@ -1,3 +1,5 @@ +//! Generated file, do not edit by hand, see `crate/ra_tools/src/codegen` + /* automatically generated by rust-bindgen */ #![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] diff --git a/crates/mun_runtime_capi/Cargo.toml b/crates/mun_runtime_capi/Cargo.toml index 0974c7514..80fe4f534 100644 --- a/crates/mun_runtime_capi/Cargo.toml +++ b/crates/mun_runtime_capi/Cargo.toml @@ -15,6 +15,3 @@ mun_abi = { path = "../mun_abi" } mun_runtime = { path = "../mun_runtime" } parking_lot = "0.9.0" rand = "0.7.2" - -[build-dependencies] -cbindgen = "0.9.1" diff --git a/crates/mun_runtime_capi/build.rs b/crates/mun_runtime_capi/build.rs deleted file mode 100644 index d3e33b7b7..000000000 --- a/crates/mun_runtime_capi/build.rs +++ /dev/null @@ -1,11 +0,0 @@ -use std::env; - -use cbindgen; - -fn main() { - let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); - - cbindgen::generate(crate_dir) - .expect("Unable to generate Mun Runtime bindings.") - .write_to_file("ffi/include/mun/runtime_capi.h"); -} diff --git a/crates/mun_runtime_capi/ffi b/crates/mun_runtime_capi/ffi index 830bf08ff..9c05b26c0 160000 --- a/crates/mun_runtime_capi/ffi +++ b/crates/mun_runtime_capi/ffi @@ -1 +1 @@ -Subproject commit 830bf08ff806a53d689b25a9dc803cbf0c84c096 +Subproject commit 9c05b26c0f04c633228b2b648cfdc50267bdd00f diff --git a/crates/tools/Cargo.toml b/crates/tools/Cargo.toml index 971ade25a..3ca0a0730 100644 --- a/crates/tools/Cargo.toml +++ b/crates/tools/Cargo.toml @@ -9,3 +9,5 @@ teraron = "0.0.1" clap = "2.32.0" failure = "0.1.4" ron = "0.4.2" +cbindgen = "0.9.1" +bindgen = "0.51" diff --git a/crates/mun_abi/build.rs b/crates/tools/src/abi.rs similarity index 64% rename from crates/mun_abi/build.rs rename to crates/tools/src/abi.rs index f40b9c306..d4a3a2da3 100644 --- a/crates/mun_abi/build.rs +++ b/crates/tools/src/abi.rs @@ -1,5 +1,8 @@ -use std::env; -use std::path::PathBuf; +use crate::{project_root, reformat, update, Result}; +use failure::format_err; +use teraron::Mode; + +pub const ABI_DIR: &str = "crates/mun_abi"; use bindgen::{self, callbacks::EnumVariantValue, callbacks::ParseCallbacks}; @@ -29,9 +32,17 @@ impl ParseCallbacks for RemoveVendorName { } } -fn main() { +/// Generates the FFI bindings for the Mun ABI +pub fn generate(mode: Mode) -> Result<()> { + let crate_dir = project_root().join(ABI_DIR); + let output_file_path = crate_dir.join("src/autogen.rs"); + let input_file_path = crate_dir.join("c/include/mun_abi.h"); + + let input_file_str = input_file_path + .to_str() + .ok_or_else(|| failure::err_msg("could not create path to mun_abi.h"))?; let bindings = bindgen::Builder::default() - .header("c/include/mun_abi.h") + .header(input_file_str) .whitelist_type("Mun.*") .blacklist_type("MunPrivacy.*") // Remove type aliasing on Linux @@ -45,13 +56,8 @@ fn main() { .raw_line("#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]") .raw_line("use crate::Privacy;") .generate() - .expect("Unable to generate bindings for 'mun_abi.h'"); - - let out_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); - bindings - .write_to_file(out_path.join("src/autogen.rs")) - .expect(&format!( - "Couldn't write bindings to '{}'", - out_path.as_path().to_string_lossy() - )); + .map_err(|_| format_err!("Unable to generate bindings from 'mun_abi.h'"))?; + + let file_contents = reformat(bindings.to_string())?; + update(&output_file_path, &file_contents, mode) } diff --git a/crates/tools/src/lib.rs b/crates/tools/src/lib.rs index 8537ae330..8b4d7be00 100644 --- a/crates/tools/src/lib.rs +++ b/crates/tools/src/lib.rs @@ -6,31 +6,9 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; pub use teraron::{Mode, Overwrite, Verify}; -pub const GRAMMAR: &str = "crates/mun_syntax/src/grammar.ron"; -pub const SYNTAX_KINDS: &str = "crates/mun_syntax/src/syntax_kind/generated.rs.tera"; -pub const AST: &str = "crates/mun_syntax/src/ast/generated.rs.tera"; - -pub fn generate_all(mode: Mode) -> Result<()> { - let grammar = project_root().join(GRAMMAR); - let syntax_kinds = project_root().join(SYNTAX_KINDS); - let ast = project_root().join(AST); - generate(&syntax_kinds, &grammar, mode)?; - generate(&ast, &grammar, mode)?; - Ok(()) -} - -pub fn generate(template: &Path, src: &Path, mode: Mode) -> Result<()> { - let file_name = template.file_stem().unwrap().to_str().unwrap(); - let tgt = template.with_file_name(file_name); - let template = fs::read_to_string(template)?; - let src: ron::Value = { - let text = fs::read_to_string(src)?; - ron::de::from_str(&text)? - }; - let content = teraron::render(&template, src)?; - let content = reformat(content)?; - update(&tgt, &content, mode) -} +pub mod abi; +pub mod runtime_capi; +pub mod syntax; /// A helper to update file on disk if it has changed. /// With verify = false, @@ -79,8 +57,25 @@ mod tests { #[test] fn grammar_is_fresh() { - if let Err(error) = super::generate_all(Mode::Verify) { + if let Err(error) = super::syntax::generate(Mode::Verify) { panic!("{}. Please update it by running `cargo gen-syntax`", error); } } + + #[test] + fn runtime_capi_is_fresh() { + if let Err(error) = super::runtime_capi::generate(Mode::Verify) { + panic!( + "{}. Please update it by running `cargo gen-runtime-capi`", + error + ); + } + } + + #[test] + fn abi_is_fresh() { + if let Err(error) = super::abi::generate(Mode::Verify) { + panic!("{}. Please update it by running `cargo gen-abi`", error); + } + } } diff --git a/crates/tools/src/main.rs b/crates/tools/src/main.rs index 86883a96c..c34de668a 100644 --- a/crates/tools/src/main.rs +++ b/crates/tools/src/main.rs @@ -1,17 +1,21 @@ use clap::{App, SubCommand}; -use tools::{generate_all, Overwrite, Result}; +use tools::{Overwrite, Result}; fn main() -> Result<()> { let matches = App::new("tasks") .setting(clap::AppSettings::SubcommandRequiredElseHelp) .subcommand(SubCommand::with_name("gen-syntax")) + .subcommand(SubCommand::with_name("gen-runtime-capi")) + .subcommand(SubCommand::with_name("gen-abi")) .get_matches(); match matches .subcommand_name() .expect("Subcommand must be specified") { - "gen-syntax" => generate_all(Overwrite)?, + "gen-syntax" => tools::syntax::generate(Overwrite)?, + "gen-abi" => tools::abi::generate(Overwrite)?, + "gen-runtime-capi" => tools::runtime_capi::generate(Overwrite)?, _ => unreachable!(), } Ok(()) diff --git a/crates/tools/src/runtime_capi.rs b/crates/tools/src/runtime_capi.rs new file mode 100644 index 000000000..2562a5dad --- /dev/null +++ b/crates/tools/src/runtime_capi.rs @@ -0,0 +1,16 @@ +use crate::{project_root, update, Result}; +use teraron::Mode; + +pub const RUNTIME_CAPI_DIR: &str = "crates/mun_runtime_capi"; + +/// Generates the FFI bindings for the Mun runtime +pub fn generate(mode: Mode) -> Result<()> { + let crate_dir = project_root().join(RUNTIME_CAPI_DIR); + let file_path = crate_dir.join("ffi/include/mun/runtime_capi.h"); + + let mut file_contents = Vec::::new(); + cbindgen::generate(crate_dir)?.write(&mut file_contents); + + let file_contents = String::from_utf8(file_contents)?.replace("\r\n", "\n"); + update(&file_path, &file_contents, mode) +} diff --git a/crates/tools/src/syntax.rs b/crates/tools/src/syntax.rs new file mode 100644 index 000000000..69311540a --- /dev/null +++ b/crates/tools/src/syntax.rs @@ -0,0 +1,32 @@ +use crate::{project_root, reformat, update, Result}; +use std::fs; +use std::path::Path; +use teraron::Mode; + +pub const GRAMMAR: &str = "crates/mun_syntax/src/grammar.ron"; +pub const SYNTAX_KINDS: &str = "crates/mun_syntax/src/syntax_kind/generated.rs.tera"; +pub const AST: &str = "crates/mun_syntax/src/ast/generated.rs.tera"; + +/// Generates the generated.rs for AST and syntax nodes. +pub fn generate(mode: Mode) -> Result<()> { + let grammar = project_root().join(GRAMMAR); + let syntax_kinds = project_root().join(SYNTAX_KINDS); + let ast = project_root().join(AST); + generate_from_template(&syntax_kinds, &grammar, mode)?; + generate_from_template(&ast, &grammar, mode)?; + Ok(()) +} + +/// Generate file contents from a template +fn generate_from_template(template: &Path, src: &Path, mode: Mode) -> Result<()> { + let file_name = template.file_stem().unwrap().to_str().unwrap(); + let tgt = template.with_file_name(file_name); + let template = fs::read_to_string(template)?; + let src: ron::Value = { + let text = fs::read_to_string(src)?; + ron::de::from_str(&text)? + }; + let content = teraron::render(&template, src)?; + let content = reformat(content)?; + update(&tgt, &content, mode) +}