| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| #![allow(clippy::needless_doctest_main)] |
| |
| //! A library for build scripts to generate `.rs` files using `regtool.py`. |
| //! |
| //! This library is intended to be used as a `build-dependencies` entry in |
| //! `Cargo.toml`: |
| //! |
| //! ```toml |
| //! [build-dependencies] |
| //! regtool = { path = "path/to/regtool" } |
| //! ``` |
| //! |
| //! By default, the library expects the environment variable `REGTOOL` to point |
| //! to `regtool.py`. Either set the variable before running cargo, or use |
| //! `Build::regtool(...)` from `build.rs` to set the path to the script |
| //! explicitly. |
| //! |
| //! # Examples |
| //! |
| //! Use the `Build` struct to process `hw/ip/uart/data/uart.hjson`: |
| //! |
| //! build.rs: |
| //! |
| //! ```no_run |
| //! fn main() { |
| //! regtool::Build::new() |
| //! .in_file_path("hw/ip/uart/data/uart.hjson") |
| //! .generate("uart.rs"); |
| //! } |
| //! ``` |
| //! |
| //! src/main.rs: |
| //! |
| //! ```no_run |
| //! include!(concat!(env!("OUT_DIR"), "/uart.rs")); |
| //! ``` |
| |
| use std::env; |
| use std::path::Path; |
| use std::path::PathBuf; |
| use std::process::Command; |
| |
| #[derive(Clone, Debug)] |
| pub struct Build { |
| in_file_path: Option<PathBuf>, // Must be set; no default |
| out_dir: Option<PathBuf>, // default: $OUT_DIR |
| |
| python: Option<PathBuf>, |
| regtool: Option<PathBuf>, // Default: $REGTOOL |
| } |
| |
| macro_rules! option_path_setter { |
| ($name:ident) => { |
| pub fn $name<P: AsRef<Path>>(&mut self, $name: P) -> &mut Build { |
| self.$name = Some($name.as_ref().to_owned()); |
| self |
| } |
| }; |
| } |
| |
| impl Build { |
| pub fn new() -> Self { |
| Self { |
| in_file_path: None, |
| out_dir: None, |
| |
| python: None, |
| regtool: None, |
| } |
| } |
| |
| // Generate setter functions for Option<PathBuf> fields: |
| option_path_setter!(in_file_path); |
| option_path_setter!(out_dir); |
| option_path_setter!(python); |
| option_path_setter!(regtool); |
| |
| // Run regtool. If out_file is an absolute path, write output to out_file, |
| // otherwise write output to out_dir/out_file. |
| pub fn generate(&self, out_file: &str) { |
| let regtool = if let Some(regtool) = &self.regtool { |
| regtool.to_owned() |
| } else { |
| println!("cargo:rerun-if-env-changed=REGTOOL"); |
| PathBuf::from(env::var("REGTOOL").expect("missing environment variable 'REGTOOL'")) |
| }; |
| println!("cargo:rerun-if-changed={}", regtool.display()); |
| |
| let mut out_file_path = if let Some(out_dir) = &self.out_dir { |
| out_dir.to_owned() |
| } else { |
| PathBuf::from(env::var("OUT_DIR").unwrap()) |
| }; |
| // NB: If out_file is absolute, it replaces the current path. |
| out_file_path.push(out_file); |
| |
| let in_file_path: &Path = self |
| .in_file_path |
| .as_ref() |
| .expect("'in_file_path' is not set"); |
| println!("cargo:rerun-if-changed={}", in_file_path.display()); |
| |
| let mut cmd; |
| if let Some(python) = &self.python { |
| cmd = Command::new(python); |
| cmd.arg(regtool); |
| } else { |
| cmd = Command::new(regtool); |
| } |
| cmd.arg("-R").arg("-o").arg(out_file_path).arg(in_file_path); |
| println!("Running: {:?}", cmd); |
| assert!(cmd.status().unwrap().success()); |
| } |
| } |
| |
| impl Default for Build { |
| fn default() -> Self { |
| Self::new() |
| } |
| } |