summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--book/src/tutorial-3.md6
-rw-r--r--src/callbacks.rs3
-rw-r--r--src/clang.rs12
-rw-r--r--src/ir/item.rs17
-rw-r--r--src/lib.rs21
5 files changed, 58 insertions, 1 deletions
diff --git a/book/src/tutorial-3.md b/book/src/tutorial-3.md
index 950411e7..139a24f9 100644
--- a/book/src/tutorial-3.md
+++ b/book/src/tutorial-3.md
@@ -18,6 +18,9 @@ fn main() {
// shared library.
println!("cargo:rustc-link-lib=bz2");
+ // Tell cargo to invalidate the built crate whenever the wrapper changes
+ println!("cargo:rerun-if-changed=wrapper.h");
+
// The bindgen::Builder is the main entry point
// to bindgen, and lets you build up options for
// the resulting bindings.
@@ -25,6 +28,9 @@ fn main() {
// The input header we would like to generate
// bindings for.
.header("wrapper.h")
+ // Tell cargo to invalidate the built crate whenever any of the
+ // included header files changed.
+ .parse_callbacks(Box::new(bindgen::CargoCallbacks))
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
diff --git a/src/callbacks.rs b/src/callbacks.rs
index 91920738..21478e4f 100644
--- a/src/callbacks.rs
+++ b/src/callbacks.rs
@@ -64,4 +64,7 @@ pub trait ParseCallbacks: fmt::Debug + UnwindSafe {
fn item_name(&self, _original_item_name: &str) -> Option<String> {
None
}
+
+ /// This will be called on every file inclusion, with the full path of the included file.
+ fn include_file(&self, _filename: &str) {}
}
diff --git a/src/clang.rs b/src/clang.rs
index 9af6b46d..0a59c309 100644
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -717,6 +717,18 @@ impl Cursor {
})
.collect()
}
+
+ /// Obtain the real path name of a cursor of InclusionDirective kind.
+ ///
+ /// Returns None if the cursor does not include a file, otherwise the file's full name
+ pub fn get_included_file_name(&self) -> Option<String> {
+ let file = unsafe { clang_sys::clang_getIncludedFile(self.x) };
+ if file.is_null() {
+ None
+ } else {
+ Some(unsafe { cxstring_into_string(clang_sys::clang_getFileName(file)) })
+ }
+ }
}
/// A struct that owns the tokenizer result from a given cursor.
diff --git a/src/ir/item.rs b/src/ir/item.rs
index 7b4f3e83..1e12424e 100644
--- a/src/ir/item.rs
+++ b/src/ir/item.rs
@@ -1357,7 +1357,6 @@ impl ClangItemParser for Item {
CXCursor_UsingDeclaration |
CXCursor_UsingDirective |
CXCursor_StaticAssert |
- CXCursor_InclusionDirective |
CXCursor_FunctionTemplate => {
debug!(
"Unhandled cursor kind {:?}: {:?}",
@@ -1365,6 +1364,22 @@ impl ClangItemParser for Item {
cursor
);
}
+ CXCursor_InclusionDirective => {
+ let file = cursor.get_included_file_name();
+ match file {
+ None => {
+ warn!(
+ "Inclusion of a nameless file in {:?}",
+ cursor
+ );
+ }
+ Some(filename) => {
+ if let Some(cb) = ctx.parse_callbacks() {
+ cb.include_file(&filename)
+ }
+ }
+ }
+ }
_ => {
// ignore toplevel operator overloads
let spelling = cursor.spelling();
diff --git a/src/lib.rs b/src/lib.rs
index e37aa29e..f5a30468 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2148,6 +2148,27 @@ pub fn clang_version() -> ClangVersion {
}
}
+/// A ParseCallbacks implementation that will act on file includes by echoing a rerun-if-changed
+/// line
+///
+/// When running in side a `build.rs` script, this can be used to make cargo invalidate the
+/// generated bindings whenever any of the files included from the header change:
+/// ```
+/// use bindgen::builder;
+/// let bindings = builder()
+/// .header("path/to/input/header")
+/// .parse_callbacks(Box::new(bindgen::CargoCallbacks))
+/// .generate();
+/// ```
+#[derive(Debug)]
+pub struct CargoCallbacks;
+
+impl callbacks::ParseCallbacks for CargoCallbacks {
+ fn include_file(&self, filename: &str) {
+ println!("cargo:rerun-if-changed={}", filename);
+ }
+}
+
/// Test command_line_flag function.
#[test]
fn commandline_flag_unit_test_function() {