diff options
-rw-r--r-- | book/src/tutorial-3.md | 6 | ||||
-rw-r--r-- | src/callbacks.rs | 3 | ||||
-rw-r--r-- | src/clang.rs | 12 | ||||
-rw-r--r-- | src/ir/item.rs | 17 | ||||
-rw-r--r-- | src/lib.rs | 21 |
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(); @@ -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() { |