hack: Add a BINDGEN_USE_BINARY=/path/to/bindgen.
diff --git a/src/lib.rs b/src/lib.rs index ce0d5d4..3d25982 100644 --- a/src/lib.rs +++ b/src/lib.rs
@@ -1327,6 +1327,15 @@ /// Generate the Rust bindings using the options built up thus far. pub fn generate(mut self) -> Result<Bindings, ()> { + if let Some(bin) = env::var_os("BINDGEN_USE_BINARY") { + let output = Command::new(bin) + .args(self.command_line_flags()) + .env_remove("BINDGEN_USE_BINARY") + .output() + .expect("Failed to run BINDGEN_USE_BINARY"); + return Ok(Bindings(BindingsInner::Eager(String::from_utf8(output.stdout).expect("Bindgen should only generate valid utf-8")))); + } + // Add any extra arguments from the environment to the clang command line. if let Some(extra_clang_args) = env::var("BINDGEN_EXTRA_CLANG_ARGS").ok() @@ -1951,9 +1960,15 @@ /// Generated Rust bindings. #[derive(Debug)] -pub struct Bindings { - options: BindgenOptions, - module: proc_macro2::TokenStream, +pub struct Bindings(BindingsInner); + +#[derive(Debug)] +enum BindingsInner { + Lazy { + options: BindgenOptions, + module: proc_macro2::TokenStream, + }, + Eager(String), } pub(crate) const HOST_TARGET: &'static str = @@ -2166,16 +2181,20 @@ let (items, options) = codegen::codegen(context); - Ok(Bindings { + Ok(Bindings(BindingsInner::Lazy { options, module: quote! { #( #items )* }, - }) + })) } /// Convert these bindings into source text (with raw lines prepended). pub fn to_string(&self) -> String { + if let BindingsInner::Eager(ref s) = self.0 { + return s.clone() + } + let mut bytes = vec![]; self.write(Box::new(&mut bytes) as Box<dyn Write>) .expect("writing to a vec cannot fail"); @@ -2196,7 +2215,12 @@ /// Write these bindings as source text to the given `Write`able. pub fn write<'a>(&self, mut writer: Box<dyn Write + 'a>) -> io::Result<()> { - if !self.options.disable_header_comment { + let (options, module) = match self.0 { + BindingsInner::Eager(ref s) => return writer.write_all(s.as_bytes()), + BindingsInner::Lazy { ref options, ref module } => (options, module), + }; + + if !options.disable_header_comment { let version = option_env!("CARGO_PKG_VERSION"); let header = format!( "/* automatically generated by rust-bindgen {} */\n\n", @@ -2205,18 +2229,18 @@ writer.write_all(header.as_bytes())?; } - for line in self.options.raw_lines.iter() { + for line in options.raw_lines.iter() { writer.write_all(line.as_bytes())?; writer.write_all("\n".as_bytes())?; } - if !self.options.raw_lines.is_empty() { + if !options.raw_lines.is_empty() { writer.write_all("\n".as_bytes())?; } - let bindings = self.module.to_string(); + let bindings = module.to_string(); - match self.rustfmt_generated_string(&bindings) { + match self.rustfmt_generated_string(&bindings, options) { Ok(rustfmt_bindings) => { writer.write_all(rustfmt_bindings.as_bytes())?; } @@ -2232,9 +2256,9 @@ } /// Gets the rustfmt path to rustfmt the generated bindings. - fn rustfmt_path<'a>(&'a self) -> io::Result<Cow<'a, PathBuf>> { - debug_assert!(self.options.rustfmt_bindings); - if let Some(ref p) = self.options.rustfmt_path { + fn rustfmt_path<'a>(options: &'a BindgenOptions) -> io::Result<Cow<'a, PathBuf>> { + debug_assert!(options.rustfmt_bindings); + if let Some(ref p) = options.rustfmt_path { return Ok(Cow::Borrowed(p)); } if let Ok(rustfmt) = env::var("RUSTFMT") { @@ -2257,21 +2281,22 @@ fn rustfmt_generated_string<'a>( &self, source: &'a str, + options: &BindgenOptions, ) -> io::Result<Cow<'a, str>> { let _t = time::Timer::new("rustfmt_generated_string") - .with_output(self.options.time_phases); + .with_output(options.time_phases); - if !self.options.rustfmt_bindings { + if !options.rustfmt_bindings { return Ok(Cow::Borrowed(source)); } - let rustfmt = self.rustfmt_path()?; + let rustfmt = Self::rustfmt_path(options)?; let mut cmd = Command::new(&*rustfmt); cmd.stdin(Stdio::piped()).stdout(Stdio::piped()); - if let Some(path) = self - .options + if let Some(path) = + options .rustfmt_configuration_file .as_ref() .and_then(|f| f.to_str())