diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/codegen/mod.rs | 10 | ||||
-rw-r--r-- | src/deps.rs | 20 | ||||
-rw-r--r-- | src/ir/context.rs | 26 | ||||
-rw-r--r-- | src/ir/item.rs | 4 | ||||
-rw-r--r-- | src/lib.rs | 34 | ||||
-rw-r--r-- | src/options.rs | 10 |
6 files changed, 95 insertions, 9 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index e498d2b2..1a702b00 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -4207,6 +4207,16 @@ pub(crate) fn codegen( } } + if let Some(spec) = context.options().depfile.as_ref() { + match spec.write(context.deps()) { + Ok(()) => info!( + "Your depfile was generated successfully into: {}", + spec.depfile_path.display() + ), + Err(e) => warn!("{}", e), + } + } + context.resolve_item(context.root_module()).codegen( context, &mut result, diff --git a/src/deps.rs b/src/deps.rs new file mode 100644 index 00000000..479c396c --- /dev/null +++ b/src/deps.rs @@ -0,0 +1,20 @@ +/// Generating build depfiles from parsed bindings. +use std::{collections::BTreeSet, path::PathBuf}; + +#[derive(Debug)] +pub(crate) struct DepfileSpec { + pub output_module: String, + pub depfile_path: PathBuf, +} + +impl DepfileSpec { + pub fn write(&self, deps: &BTreeSet<String>) -> std::io::Result<()> { + let mut buf = format!("{}:", self.output_module); + + for file in deps { + buf = format!("{} {}", buf, file); + } + + std::fs::write(&self.depfile_path, &buf) + } +} diff --git a/src/ir/context.rs b/src/ir/context.rs index ccb05e75..2b8acc36 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -29,7 +29,7 @@ use clang_sys; use proc_macro2::{Ident, Span}; use std::borrow::Cow; use std::cell::{Cell, RefCell}; -use std::collections::HashMap as StdHashMap; +use std::collections::{BTreeSet, HashMap as StdHashMap}; use std::iter::IntoIterator; use std::mem; @@ -354,6 +354,9 @@ pub struct BindgenContext { /// This needs to be an std::HashMap because the cexpr API requires it. parsed_macros: StdHashMap<Vec<u8>, cexpr::expr::EvalResult>, + /// A set of all the included filenames. + deps: BTreeSet<String>, + /// The active replacements collected from replaces="xxx" annotations. replacements: HashMap<Vec<String>, ItemId>, @@ -545,8 +548,16 @@ If you encounter an error missing from this list, please file an issue or a PR!" let root_module = Self::build_root_module(ItemId(0)); let root_module_id = root_module.id().as_module_id_unchecked(); + // depfiles need to include the explicitly listed headers too + let mut deps = BTreeSet::default(); + if let Some(filename) = &options.input_header { + deps.insert(filename.clone()); + } + deps.extend(options.extra_input_headers.iter().cloned()); + BindgenContext { items: vec![Some(root_module)], + deps, types: Default::default(), type_params: Default::default(), modules: Default::default(), @@ -632,6 +643,19 @@ If you encounter an error missing from this list, please file an issue or a PR!" self.options().parse_callbacks.as_ref().map(|t| &**t) } + /// Add another path to the set of included files. + pub fn include_file(&mut self, filename: String) { + if let Some(cbs) = self.parse_callbacks() { + cbs.include_file(&filename); + } + self.deps.insert(filename); + } + + /// Get any included files. + pub fn deps(&self) -> &BTreeSet<String> { + &self.deps + } + /// Define a new item. /// /// This inserts it into the internal items set, and its type into the diff --git a/src/ir/item.rs b/src/ir/item.rs index 45415045..d7c92ab4 100644 --- a/src/ir/item.rs +++ b/src/ir/item.rs @@ -1415,9 +1415,7 @@ impl ClangItemParser for Item { ); } Some(filename) => { - if let Some(cb) = ctx.parse_callbacks() { - cb.include_file(&filename) - } + ctx.include_file(filename); } } } @@ -51,6 +51,7 @@ macro_rules! doc_mod { mod clang; mod codegen; +mod deps; mod features; mod ir; mod parse; @@ -604,6 +605,19 @@ impl Builder { self } + /// Add a depfile output which will be written alongside the generated bindings. + pub fn depfile<H: Into<String>, D: Into<PathBuf>>( + mut self, + output_module: H, + depfile: D, + ) -> Builder { + self.options.depfile = Some(deps::DepfileSpec { + output_module: output_module.into(), + depfile_path: depfile.into(), + }); + self + } + /// Add `contents` as an input C/C++ header named `name`. /// /// The file `name` will be added to the clang arguments. @@ -1417,11 +1431,13 @@ impl Builder { // Transform input headers to arguments on the clang command line. self.options.input_header = self.input_headers.pop(); - self.options - .clang_args - .extend(self.input_headers.drain(..).flat_map(|header| { - iter::once("-include".into()).chain(iter::once(header)) - })); + self.options.extra_input_headers = self.input_headers; + self.options.clang_args.extend( + self.options.extra_input_headers.iter().flat_map(|header| { + iter::once("-include".into()) + .chain(iter::once(header.to_string())) + }), + ); self.options.input_unsaved_files.extend( self.input_header_contents @@ -1624,6 +1640,9 @@ struct BindgenOptions { /// The explicit rustfmt path. rustfmt_path: Option<PathBuf>, + /// The path to which we should write a Makefile-syntax depfile (if any). + depfile: Option<deps::DepfileSpec>, + /// The set of types that we should have bindings for in the generated /// code. /// @@ -1785,6 +1804,9 @@ struct BindgenOptions { /// The input header file. input_header: Option<String>, + /// Any additional input header files. + extra_input_headers: Vec<String>, + /// Unsaved files for input. input_unsaved_files: Vec<clang::UnsavedFile>, @@ -1963,6 +1985,7 @@ impl Default for BindgenOptions { blocklisted_items: Default::default(), opaque_types: Default::default(), rustfmt_path: Default::default(), + depfile: Default::default(), allowlisted_types: Default::default(), allowlisted_functions: Default::default(), allowlisted_vars: Default::default(), @@ -2008,6 +2031,7 @@ impl Default for BindgenOptions { module_lines: HashMap::default(), clang_args: vec![], input_header: None, + extra_input_headers: vec![], input_unsaved_files: vec![], parse_callbacks: None, codegen_config: CodegenConfig::all(), diff --git a/src/options.rs b/src/options.rs index 36267321..ff2d4282 100644 --- a/src/options.rs +++ b/src/options.rs @@ -30,6 +30,10 @@ where Arg::with_name("header") .help("C or C++ header file") .required(true), + Arg::with_name("depfile") + .long("depfile") + .takes_value(true) + .help("Path to write depfile to"), Arg::with_name("default-enum-style") .long("default-enum-style") .help("The default style of code used to generate enums.") @@ -848,8 +852,14 @@ where let output = if let Some(path) = matches.value_of("output") { let file = File::create(path)?; + if let Some(depfile) = matches.value_of("depfile") { + builder = builder.depfile(path, depfile); + } Box::new(io::BufWriter::new(file)) as Box<dyn io::Write> } else { + if let Some(depfile) = matches.value_of("depfile") { + builder = builder.depfile("-", depfile); + } Box::new(io::BufWriter::new(io::stdout())) as Box<dyn io::Write> }; |