diff options
Diffstat (limited to 'subplot-build')
-rw-r--r-- | subplot-build/Cargo.toml | 19 | ||||
-rw-r--r-- | subplot-build/src/lib.rs | 83 |
2 files changed, 102 insertions, 0 deletions
diff --git a/subplot-build/Cargo.toml b/subplot-build/Cargo.toml new file mode 100644 index 0000000..40e4bac --- /dev/null +++ b/subplot-build/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "subplot-build" +version = "0.1.0" +authors = [ + "Lars Wirzenius <liw@liw.fi>", + "Daniel Silverstone <dsilvers@digital-scurf.org>", +] +edition = "2018" +license = "GPL-3.0-or-later" +description = '''A library for using Subplot code generation from another project's +`build.rs` module.''' +homepage = "https://subplot.liw.fi/" +repository = "https://gitlab.com/subplot/subplot" + + +[dependencies] +subplot = { version="0.2.2", path = ".." } +tracing = "0.1" +tempfile = "3.1.0" diff --git a/subplot-build/src/lib.rs b/subplot-build/src/lib.rs new file mode 100644 index 0000000..89ea57d --- /dev/null +++ b/subplot-build/src/lib.rs @@ -0,0 +1,83 @@ +//! Subplot test program building from `build.rs` +//! +//! This crate provides the Subplot code generation facility in a way +//! that's meant to be easy to use from another project's `build.rs` +//! module. + +use std::env::var_os; +use std::fmt::Debug; +use std::path::{Path, PathBuf}; +use subplot::{get_basedir_from, Result}; +use tracing::{event, instrument, span, Level}; + +/// Generate code for one document, inside `build.rs`. +/// +/// The output files will be written to the directory specified in the +/// OUT_DIR environment variable. That variable is set by Cargo, when +/// a crate is built. +/// +/// Also emit instructions for Cargo so it knows to re-run `build.rs` +/// whenever the input subplot or any of the bindings or functions +/// files it refers to changes. See +/// <https://doc.rust-lang.org/cargo/reference/build-scripts.html> for +/// details. +/// +/// ``` +/// use subplot_build::codegen; +/// # let dir = tempfile::tempdir().unwrap(); +/// # std::env::set_var("OUT_DIR", dir.path()); +/// +/// codegen("foo.md").ok(); // ignoring error to keep example short +/// # dir.close().unwrap() +/// ``` +#[instrument(level = "trace")] +pub fn codegen<P>(filename: P) -> Result<()> +where + P: AsRef<Path> + Debug, +{ + let span = span!(Level::TRACE, "codegen_buildrs"); + let _enter = span.enter(); + + event!(Level::TRACE, "Generating code in build.rs"); + + // Decide the name of the generated test program. + let out_dir = var_os("OUT_DIR").expect("OUT_DIR is not defined in the environment"); + let out_dir = Path::new(&out_dir); + let filename = filename.as_ref(); + let test_rs = + buildrs_output(out_dir, filename, "rs").expect("could not create output filename"); + + // Generate test program. + let output = subplot::codegen(filename, &test_rs)?; + + // Write instructions for Cargo to check if build scripts needs + // re-running. + let base_path = get_basedir_from(filename); + let meta = output.doc.meta(); + buildrs_deps(&base_path, &meta.bindings_filenames()); + buildrs_deps(&base_path, &meta.functions_filenames()); + buildrs_deps(&base_path, &[filename]); + + event!(Level::TRACE, "Finished generating code"); + Ok(()) +} + +fn buildrs_deps(base_path: &Path, filenames: &[&Path]) { + for filename in filenames { + let filename = base_path.join(filename); + if filename.exists() { + println!("cargo:rerun-if-changed={}", filename.display()); + } + } +} + +fn buildrs_output(dir: &Path, filename: &Path, new_extension: &str) -> Option<PathBuf> { + if let Some(basename) = filename.file_name() { + let basename = Path::new(basename); + if let Some(stem) = basename.file_stem() { + let stem = Path::new(stem); + return Some(dir.join(stem.with_extension(new_extension))); + } + } + None +} |