Skip to content

Commit 1bb548b

Browse files
anpemilio
authored andcommitted
Support emitting Makefile-syntax depfiles like gcc/clang/rustc.
Needed to auto-bindgen with a ninja build without the build graph going stale.
1 parent c39c47c commit 1bb548b

File tree

10 files changed

+219
-9
lines changed

10 files changed

+219
-9
lines changed

Cargo.lock

Lines changed: 96 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ required-features = ["clap"]
4343
diff = "0.1"
4444
clap = "2"
4545
shlex = "1"
46+
tempfile = "3"
4647

4748
[dependencies]
4849
bitflags = "1.0.3"

src/codegen/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4207,6 +4207,16 @@ pub(crate) fn codegen(
42074207
}
42084208
}
42094209

4210+
if let Some(spec) = context.options().depfile.as_ref() {
4211+
match spec.write(context.deps()) {
4212+
Ok(()) => info!(
4213+
"Your depfile was generated successfully into: {}",
4214+
spec.depfile_path.display()
4215+
),
4216+
Err(e) => warn!("{}", e),
4217+
}
4218+
}
4219+
42104220
context.resolve_item(context.root_module()).codegen(
42114221
context,
42124222
&mut result,

src/deps.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/// Generating build depfiles from parsed bindings.
2+
use std::{collections::BTreeSet, path::PathBuf};
3+
4+
#[derive(Debug)]
5+
pub(crate) struct DepfileSpec {
6+
pub output_module: String,
7+
pub depfile_path: PathBuf,
8+
}
9+
10+
impl DepfileSpec {
11+
pub fn write(&self, deps: &BTreeSet<String>) -> std::io::Result<()> {
12+
let mut buf = format!("{}:", self.output_module);
13+
14+
for file in deps {
15+
buf = format!("{} {}", buf, file);
16+
}
17+
18+
std::fs::write(&self.depfile_path, &buf)
19+
}
20+
}

src/ir/context.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use clang_sys;
2929
use proc_macro2::{Ident, Span};
3030
use std::borrow::Cow;
3131
use std::cell::{Cell, RefCell};
32-
use std::collections::HashMap as StdHashMap;
32+
use std::collections::{BTreeSet, HashMap as StdHashMap};
3333
use std::iter::IntoIterator;
3434
use std::mem;
3535

@@ -354,6 +354,9 @@ pub struct BindgenContext {
354354
/// This needs to be an std::HashMap because the cexpr API requires it.
355355
parsed_macros: StdHashMap<Vec<u8>, cexpr::expr::EvalResult>,
356356

357+
/// A set of all the included filenames.
358+
deps: BTreeSet<String>,
359+
357360
/// The active replacements collected from replaces="xxx" annotations.
358361
replacements: HashMap<Vec<String>, ItemId>,
359362

@@ -545,8 +548,16 @@ If you encounter an error missing from this list, please file an issue or a PR!"
545548
let root_module = Self::build_root_module(ItemId(0));
546549
let root_module_id = root_module.id().as_module_id_unchecked();
547550

551+
// depfiles need to include the explicitly listed headers too
552+
let mut deps = BTreeSet::default();
553+
if let Some(filename) = &options.input_header {
554+
deps.insert(filename.clone());
555+
}
556+
deps.extend(options.extra_input_headers.iter().cloned());
557+
548558
BindgenContext {
549559
items: vec![Some(root_module)],
560+
deps,
550561
types: Default::default(),
551562
type_params: Default::default(),
552563
modules: Default::default(),
@@ -632,6 +643,19 @@ If you encounter an error missing from this list, please file an issue or a PR!"
632643
self.options().parse_callbacks.as_ref().map(|t| &**t)
633644
}
634645

646+
/// Add another path to the set of included files.
647+
pub fn include_file(&mut self, filename: String) {
648+
if let Some(cbs) = self.parse_callbacks() {
649+
cbs.include_file(&filename);
650+
}
651+
self.deps.insert(filename);
652+
}
653+
654+
/// Get any included files.
655+
pub fn deps(&self) -> &BTreeSet<String> {
656+
&self.deps
657+
}
658+
635659
/// Define a new item.
636660
///
637661
/// This inserts it into the internal items set, and its type into the

src/ir/item.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,9 +1415,7 @@ impl ClangItemParser for Item {
14151415
);
14161416
}
14171417
Some(filename) => {
1418-
if let Some(cb) = ctx.parse_callbacks() {
1419-
cb.include_file(&filename)
1420-
}
1418+
ctx.include_file(filename);
14211419
}
14221420
}
14231421
}

