1use std::env::var_os;
8use std::error::Error;
9use std::fmt::Debug;
10use std::path::{Path, PathBuf};
11pub use subplot::SubplotError;
12use subplot::{get_basedir_from, SCENARIO_FILTER_EVERYTHING};
13use tracing::{event, instrument, span, Level};
14
15#[deprecated(
36 since = "0.13.0",
37 note = "The `subplot-build` crate has been replaced by a macro in `subplotlib` and will not be updated past 0.13 of Subplot"
38)]
39#[instrument(level = "trace")]
40pub fn codegen<P>(filename: P) -> Result<(), SubplotError>
41where
42 P: AsRef<Path> + Debug,
43{
44 let filename = filename.as_ref();
45 match _codegen(filename) {
46 Ok(()) => Ok(()),
47 Err(e) => {
48 eprintln!(
49 "\n\n\nsubplot_build::codegen({}) failed: {e}",
50 filename.display(),
51 );
52 let mut es = e.source();
53 while let Some(source) = es {
54 eprintln!("caused by: {source}");
55 es = source.source();
56 }
57 eprintln!("\n\n");
58 Err(e)
59 }
60 }
61}
62
63fn _codegen(filename: &Path) -> Result<(), SubplotError> {
64 let span = span!(Level::TRACE, "codegen_buildrs");
65 let _enter = span.enter();
66
67 event!(Level::TRACE, "Generating code in build.rs");
68
69 let out_dir = var_os("OUT_DIR").expect("OUT_DIR is not defined in the environment");
71 let out_dir = Path::new(&out_dir);
72 let test_rs =
73 buildrs_output(out_dir, filename, "rs").expect("could not create output filename");
74
75 let output = subplot::codegen(
77 filename,
78 &test_rs,
79 Some("rust"),
80 &SCENARIO_FILTER_EVERYTHING,
81 )?;
82
83 let base_path = get_basedir_from(filename);
86 let meta = output.doc.meta();
87 for filename in meta.markdown_filenames() {
88 buildrs_deps(&base_path, Some(filename.as_path()));
89 }
90 buildrs_deps(&base_path, meta.bindings_filenames());
91 let docimpl = output
92 .doc
93 .meta()
94 .document_impl("rust")
95 .expect("We managed to codegen rust, yet the spec is missing?");
96 buildrs_deps(&base_path, docimpl.functions_filenames());
97 buildrs_deps(&base_path, Some(filename));
98
99 event!(Level::TRACE, "Finished generating code");
100 Ok(())
101}
102
103fn buildrs_deps<'a>(base_path: &Path, filenames: impl IntoIterator<Item = &'a Path>) {
104 for filename in filenames {
105 let filename = base_path.join(filename);
106 if filename.exists() {
107 println!("cargo:rerun-if-changed={}", filename.display());
108 }
109 }
110}
111
112fn buildrs_output(dir: &Path, filename: &Path, new_extension: &str) -> Option<PathBuf> {
113 if let Some(basename) = filename.file_name() {
114 let basename = Path::new(basename);
115 if let Some(stem) = basename.file_stem() {
116 let stem = Path::new(stem);
117 return Some(dir.join(stem.with_extension(new_extension)));
118 }
119 }
120 None
121}