Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support emitting Makefile-syntax depfiles like gcc/clang/rustc. #2026

Merged
merged 2 commits into from Apr 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
96 changes: 96 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -43,6 +43,7 @@ required-features = ["clap"]
diff = "0.1"
clap = "2"
shlex = "1"
tempfile = "3"

[dependencies]
bitflags = "1.0.3"
Expand Down
23 changes: 17 additions & 6 deletions bindgen-integration/build.rs
Expand Up @@ -140,10 +140,16 @@ fn main() {
cc::Build::new()
.cpp(true)
.file("cpp/Test.cc")
.include("include")
.compile("libtest.a");

let macros = Arc::new(RwLock::new(HashSet::new()));

let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let out_rust_file = out_path.join("test.rs");
let out_rust_file_relative = out_rust_file.strip_prefix(std::env::current_dir().unwrap()).unwrap();
let out_dep_file = out_path.join("test.d");

let bindings = Builder::default()
.rustfmt_bindings(false)
.enable_cxx_namespaces()
Expand All @@ -154,7 +160,7 @@ fn main() {
.raw_line("extern { fn my_prefixed_function_to_remove(i: i32); }")
.module_raw_line("root::testing", "pub type Bar = i32;")
.header("cpp/Test.h")
.clang_args(&["-x", "c++", "-std=c++11"])
.clang_args(&["-x", "c++", "-std=c++11", "-I", "include"])
.parse_callbacks(Box::new(MacroCallback {
macros: macros.clone(),
seen_hellos: Mutex::new(0),
Expand All @@ -163,13 +169,18 @@ fn main() {
.blocklist_function("my_prefixed_function_to_remove")
.constified_enum("my_prefixed_enum_to_be_constified")
.opaque_type("my_prefixed_templated_foo<my_prefixed_baz>")
.depfile(out_rust_file_relative.display().to_string(), &out_dep_file)
.generate()
.expect("Unable to generate bindings");

assert!(macros.read().unwrap().contains("TESTMACRO"));

let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("test.rs"))
.expect("Couldn't write bindings!");
bindings.write_to_file(&out_rust_file).expect("Couldn't write bindings!");

let observed_deps = std::fs::read_to_string(out_dep_file).expect("Couldn't read depfile!");
let expected_deps = format!("{}: cpp/Test.h include/stub.h", out_rust_file_relative.display());
assert_eq!(
observed_deps,
expected_deps,
"including stub via include dir must produce correct dep path",
);
}
2 changes: 2 additions & 0 deletions bindgen-integration/cpp/Test.h
@@ -1,3 +1,5 @@
#include "stub.h" // this bad path is made valid by a `-I include` clang arg

#pragma once

#define TESTMACRO
Expand Down
Empty file.
10 changes: 10 additions & 0 deletions src/codegen/mod.rs
Expand Up @@ -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,
Expand Down
20 changes: 20 additions & 0 deletions 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)
}
}
26 changes: 25 additions & 1 deletion src/ir/context.rs
Expand Up @@ -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;

Expand Down Expand Up @@ -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>,

Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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
Expand Down
4 changes: 1 addition & 3 deletions src/ir/item.rs
Expand Up @@ -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);
}
}
}
Expand Down
34 changes: 29 additions & 5 deletions src/lib.rs
Expand Up @@ -51,6 +51,7 @@ macro_rules! doc_mod {

mod clang;
mod codegen;
mod deps;
mod features;
mod ir;
mod parse;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
///
Expand Down Expand Up @@ -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>,

Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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(),
Expand Down