src/lib.rs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ macro_rules! doc_mod {
5151

5252
mod clang;
5353
mod codegen;
54+
mod deps;
5455
mod features;
5556
mod ir;
5657
mod parse;
@@ -604,6 +605,19 @@ impl Builder {
604605
self
605606
}
606607

608+
/// Add a depfile output which will be written alongside the generated bindings.
609+
pub fn depfile<H: Into<String>, D: Into<PathBuf>>(
610+
mut self,
611+
output_module: H,
612+
depfile: D,
613+
) -> Builder {
614+
self.options.depfile = Some(deps::DepfileSpec {
615+
output_module: output_module.into(),
616+
depfile_path: depfile.into(),
617+
});
618+
self
619+
}
620+
607621
/// Add `contents` as an input C/C++ header named `name`.
608622
///
609623
/// The file `name` will be added to the clang arguments.
@@ -1417,11 +1431,13 @@ impl Builder {
14171431

14181432
// Transform input headers to arguments on the clang command line.
14191433
self.options.input_header = self.input_headers.pop();
1420-
self.options
1421-
.clang_args
1422-
.extend(self.input_headers.drain(..).flat_map(|header| {
1423-
iter::once("-include".into()).chain(iter::once(header))
1424-
}));
1434+
self.options.extra_input_headers = self.input_headers;
1435+
self.options.clang_args.extend(
1436+
self.options.extra_input_headers.iter().flat_map(|header| {
1437+
iter::once("-include".into())
1438+
.chain(iter::once(header.to_string()))
1439+
}),
1440+
);
14251441

14261442
self.options.input_unsaved_files.extend(
14271443
self.input_header_contents
@@ -1624,6 +1640,9 @@ struct BindgenOptions {
16241640
/// The explicit rustfmt path.
16251641
rustfmt_path: Option<PathBuf>,
16261642

1643+
/// The path to which we should write a Makefile-syntax depfile (if any).
1644+
depfile: Option<deps::DepfileSpec>,
1645+
16271646
/// The set of types that we should have bindings for in the generated
16281647
/// code.
16291648
///
@@ -1785,6 +1804,9 @@ struct BindgenOptions {
17851804
/// The input header file.
17861805
input_header: Option<String>,
17871806

1807+
/// Any additional input header files.
1808+
extra_input_headers: Vec<String>,
1809+
17881810
/// Unsaved files for input.
17891811
input_unsaved_files: Vec<clang::UnsavedFile>,
17901812

@@ -1963,6 +1985,7 @@ impl Default for BindgenOptions {
19631985
blocklisted_items: Default::default(),
19641986
opaque_types: Default::default(),
19651987
rustfmt_path: Default::default(),
1988+
depfile: Default::default(),
19661989
allowlisted_types: Default::default(),
19671990
allowlisted_functions: Default::default(),
19681991
allowlisted_vars: Default::default(),
@@ -2008,6 +2031,7 @@ impl Default for BindgenOptions {
20082031
module_lines: HashMap::default(),
20092032
clang_args: vec![],
20102033
input_header: None,
2034+
extra_input_headers: vec![],
20112035
input_unsaved_files: vec![],
20122036
parse_callbacks: None,
20132037
codegen_config: CodegenConfig::all(),

src/options.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ where
3030
Arg::with_name("header")
3131
.help("C or C++ header file")
3232
.required(true),
33+
Arg::with_name("depfile")
34+
.long("depfile")
35+
.takes_value(true)
36+
.help("Path to write depfile to"),
3337
Arg::with_name("default-enum-style")
3438
.long("default-enum-style")
3539
.help("The default style of code used to generate enums.")
@@ -848,8 +852,14 @@ where
848852

849853
let output = if let Some(path) = matches.value_of("output") {
850854
let file = File::create(path)?;
855+
if let Some(depfile) = matches.value_of("depfile") {
856+
builder = builder.depfile(path, depfile);
857+
}
851858
Box::new(io::BufWriter::new(file)) as Box<dyn io::Write>
852859
} else {
860+
if let Some(depfile) = matches.value_of("depfile") {
861+
builder = builder.depfile("-", depfile);
862+
}
853863
Box::new(io::BufWriter::new(io::stdout())) as Box<dyn io::Write>
854864
};
855865

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
tests/expectations/tests/enum-default-rust.rs: tests/headers/enum-default-rust.h tests/headers/enum.h

0 commit comments

Comments
 (0)