Regenerate QEMU binding stubs only for newer versions of the nightly compiler (#2177)

* Regenerate binding stubs only for newer versions of the nightly compiler.

* fmt

* clippy
This commit is contained in:
Romain Malmain 2024-05-15 01:42:59 +02:00 committed by GitHub
parent 19087f3dab
commit b127f0579d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 102 additions and 20 deletions

View File

@ -37,3 +37,4 @@ pkg-config = "0.3.26"
cc = "1.0" cc = "1.0"
regex = "1" regex = "1"
rustversion = "1.0" rustversion = "1.0"
rustc_version = "0.4"

View File

@ -95,7 +95,7 @@ pub fn generate(
) -> Result<Bindings, BindgenError> { ) -> Result<Bindings, BindgenError> {
let wrapper_h = build_dir.join("wrapper.h"); let wrapper_h = build_dir.join("wrapper.h");
store_generated_content_if_different(&wrapper_h, WRAPPER_HEADER.as_bytes()); store_generated_content_if_different(&wrapper_h, WRAPPER_HEADER.as_bytes(), None, None, false);
let bindings = bindgen::Builder::default() let bindings = bindgen::Builder::default()
.derive_debug(true) .derive_debug(true)

View File

@ -6,12 +6,14 @@ use std::{
env, fs, env, fs,
fs::File, fs::File,
hash::Hasher, hash::Hasher,
io::{Read, Seek, SeekFrom, Write}, io::{BufRead, BufReader, Read, Seek, SeekFrom, Write},
path::{Path, PathBuf}, path::{Path, PathBuf},
process::Command, process::Command,
ptr::addr_of_mut, ptr::addr_of_mut,
}; };
use regex::Regex;
use rustc_version::Version;
use which::which; use which::which;
mod bindings; mod bindings;
@ -243,17 +245,27 @@ fn include_path(build_dir: &Path, path: &str) -> String {
} }
} }
pub fn store_generated_content_if_different(file_to_update: &PathBuf, fresh_content: &[u8]) { /// If `fresh_content` != `content_file_to_update` (the file is read directly if `content_file_to_update` is None), update the file. prefix is not considered for comparison.
/// If a prefix is given, it will be added as the first line of the file.
pub fn store_generated_content_if_different(
file_to_update: &PathBuf,
fresh_content: &[u8],
content_file_to_update: Option<Vec<u8>>,
first_line_prefix: Option<&str>,
force_regeneration: bool,
) {
let mut must_rewrite_file = true; let mut must_rewrite_file = true;
// Check if equivalent file already exists without relying on filesystem timestamp. // Check if equivalent file already exists without relying on filesystem timestamp.
let mut file_to_check = let mut file_to_check =
if let Ok(mut wrapper_file) = File::options().read(true).write(true).open(file_to_update) { if let Ok(mut wrapper_file) = File::options().read(true).write(true).open(file_to_update) {
let mut existing_file_content = Vec::with_capacity(fresh_content.len()); let existing_file_content = content_file_to_update.unwrap_or_else(|| {
wrapper_file let mut content = Vec::with_capacity(fresh_content.len());
.read_to_end(existing_file_content.as_mut()) wrapper_file.read_to_end(content.as_mut()).unwrap();
.unwrap(); content
});
if !force_regeneration {
let mut existing_wrapper_hasher = hash_map::DefaultHasher::new(); let mut existing_wrapper_hasher = hash_map::DefaultHasher::new();
existing_wrapper_hasher.write(existing_file_content.as_ref()); existing_wrapper_hasher.write(existing_file_content.as_ref());
@ -264,6 +276,7 @@ pub fn store_generated_content_if_different(file_to_update: &PathBuf, fresh_cont
if existing_wrapper_hasher.finish() == wrapper_h_hasher.finish() { if existing_wrapper_hasher.finish() == wrapper_h_hasher.finish() {
must_rewrite_file = false; must_rewrite_file = false;
} }
}
// Reset file cursor if it's going to be rewritten // Reset file cursor if it's going to be rewritten
if must_rewrite_file { if must_rewrite_file {
@ -280,6 +293,10 @@ pub fn store_generated_content_if_different(file_to_update: &PathBuf, fresh_cont
}; };
if must_rewrite_file { if must_rewrite_file {
if let Some(prefix) = first_line_prefix {
writeln!(&file_to_check, "{prefix}").expect("Could not write prefix");
}
file_to_check file_to_check
.write_all(fresh_content) .write_all(fresh_content)
.unwrap_or_else(|_| panic!("Unable to write in {}", file_to_update.display())); .unwrap_or_else(|_| panic!("Unable to write in {}", file_to_update.display()));
@ -293,14 +310,76 @@ pub fn maybe_generate_stub_bindings(
bindings_file: &PathBuf, bindings_file: &PathBuf,
) { ) {
if cpu_target == "x86_64" && emulation_mode == "usermode" { if cpu_target == "x86_64" && emulation_mode == "usermode" {
let current_rustc_version =
rustc_version::version().expect("Could not get current rustc version");
let semver_re = Regex::new(r"/\* (.*) \*/").unwrap();
// We only try to store the stub if the current rustc version is strictly bigger than the one used to generate
// the versioned stub.
let (try_generate, force_regeneration, stub_content): (bool, bool, Option<Vec<u8>>) =
if let Ok(stub_file) = File::open(stub_bindings_file) {
let mut stub_rdr = BufReader::new(stub_file);
let mut first_line = String::new();
let mut stub_content = Vec::<u8>::new();
assert!(
stub_rdr
.read_line(&mut first_line)
.expect("Could not read first line")
> 0,
"Error while reading first line."
);
if let Some((_, [version_str])) = semver_re
.captures_iter(&first_line)
.next()
.map(|caps| caps.extract())
{
// The first line matches the regex
if let Ok(version) = Version::parse(version_str) {
// The first line contains a version
stub_rdr
.read_to_end(&mut stub_content)
.expect("could not read stub content");
(current_rustc_version > version, false, Some(stub_content))
} else {
stub_rdr.seek(SeekFrom::Start(0)).unwrap();
stub_rdr
.read_to_end(&mut stub_content)
.expect("could not read stub content");
(true, true, Some(stub_content))
}
} else {
stub_rdr.seek(SeekFrom::Start(0)).unwrap();
stub_rdr
.read_to_end(&mut stub_content)
.expect("could not read stub content");
(true, true, Some(stub_content))
}
} else {
// No stub file stored
(true, true, None)
};
let header = format!("/* {current_rustc_version} */");
if try_generate {
store_generated_content_if_different( store_generated_content_if_different(
stub_bindings_file, stub_bindings_file,
fs::read(bindings_file) fs::read(bindings_file)
.expect("Could not read generated bindings file") .expect("Could not read generated bindings file")
.as_slice(), .as_slice(),
stub_content,
Some(header.as_str()),
force_regeneration,
); );
} }
} }
}
#[rustversion::not(nightly)] #[rustversion::not(nightly)]
pub fn maybe_generate_stub_bindings( pub fn maybe_generate_stub_bindings(

View File

@ -1,3 +1,4 @@
/* 1.80.0-nightly */
/* automatically generated by rust-bindgen 0.69.4 */ /* automatically generated by rust-bindgen 0.69.4 */
#[repr(C)] #[repr(C)]

View File

@ -1,3 +1,4 @@
/* 1.80.0-nightly */
/* automatically generated by rust-bindgen 0.69.4 */ /* automatically generated by rust-bindgen 0.69.4 */
pub const _STDINT_H: u32 = 1; pub const _STDINT_H: u32 = 1;