Skip to content

Commit a2fe04c

Browse files
authored
Add a mechanism to rerun bindgen with the same user options (#2292)
* 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 `GenerateResult::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.
1 parent 4f92dfb commit a2fe04c

File tree

1 file changed

+42
-15
lines changed

1 file changed

+42
-15
lines changed

bindgen/lib.rs

+42-15
Original file line numberDiff line numberDiff line change
@@ -1559,25 +1559,33 @@ impl Builder {
15591559
}
15601560

15611561
/// Generate the Rust bindings using the options built up thus far.
1562-
pub fn generate(mut self) -> Result<Bindings, BindgenError> {
1562+
pub fn generate(self) -> Result<Bindings, BindgenError> {
1563+
let mut options = self.options.clone();
15631564
// Add any extra arguments from the environment to the clang command line.
1564-
self.options.clang_args.extend(get_extra_clang_args());
1565+
options.clang_args.extend(get_extra_clang_args());
15651566

15661567
// Transform input headers to arguments on the clang command line.
1567-
self.options.clang_args.extend(
1568-
self.options.input_headers
1569-
[..self.options.input_headers.len().saturating_sub(1)]
1568+
options.clang_args.extend(
1569+
options.input_headers
1570+
[..options.input_headers.len().saturating_sub(1)]
15701571
.iter()
15711572
.flat_map(|header| ["-include".into(), header.to_string()]),
15721573
);
15731574

15741575
let input_unsaved_files =
1575-
std::mem::take(&mut self.options.input_header_contents)
1576+
std::mem::take(&mut options.input_header_contents)
15761577
.into_iter()
15771578
.map(|(name, contents)| clang::UnsavedFile::new(name, contents))
15781579
.collect::<Vec<_>>();
15791580

1580-
Bindings::generate(self.options, input_unsaved_files)
1581+
match Bindings::generate(options, input_unsaved_files) {
1582+
GenerateResult::Ok(bindings) => Ok(bindings),
1583+
GenerateResult::ShouldRestart { header } => self
1584+
.header(header)
1585+
.generate_inline_functions(false)
1586+
.generate(),
1587+
GenerateResult::Err(err) => Err(err),
1588+
}
15811589
}
15821590

15831591
/// Preprocess and dump the input header files to disk.
@@ -2282,6 +2290,18 @@ fn ensure_libclang_is_loaded() {
22822290
#[cfg(not(feature = "runtime"))]
22832291
fn ensure_libclang_is_loaded() {}
22842292

2293+
#[derive(Debug)]
2294+
enum GenerateResult {
2295+
Ok(Bindings),
2296+
/// Error variant raised when bindgen requires to run again with a newly generated header
2297+
/// input.
2298+
#[allow(dead_code)]
2299+
ShouldRestart {
2300+
header: String,
2301+
},
2302+
Err(BindgenError),
2303+
}
2304+
22852305
/// Error type for rust-bindgen.
22862306
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
22872307
#[non_exhaustive]
@@ -2375,7 +2395,7 @@ impl Bindings {
23752395
pub(crate) fn generate(
23762396
mut options: BindgenOptions,
23772397
input_unsaved_files: Vec<clang::UnsavedFile>,
2378-
) -> Result<Bindings, BindgenError> {
2398+
) -> GenerateResult {
23792399
ensure_libclang_is_loaded();
23802400

23812401
#[cfg(feature = "runtime")]
@@ -2496,17 +2516,22 @@ impl Bindings {
24962516
let path = Path::new(h);
24972517
if let Ok(md) = std::fs::metadata(path) {
24982518
if md.is_dir() {
2499-
return Err(BindgenError::FolderAsHeader(path.into()));
2519+
return GenerateResult::Err(
2520+
BindgenError::FolderAsHeader(path.into()).into(),
2521+
);
25002522
}
25012523
if !can_read(&md.permissions()) {
2502-
return Err(BindgenError::InsufficientPermissions(
2503-
path.into(),
2504-
));
2524+
return GenerateResult::Err(
2525+
BindgenError::InsufficientPermissions(path.into())
2526+
.into(),
2527+
);
25052528
}
25062529
let h = h.clone();
25072530
options.clang_args.push(h);
25082531
} else {
2509-
return Err(BindgenError::NotExist(path.into()));
2532+
return GenerateResult::Err(
2533+
BindgenError::NotExist(path.into()).into(),
2534+
);
25102535
}
25112536
}
25122537

@@ -2534,12 +2559,14 @@ impl Bindings {
25342559

25352560
{
25362561
let _t = time::Timer::new("parse").with_output(time_phases);
2537-
parse(&mut context)?;
2562+
if let Err(err) = parse(&mut context) {
2563+
return GenerateResult::Err(err);
2564+
}
25382565
}
25392566

25402567
let (module, options, warnings) = codegen::codegen(context);
25412568

2542-
Ok(Bindings {
2569+
GenerateResult::Ok(Bindings {
25432570
options,
25442571
warnings,
25452572
module,

0 commit comments

Comments
 (0)