diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 94 |
1 files changed, 80 insertions, 14 deletions
@@ -1444,6 +1444,7 @@ impl Builder { } /// Generate the Rust bindings using the options built up thus far. + #[deprecated(since = "0.59.3", note = "please use `gen` instead")] pub fn generate(mut self) -> Result<Bindings, ()> { // Add any extra arguments from the environment to the clang command line. if let Some(extra_clang_args) = @@ -1475,6 +1476,41 @@ impl Builder { }), ); + Bindings::generate(self.options).map_err(|_| ()) + } + + /// Generate the Rust bindings using the options built up thus far, or `Err` on failure. + pub fn gen(mut self) -> Result<Bindings, BindgenError> { + // Add any extra arguments from the environment to the clang command line. + if let Some(extra_clang_args) = + get_target_dependent_env_var("BINDGEN_EXTRA_CLANG_ARGS") + { + // Try to parse it with shell quoting. If we fail, make it one single big argument. + if let Some(strings) = shlex::split(&extra_clang_args) { + self.options.clang_args.extend(strings); + } else { + self.options.clang_args.push(extra_clang_args); + }; + } + + // Transform input headers to arguments on the clang command line. + self.options.input_header = self.input_headers.pop(); + 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 + .drain(..) + .map(|(name, contents)| { + clang::UnsavedFile::new(&name, &contents) + }), + ); + Bindings::generate(self.options) } @@ -2146,6 +2182,28 @@ fn ensure_libclang_is_loaded() { #[cfg(not(feature = "runtime"))] fn ensure_libclang_is_loaded() {} +/// Error type for rust-bindgen. +#[derive(Debug)] +pub enum BindgenError { + /// Any provided header was invalid. + InvalidHeader(String), + /// Clang diagnosed an error. + ClangDiagnostic(String), +} + +impl std::fmt::Display for BindgenError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + BindgenError::InvalidHeader(message) => { + write!(f, "invalid header: {}", message) + } + BindgenError::ClangDiagnostic(message) => { + write!(f, "clang diagnosed error: {}", message) + } + } + } +} + /// Generated Rust bindings. #[derive(Debug)] pub struct Bindings { @@ -2202,7 +2260,7 @@ impl Bindings { /// Generate bindings for the given options. pub(crate) fn generate( mut options: BindgenOptions, - ) -> Result<Bindings, ()> { + ) -> Result<Bindings, BindgenError> { ensure_libclang_is_loaded(); #[cfg(feature = "runtime")] @@ -2322,20 +2380,23 @@ impl Bindings { if let Some(h) = options.input_header.as_ref() { if let Ok(md) = std::fs::metadata(h) { if md.is_dir() { - eprintln!("error: '{}' is a folder", h); - return Err(()); + return Err(BindgenError::InvalidHeader(format!( + "error: '{}' is a folder", + h + ))); } if !can_read(&md.permissions()) { - eprintln!( + return Err(BindgenError::InvalidHeader(format!( "error: insufficient permissions to read '{}'", h - ); - return Err(()); + ))); } options.clang_args.push(h.clone()) } else { - eprintln!("error: header '{}' does not exist.", h); - return Err(()); + return Err(BindgenError::InvalidHeader(format!( + "error: header '{}' does not exist.", + h + ))); } } @@ -2556,19 +2617,24 @@ fn parse_one( } /// Parse the Clang AST into our `Item` internal representation. -fn parse(context: &mut BindgenContext) -> Result<(), ()> { +fn parse(context: &mut BindgenContext) -> Result<(), BindgenError> { use clang_sys::*; - let mut any_error = false; + let mut error = None; for d in context.translation_unit().diags().iter() { let msg = d.format(); let is_err = d.severity() >= CXDiagnostic_Error; - eprintln!("{}, err: {}", msg, is_err); - any_error |= is_err; + if is_err { + let error = error.get_or_insert_with(String::new); + error.push_str(&msg); + error.push('\n'); + } else { + eprintln!("clang diag: {}", msg); + } } - if any_error { - return Err(()); + if let Some(message) = error { + return Err(BindgenError::ClangDiagnostic(message)); } let cursor = context.translation_unit().cursor(); |