From 63de9486e8e1a2d2987c93a7fedd766bf8c52b78 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Mon, 27 Mar 2017 13:02:33 -0400 Subject: [PATCH] Add a `Builder::header_contents` method to allow passing source code as a string to a Builder Currently the Builder API requires input as header files on disk. This allows passing C source directly to clang using the existing UnsavedFile struct. --- src/clang.rs | 13 ++++++++++++- src/ir/context.rs | 2 +- src/lib.rs | 16 ++++++++++++++++ tests/tests.rs | 18 +++++++++++++++++- 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/clang.rs b/src/clang.rs index fc7950dcfc..ee42274551 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -1409,7 +1409,9 @@ impl Drop for Diagnostic { /// A file which has not been saved to disk. pub struct UnsavedFile { x: CXUnsavedFile, - name: CString, + /// The name of the unsaved file. Kept here to avoid leaving dangling pointers in + /// `CXUnsavedFile`. + pub name: CString, contents: CString, } @@ -1431,6 +1433,15 @@ impl UnsavedFile { } } +impl fmt::Debug for UnsavedFile { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, + "UnsavedFile(name: {:?}, contents: {:?})", + self.name, + self.contents) + } +} + /// Convert a cursor kind into a static string. pub fn kind_to_str(x: CXCursorKind) -> String { unsafe { cxstring_into_string(clang_getCursorKindSpelling(x)) } diff --git a/src/ir/context.rs b/src/ir/context.rs index 4a6785b16c..c95d517918 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -182,7 +182,7 @@ impl<'ctx> BindgenContext<'ctx> { clang::TranslationUnit::parse(&index, "", &options.clang_args, - &[], + &options.input_unsaved_files, parse_options) .expect("TranslationUnit::parse failed"); diff --git a/src/lib.rs b/src/lib.rs index 433198b07a..8f838c15ea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -175,6 +175,14 @@ impl Builder { self } + /// Add `contents` as an input C/C++ header named `name`. + /// + /// The file `name` will be added to the clang arguments. + pub fn header_contents(mut self, name: &str, contents: &str) -> Builder { + self.options.input_unsaved_files.push(clang::UnsavedFile::new(name, contents)); + self + } + /// Set the output graphviz file. pub fn emit_ir_graphviz>(mut self, path: T) -> Builder { let path = path.into(); @@ -573,6 +581,9 @@ pub struct BindgenOptions { /// The input header file. pub input_header: Option, + /// Unsaved files for input. + pub input_unsaved_files: Vec, + /// Generate a dummy C/C++ file that includes the header and has dummy uses /// of all types defined therein. See the `uses` module for more. pub dummy_uses: Option, @@ -662,6 +673,7 @@ impl Default for BindgenOptions { raw_lines: vec![], clang_args: vec![], input_header: None, + input_unsaved_files: vec![], dummy_uses: None, parse_callbacks: None, codegen_config: CodegenConfig::all(), @@ -754,6 +766,10 @@ impl<'ctx> Bindings<'ctx> { options.clang_args.push(h.clone()) } + for f in options.input_unsaved_files.iter() { + options.clang_args.push(f.name.to_str().unwrap().to_owned()) + } + let mut context = BindgenContext::new(options); try!(parse(&mut context)); diff --git a/tests/tests.rs b/tests/tests.rs index 6b69e0d42c..84b5e076f7 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -3,7 +3,7 @@ extern crate diff; extern crate bindgen; extern crate shlex; -use bindgen::Builder; +use bindgen::{Builder, builder}; use std::fs; use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Write}; use std::path::PathBuf; @@ -144,3 +144,19 @@ macro_rules! test_header { // This file is generated by build.rs include!(concat!(env!("OUT_DIR"), "/tests.rs")); + +#[test] +fn test_header_contents() { + let bindings = builder() + .header_contents("test.h", "int foo(const char* a);") + .no_unstable_rust() + .generate() + .unwrap() + .to_string(); + assert_eq!(bindings, "/* automatically generated by rust-bindgen */ + +extern \"C\" { + pub fn foo(a: *const ::std::os::raw::c_schar) -> ::std::os::raw::c_int; +} +"); +}