summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock96
-rw-r--r--Cargo.toml1
-rw-r--r--src/codegen/mod.rs10
-rw-r--r--src/deps.rs20
-rw-r--r--src/ir/context.rs26
-rw-r--r--src/ir/item.rs4
-rw-r--r--src/lib.rs34
-rw-r--r--src/options.rs10
-rw-r--r--tests/expectations/tests/enum-default-rust.d1
-rw-r--r--tests/tests.rs26
10 files changed, 219 insertions, 9 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 7fc45354..443201ee 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -50,6 +50,7 @@ dependencies = [
"regex",
"rustc-hash",
"shlex",
+ "tempfile",
"which",
]
@@ -126,6 +127,17 @@ dependencies = [
]
[[package]]
+name = "getrandom"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
+dependencies = [
+ "cfg-if 1.0.0",
+ "libc",
+ "wasi",
+]
+
+[[package]]
name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -206,6 +218,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
+name = "ppv-lite86"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+
+[[package]]
name = "proc-macro2"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -224,6 +242,55 @@ dependencies = [
]
[[package]]
+name = "rand"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
name = "regex"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -242,6 +309,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
[[package]]
+name = "remove_dir_all"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -260,6 +336,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
+name = "tempfile"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
+dependencies = [
+ "cfg-if 1.0.0",
+ "libc",
+ "rand",
+ "redox_syscall",
+ "remove_dir_all",
+ "winapi",
+]
+
+[[package]]
name = "termcolor"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -311,6 +401,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
[[package]]
+name = "wasi"
+version = "0.10.2+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
+
+[[package]]
name = "which"
version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index dd30f09c..61404078 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -43,6 +43,7 @@ required-features = ["clap"]
diff = "0.1"
clap = "2"
shlex = "1"
+tempfile = "3"
[dependencies]
bitflags = "1.0.3"
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);
}
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 418811e3..58c99c8d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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>
};
diff --git a/tests/expectations/tests/enum-default-rust.d b/tests/expectations/tests/enum-default-rust.d
new file mode 100644
index 00000000..a6540005
--- /dev/null
+++ b/tests/expectations/tests/enum-default-rust.d
@@ -0,0 +1 @@
+tests/expectations/tests/enum-default-rust.rs: tests/headers/enum-default-rust.h tests/headers/enum.h
diff --git a/tests/tests.rs b/tests/tests.rs
index 80ccc8c9..ced48540 100644
--- a/tests/tests.rs
+++ b/tests/tests.rs
@@ -579,6 +579,32 @@ fn no_system_header_includes() {
}
#[test]
+fn emit_depfile() {
+ let header = PathBuf::from("tests/headers/enum-default-rust.h");
+ let expected_depfile = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
+ .join("tests")
+ .join("expectations")
+ .join("tests")
+ .join("enum-default-rust.d");
+ let observed_depfile = tempfile::NamedTempFile::new().unwrap();
+ let mut builder = create_bindgen_builder(&header).unwrap();
+ builder.builder = builder.builder.depfile(
+ "tests/expectations/tests/enum-default-rust.rs",
+ observed_depfile.path(),
+ );
+
+ let check_roundtrip =
+ env::var_os("BINDGEN_DISABLE_ROUNDTRIP_TEST").is_none();
+ let (builder, _roundtrip_builder) =
+ builder.into_builder(check_roundtrip).unwrap();
+ let _bindings = builder.generate().unwrap();
+
+ let observed = std::fs::read_to_string(observed_depfile).unwrap();
+ let expected = std::fs::read_to_string(expected_depfile).unwrap();
+ assert_eq!(observed.trim(), expected.trim());
+}
+
+#[test]
fn dump_preprocessed_input() {
let arg_keyword =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/arg_keyword.hpp");