From 056333c380cb8a36647c7e65ff73f635f3c86269 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 3 Oct 2022 14:16:01 -0500 Subject: [PATCH 1/2] Run `Bindings::generate` again if required. This adds a mechanism so `bindgen` is able to run `Bindings::generate` multiple times with the same user input if the `generate_static_inline` option is enabled and `GenerateError::ShouldRestart` is returned by `Bindings::generate`. This is done to eventually solve #1090 which would require to check for any static inline functions and generate a new header file to be used as an extra input and run `Bindings::generate` again. --- bindgen/lib.rs | 50 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/bindgen/lib.rs b/bindgen/lib.rs index 880d52a9ee..fbb70224b0 100644 --- a/bindgen/lib.rs +++ b/bindgen/lib.rs @@ -1559,25 +1559,33 @@ impl Builder { } /// Generate the Rust bindings using the options built up thus far. - pub fn generate(mut self) -> Result { + pub fn generate(self) -> Result { + let mut options = self.options.clone(); // Add any extra arguments from the environment to the clang command line. - self.options.clang_args.extend(get_extra_clang_args()); + options.clang_args.extend(get_extra_clang_args()); // Transform input headers to arguments on the clang command line. - self.options.clang_args.extend( - self.options.input_headers - [..self.options.input_headers.len().saturating_sub(1)] + options.clang_args.extend( + options.input_headers + [..options.input_headers.len().saturating_sub(1)] .iter() .flat_map(|header| ["-include".into(), header.to_string()]), ); let input_unsaved_files = - std::mem::take(&mut self.options.input_header_contents) + std::mem::take(&mut options.input_header_contents) .into_iter() .map(|(name, contents)| clang::UnsavedFile::new(name, contents)) .collect::>(); - Bindings::generate(self.options, input_unsaved_files) + match Bindings::generate(options, input_unsaved_files) { + Ok(bindings) => Ok(bindings), + Err(GenerateError::ShouldRestart { header }) => self + .header(header) + .generate_inline_functions(false) + .generate(), + Err(GenerateError::Bindgen(err)) => Err(err), + } } /// Preprocess and dump the input header files to disk. @@ -2287,6 +2295,23 @@ fn ensure_libclang_is_loaded() { #[cfg(not(feature = "runtime"))] fn ensure_libclang_is_loaded() {} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +enum GenerateError { + /// Error variant raised when bindgen requires to run again with a newly generated header + /// input. + #[allow(dead_code)] + ShouldRestart { + header: String, + }, + Bindgen(BindgenError), +} + +impl From for GenerateError { + fn from(err: BindgenError) -> Self { + Self::Bindgen(err) + } +} + /// Error type for rust-bindgen. #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] @@ -2380,7 +2405,7 @@ impl Bindings { pub(crate) fn generate( mut options: BindgenOptions, input_unsaved_files: Vec, - ) -> Result { + ) -> Result { ensure_libclang_is_loaded(); #[cfg(feature = "runtime")] @@ -2501,17 +2526,20 @@ impl Bindings { let path = Path::new(h); if let Ok(md) = std::fs::metadata(path) { if md.is_dir() { - return Err(BindgenError::FolderAsHeader(path.into())); + return Err( + BindgenError::FolderAsHeader(path.into()).into() + ); } if !can_read(&md.permissions()) { return Err(BindgenError::InsufficientPermissions( path.into(), - )); + ) + .into()); } let h = h.clone(); options.clang_args.push(h); } else { - return Err(BindgenError::NotExist(path.into())); + return Err(BindgenError::NotExist(path.into()).into()); } } From cf6f39e081fae4f96fc7de1d2c08225e5932d1b9 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 1 Nov 2022 08:41:07 -0500 Subject: [PATCH 2/2] use result instead of error --- bindgen/lib.rs | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/bindgen/lib.rs b/bindgen/lib.rs index fbb70224b0..d890898a42 100644 --- a/bindgen/lib.rs +++ b/bindgen/lib.rs @@ -1579,12 +1579,12 @@ impl Builder { .collect::>(); match Bindings::generate(options, input_unsaved_files) { - Ok(bindings) => Ok(bindings), - Err(GenerateError::ShouldRestart { header }) => self + GenerateResult::Ok(bindings) => Ok(bindings), + GenerateResult::ShouldRestart { header } => self .header(header) .generate_inline_functions(false) .generate(), - Err(GenerateError::Bindgen(err)) => Err(err), + GenerateResult::Err(err) => Err(err), } } @@ -2295,21 +2295,16 @@ fn ensure_libclang_is_loaded() { #[cfg(not(feature = "runtime"))] fn ensure_libclang_is_loaded() {} -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -enum GenerateError { +#[derive(Debug)] +enum GenerateResult { + Ok(Bindings), /// Error variant raised when bindgen requires to run again with a newly generated header /// input. #[allow(dead_code)] ShouldRestart { header: String, }, - Bindgen(BindgenError), -} - -impl From for GenerateError { - fn from(err: BindgenError) -> Self { - Self::Bindgen(err) - } + Err(BindgenError), } /// Error type for rust-bindgen. @@ -2405,7 +2400,7 @@ impl Bindings { pub(crate) fn generate( mut options: BindgenOptions, input_unsaved_files: Vec, - ) -> Result { + ) -> GenerateResult { ensure_libclang_is_loaded(); #[cfg(feature = "runtime")] @@ -2526,20 +2521,22 @@ impl Bindings { let path = Path::new(h); if let Ok(md) = std::fs::metadata(path) { if md.is_dir() { - return Err( - BindgenError::FolderAsHeader(path.into()).into() + return GenerateResult::Err( + BindgenError::FolderAsHeader(path.into()).into(), ); } if !can_read(&md.permissions()) { - return Err(BindgenError::InsufficientPermissions( - path.into(), - ) - .into()); + return GenerateResult::Err( + BindgenError::InsufficientPermissions(path.into()) + .into(), + ); } let h = h.clone(); options.clang_args.push(h); } else { - return Err(BindgenError::NotExist(path.into()).into()); + return GenerateResult::Err( + BindgenError::NotExist(path.into()).into(), + ); } } @@ -2567,12 +2564,14 @@ impl Bindings { { let _t = time::Timer::new("parse").with_output(time_phases); - parse(&mut context)?; + if let Err(err) = parse(&mut context) { + return GenerateResult::Err(err); + } } let (module, options, warnings) = codegen::codegen(context); - Ok(Bindings { + GenerateResult::Ok(Bindings { options, warnings, module,