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/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 f1020a2a2..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.12.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..10061b7f8 160000 --- a/crates/mun_runtime_capi/ffi +++ b/crates/mun_runtime_capi/ffi @@ -1 +1 @@ -Subproject commit 830bf08ff806a53d689b25a9dc803cbf0c84c096 +Subproject commit 10061b7f898ea4f3c0b1b9e1d2921e46a7109f38 diff --git a/crates/tools/Cargo.toml b/crates/tools/Cargo.toml index 971ade25a..07acf8f8d 100644 --- a/crates/tools/Cargo.toml +++ b/crates/tools/Cargo.toml @@ -9,3 +9,6 @@ teraron = "0.0.1" clap = "2.32.0" failure = "0.1.4" ron = "0.4.2" +cbindgen = { git = "https://github.com/baszalmstra/cbindgen", branch = "fix_lockfile_v2" } +bindgen = "0.51" +difference = "2.0" 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..39edcf386 100644 --- a/crates/tools/src/lib.rs +++ b/crates/tools/src/lib.rs @@ -6,45 +6,23 @@ 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, fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { - match fs::read_to_string(path) { - Ok(ref old_contents) - if old_contents.replace("\r\n", "\n") == contents.replace("\r\n", "\n") => - { - return Ok(()); - } - _ => (), + let old_contents = fs::read_to_string(path)?; + let old_contents = old_contents.replace("\r\n", "\n"); + let contents = contents.replace("\r\n", "\n"); + if old_contents == contents { + return Ok(()); } + if mode == Mode::Verify { - failure::bail!("`{}` is not up-to-date", path.display()); + let changes = difference::Changeset::new(&old_contents, &contents, "\n"); + failure::bail!("`{}` is not up-to-date:\n{}", path.display(), changes); } eprintln!("updating {}", path.display()); fs::write(path, contents)?; @@ -79,8 +57,31 @@ mod tests { #[test] fn grammar_is_fresh() { - if let Err(error) = super::generate_all(Mode::Verify) { - panic!("{}. Please update it by running `cargo gen-syntax`", error); + if let Err(error) = super::syntax::generate(Mode::Verify) { + panic!( + "Please update syntax by running `cargo gen-syntax`, its out of date.\n{}", + error + ); + } + } + + #[test] + fn runtime_capi_is_fresh() { + if let Err(error) = super::runtime_capi::generate(Mode::Verify) { + panic!( + "Please update runtime-capi by running `cargo gen-runtime-capi`, its out of date.\n{}", + error + ); + } + } + + #[test] + fn abi_is_fresh() { + if let Err(error) = super::abi::generate(Mode::Verify) { + panic!( + "Please update abi by running `cargo gen-abi`, its out of date.\n{}", + 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..db7fe29eb --- /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)?; + 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) +}