Skip to content

Commit

Permalink
Support emitting Makefile-syntax depfiles like gcc/clang/rustc.
Browse files Browse the repository at this point in the history
Needed to auto-bindgen with a ninja build without the build graph
going stale.
  • Loading branch information
anp committed Apr 8, 2021
1 parent 696455d commit 9e560ad
Show file tree
Hide file tree
Showing 9 changed files with 362 additions and 1 deletion.
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
8 changes: 7 additions & 1 deletion src/callbacks.rs
Expand Up @@ -4,6 +4,7 @@ pub use crate::ir::analysis::DeriveTrait;
pub use crate::ir::derive::CanDerive as ImplementsTrait;
pub use crate::ir::enum_ty::{EnumVariantCustomBehavior, EnumVariantValue};
pub use crate::ir::int::IntKind;
use std::any::Any;
use std::fmt;
use std::panic::UnwindSafe;

Expand All @@ -25,7 +26,7 @@ impl Default for MacroParsingBehavior {

/// A trait to allow configuring different kinds of types in different
/// situations.
pub trait ParseCallbacks: fmt::Debug + UnwindSafe {
pub trait ParseCallbacks: Any + fmt::Debug + UnwindSafe {
/// This function will be run on every macro that is identified.
fn will_parse_macro(&self, _name: &str) -> MacroParsingBehavior {
MacroParsingBehavior::Default
Expand Down Expand Up @@ -95,4 +96,9 @@ pub trait ParseCallbacks: fmt::Debug + UnwindSafe {
) -> Option<ImplementsTrait> {
None
}

/// TODO find a way to delete this from this PR
fn as_any(&self) -> Option<&dyn Any> {
None
}
}
17 changes: 17 additions & 0 deletions src/codegen/mod.rs
Expand Up @@ -4198,6 +4198,23 @@ pub(crate) fn codegen(
}
}

if let Some(collector) =
crate::deps::DepCollector::retrieve(&context.options())
{
let spec = context
.options()
.depfile
.as_ref()
.expect("if we have a collector, we have a spec");
match collector.write_depfile(spec) {
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
175 changes: 175 additions & 0 deletions src/deps.rs
@@ -0,0 +1,175 @@
// Generating build depfiles from parsed bindings.

use crate::{
callbacks::{
DeriveTrait, EnumVariantCustomBehavior, EnumVariantValue,
ImplementsTrait, IntKind, MacroParsingBehavior, ParseCallbacks,
},
BindgenOptions,
};
use std::{
collections::BTreeSet,
path::PathBuf,
sync::{Arc, Mutex},
};

#[derive(Debug)]
pub(crate) struct DepfileSpec {
pub output_module: String,
pub depfile_path: PathBuf,
}

#[derive(Clone, Debug)]
pub(crate) struct DepCollector {
inner: Arc<Mutex<InnerCollector>>,
}

impl DepCollector {
pub(crate) fn install(options: &mut BindgenOptions) {
let collector = DepCollector {
inner: Arc::new(Mutex::new(InnerCollector {
files: Default::default(),
prev_cb: None,
})),
};
collector.inner.lock().unwrap().prev_cb = std::mem::replace(
&mut options.parse_callbacks,
Some(Box::new(collector.clone())),
);
}

pub(crate) fn retrieve(options: &BindgenOptions) -> Option<&Self> {
options
.parse_callbacks
.as_ref()
.and_then(|cb| cb.as_any())
.and_then(|cb| cb.downcast_ref())
}

pub(crate) fn write_depfile(
&self,
spec: &DepfileSpec,
) -> std::io::Result<()> {
let inner = self.inner.lock().unwrap();

let mut buf = format!("{}:", spec.output_module);

for file in &inner.files {
buf = format!("{} {}", buf, file);
}

std::fs::write(&spec.depfile_path, &buf)
}
}

impl ParseCallbacks for DepCollector {
fn include_file(&self, filename: &str) {
let mut inner = self.inner.lock().unwrap();
inner.files.insert(filename.to_owned());
if let Some(prev_cb) = &inner.prev_cb {
prev_cb.include_file(filename);
}
}

// all trait methods below here just forward to the wrapped callbacks

fn will_parse_macro(&self, name: &str) -> MacroParsingBehavior {
let inner = self.inner.lock().unwrap();
if let Some(prev_cb) = &inner.prev_cb {
prev_cb.will_parse_macro(name)
} else {
Default::default()
}
}

fn int_macro(&self, name: &str, value: i64) -> Option<IntKind> {
let inner = self.inner.lock().unwrap();
if let Some(prev_cb) = &inner.prev_cb {
prev_cb.int_macro(name, value)
} else {
None
}
}

fn str_macro(&self, name: &str, value: &[u8]) {
let inner = self.inner.lock().unwrap();
if let Some(prev_cb) = &inner.prev_cb {
prev_cb.str_macro(name, value);
}
}

fn func_macro(&self, name: &str, value: &[&[u8]]) {
let inner = self.inner.lock().unwrap();
if let Some(prev_cb) = &inner.prev_cb {
prev_cb.func_macro(name, value);
}
}

fn enum_variant_behavior(
&self,
enum_name: Option<&str>,
original_variant_name: &str,
variant_value: EnumVariantValue,
) -> Option<EnumVariantCustomBehavior> {
let inner = self.inner.lock().unwrap();
if let Some(prev_cb) = &inner.prev_cb {
prev_cb.enum_variant_behavior(
enum_name,
original_variant_name,
variant_value,
)
} else {
None
}
}

fn enum_variant_name(
&self,
enum_name: Option<&str>,
original_variant_name: &str,
variant_value: EnumVariantValue,
) -> Option<String> {
let inner = self.inner.lock().unwrap();
if let Some(prev_cb) = &inner.prev_cb {
prev_cb.enum_variant_name(
enum_name,
original_variant_name,
variant_value,
)
} else {
None
}
}

fn item_name(&self, original_item_name: &str) -> Option<String> {
let inner = self.inner.lock().unwrap();
if let Some(prev_cb) = &inner.prev_cb {
prev_cb.item_name(original_item_name)
} else {
None
}
}

fn blocklisted_type_implements_trait(
&self,
name: &str,
derive_trait: DeriveTrait,
) -> Option<ImplementsTrait> {
let inner = self.inner.lock().unwrap();
if let Some(prev_cb) = &inner.prev_cb {
prev_cb.blocklisted_type_implements_trait(name, derive_trait)
} else {
None
}
}

fn as_any(&self) -> Option<&dyn std::any::Any> {
Some(self)
}
}

#[derive(Debug)]
struct InnerCollector {
files: BTreeSet<String>,
prev_cb: Option<Box<dyn ParseCallbacks>>,
}

0 comments on commit 9e560ad

Please sign in to comment.