From 71260a012013c249f3ddd2738fad0b43dfb8e055 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 30 Oct 2025 23:13:19 +0300 Subject: [PATCH 1/8] scripts/checkpatch.pl: remove bogus patch prefix warning Remove the 'patch prefix exists, appears to be a -p0 patch' warning entirely as it is fundamentally flawed and can only produce false positives. Sometimes I create test files with names 'a' and 'b', and then get surprised seeing this warning. It was not easy to understand where it comes from. How it works: 1. It extracts prefixes (a/, b/) from standard diff output 2. Checks if files/directories with these names exist in the project root 3. Warns if they exist, claiming it's a '-p0 patch' issue This logic is wrong because: - Standard diff/patch tools always use a/ and b/ prefixes by default - The existence of files named 'a' or 'b' in the working directory is completely unrelated to patch format - The working directory state may not correspond to the patch content (different commits, branches, etc.) - In QEMU project, there are no single-letter files/directories in root, so this check can only generate false positives The correct way to detect -p0 patches would be to analyze the path format within the patch itself (e.g., absolute paths or paths without prefixes), not check filesystem state. So, let's finally drop it. Signed-off-by: Vladimir Sementsov-Ogievskiy Link: https://lore.kernel.org/r/20251030201319.858480-1-vsementsov@yandex-team.ru Signed-off-by: Paolo Bonzini --- scripts/checkpatch.pl | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index d3d75f3f13..d0f4537f25 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1741,13 +1741,7 @@ sub process { } } elsif ($line =~ /^\+\+\+\s+(\S+)/) { $realfile = $1; - $realfile =~ s@^([^/]*)/@@ if (!$file); - - $p1_prefix = $1; - if (!$file && $tree && $p1_prefix ne '' && - -e "$root/$p1_prefix") { - WARN("patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n"); - } + $realfile =~ s@^[^/]*/@@ if (!$file); if (defined $fileinfo && !$fileinfo->{isgit}) { $fileinfo->{lineend} = $oldhere; From 56dbf087a8a2cec7e3aeb19defed2a19efc85faa Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 10 Oct 2025 14:25:08 +0200 Subject: [PATCH 2/8] rust/util: add ensure macro The macro is similar to anyhow::ensure but uses QEMU's variation on anyhow::Error. It can be used to easily check a condition and format an error message. Reviewed-by: Zhao Liu Signed-off-by: Paolo Bonzini --- rust/hw/timer/hpet/src/device.rs | 21 ++++++---- rust/hw/timer/hpet/src/fw_cfg.rs | 7 ++-- rust/util/src/error.rs | 71 ++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 13 deletions(-) diff --git a/rust/hw/timer/hpet/src/device.rs b/rust/hw/timer/hpet/src/device.rs index 23f2eefd1c..3564aa79c6 100644 --- a/rust/hw/timer/hpet/src/device.rs +++ b/rust/hw/timer/hpet/src/device.rs @@ -25,7 +25,10 @@ use system::{ bindings::{address_space_memory, address_space_stl_le, hwaddr}, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder, MEMTXATTRS_UNSPECIFIED, }; -use util::timer::{Timer, CLOCK_VIRTUAL, NANOSECONDS_PER_SECOND}; +use util::{ + ensure, + timer::{Timer, CLOCK_VIRTUAL, NANOSECONDS_PER_SECOND}, +}; use crate::fw_cfg::HPETFwConfig; @@ -728,14 +731,14 @@ impl HPETState { } fn realize(&self) -> util::Result<()> { - if self.num_timers < HPET_MIN_TIMERS || self.num_timers > HPET_MAX_TIMERS { - Err(format!( - "hpet.num_timers must be between {HPET_MIN_TIMERS} and {HPET_MAX_TIMERS}" - ))?; - } - if self.int_route_cap == 0 { - Err("hpet.hpet-intcap property not initialized")?; - } + ensure!( + (HPET_MIN_TIMERS..=HPET_MAX_TIMERS).contains(&self.num_timers), + "hpet.num_timers must be between {HPET_MIN_TIMERS} and {HPET_MAX_TIMERS}" + ); + ensure!( + self.int_route_cap != 0, + "hpet.hpet-intcap property not initialized" + ); self.hpet_id.set(HPETFwConfig::assign_hpet_id()?); diff --git a/rust/hw/timer/hpet/src/fw_cfg.rs b/rust/hw/timer/hpet/src/fw_cfg.rs index bb4ea8909a..777fc8ef45 100644 --- a/rust/hw/timer/hpet/src/fw_cfg.rs +++ b/rust/hw/timer/hpet/src/fw_cfg.rs @@ -5,6 +5,7 @@ use std::ptr::addr_of_mut; use common::Zeroable; +use util::{self, ensure}; /// Each `HPETState` represents a Event Timer Block. The v1 spec supports /// up to 8 blocks. QEMU only uses 1 block (in PC machine). @@ -36,7 +37,7 @@ pub static mut hpet_fw_cfg: HPETFwConfig = HPETFwConfig { }; impl HPETFwConfig { - pub(crate) fn assign_hpet_id() -> Result { + pub(crate) fn assign_hpet_id() -> util::Result { assert!(bql::is_locked()); // SAFETY: all accesses go through these methods, which guarantee // that the accesses are protected by the BQL. @@ -47,9 +48,7 @@ impl HPETFwConfig { fw_cfg.count = 0; } - if fw_cfg.count == 8 { - Err("Only 8 instances of HPET are allowed")?; - } + ensure!(fw_cfg.count != 8, "Only 8 instances of HPET are allowed"); let id: usize = fw_cfg.count.into(); fw_cfg.count += 1; diff --git a/rust/util/src/error.rs b/rust/util/src/error.rs index bfa5a8685b..2a57c7fd5f 100644 --- a/rust/util/src/error.rs +++ b/rust/util/src/error.rs @@ -86,6 +86,19 @@ impl Display for Error { } } +impl From> for Error { + #[track_caller] + fn from(msg: Cow<'static, str>) -> Self { + let location = panic::Location::caller(); + Error { + msg: Some(msg), + cause: None, + file: location.file(), + line: location.line(), + } + } +} + impl From for Error { #[track_caller] fn from(msg: String) -> Self { @@ -126,6 +139,17 @@ impl From for Error { } impl Error { + #[track_caller] + #[doc(hidden)] + pub fn format(args: fmt::Arguments) -> Self { + if let Some(msg) = args.as_str() { + Self::from(msg) + } else { + let msg = fmt::format(args); + Self::from(msg) + } + } + /// Create a new error, prepending `msg` to the /// description of `cause` #[track_caller] @@ -311,6 +335,53 @@ impl FromForeign for Error { } } +/// Ensure that a condition is true, returning an error if it is false. +/// +/// This macro is similar to [`anyhow::ensure`] but returns a QEMU [`Result`]. +/// If the condition evaluates to `false`, the macro returns early with an error +/// constructed from the provided message. +/// +/// # Examples +/// +/// ``` +/// # use util::{ensure, Result}; +/// # fn check_positive(x: i32) -> Result<()> { +/// ensure!(x > 0, "value must be positive"); +/// # Ok(()) +/// # } +/// ``` +/// +/// ``` +/// # use util::{ensure, Result}; +/// # const MIN: i32 = 123; +/// # const MAX: i32 = 456; +/// # fn check_range(x: i32) -> Result<()> { +/// ensure!( +/// x >= MIN && x <= MAX, +/// "{} not between {} and {}", +/// x, +/// MIN, +/// MAX +/// ); +/// # Ok(()) +/// # } +/// ``` +#[macro_export] +macro_rules! ensure { + ($cond:expr, $fmt:literal, $($arg:tt)*) => { + if !$cond { + let e = $crate::Error::format(format_args!($fmt, $($arg)*)); + return $crate::Result::Err(e); + } + }; + ($cond:expr, $err:expr $(,)?) => { + if !$cond { + let s = ::std::borrow::Cow::<'static, str>::from($err); + return $crate::Result::Err(s.into()); + } + }; +} + #[cfg(test)] mod tests { use std::ffi::CStr; From 0830ec94059b239b3f67527b58e52fa7cd4a5439 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 10 Oct 2025 18:17:59 +0200 Subject: [PATCH 3/8] rust/util: use anyhow's native chaining capabilities This simplifies conversions, making it possible to convert any error into a QEMU util::Error with ".into()" (and therefore with "?"). The cost is having a separate constructor for when the error is a simple string, but that is made easier by the ensure! macro. If necessary, another macro similar to "anyhow!" can be returned, but for now there is no need for that. Reviewed-by: Zhao Liu Signed-off-by: Paolo Bonzini --- rust/util/src/error.rs | 160 +++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 101 deletions(-) diff --git a/rust/util/src/error.rs b/rust/util/src/error.rs index 2a57c7fd5f..11b574ca59 100644 --- a/rust/util/src/error.rs +++ b/rust/util/src/error.rs @@ -38,6 +38,7 @@ use std::{ borrow::Cow, ffi::{c_char, c_int, c_void, CStr}, fmt::{self, Display}, + ops::Deref, panic, ptr, }; @@ -49,118 +50,85 @@ pub type Result = std::result::Result; #[derive(Debug)] pub struct Error { - msg: Option>, - /// Appends the print string of the error to the msg if not None - cause: Option, + cause: anyhow::Error, file: &'static str, line: u32, } -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - self.cause.as_ref().map(AsRef::as_ref) - } +impl Deref for Error { + type Target = anyhow::Error; - #[allow(deprecated)] - fn description(&self) -> &str { - self.msg - .as_deref() - .or_else(|| self.cause.as_deref().map(std::error::Error::description)) - .expect("no message nor cause?") + fn deref(&self) -> &Self::Target { + &self.cause } } impl Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut prefix = ""; - if let Some(ref msg) = self.msg { - write!(f, "{msg}")?; - prefix = ": "; - } - if let Some(ref cause) = self.cause { - write!(f, "{prefix}{cause}")?; - } else if prefix.is_empty() { - panic!("no message nor cause?"); - } - Ok(()) + Display::fmt(&format_args!("{:#}", self.cause), f) } } -impl From> for Error { +impl From for Error +where + anyhow::Error: From, +{ #[track_caller] - fn from(msg: Cow<'static, str>) -> Self { - let location = panic::Location::caller(); - Error { - msg: Some(msg), - cause: None, - file: location.file(), - line: location.line(), - } - } -} - -impl From for Error { - #[track_caller] - fn from(msg: String) -> Self { - let location = panic::Location::caller(); - Error { - msg: Some(Cow::Owned(msg)), - cause: None, - file: location.file(), - line: location.line(), - } - } -} - -impl From<&'static str> for Error { - #[track_caller] - fn from(msg: &'static str) -> Self { - let location = panic::Location::caller(); - Error { - msg: Some(Cow::Borrowed(msg)), - cause: None, - file: location.file(), - line: location.line(), - } - } -} - -impl From for Error { - #[track_caller] - fn from(error: anyhow::Error) -> Self { - let location = panic::Location::caller(); - Error { - msg: None, - cause: Some(error), - file: location.file(), - line: location.line(), - } + fn from(src: E) -> Self { + Self::new(anyhow::Error::from(src)) } } impl Error { + /// Create a new error from an [`anyhow::Error`]. + /// + /// This wraps the error with QEMU's location tracking information. + /// Most code should use the `?` operator instead of calling this directly. + #[track_caller] + pub fn new(cause: anyhow::Error) -> Self { + let location = panic::Location::caller(); + Self { + cause, + file: location.file(), + line: location.line(), + } + } + + /// Create a new error from a string message. + /// + /// This is a convenience wrapper around [`Error::new`] for simple string + /// errors. Most code should use the [`ensure!`](crate::ensure) macro + /// instead of calling this directly. + #[track_caller] + pub fn msg(src: impl Into>) -> Self { + Self::new(anyhow::Error::msg(src.into())) + } + #[track_caller] #[doc(hidden)] + #[inline(always)] pub fn format(args: fmt::Arguments) -> Self { - if let Some(msg) = args.as_str() { - Self::from(msg) - } else { - let msg = fmt::format(args); - Self::from(msg) - } + // anyhow::Error::msg will allocate anyway, might as well let fmt::format doit. + let msg = fmt::format(args); + Self::new(anyhow::Error::msg(msg)) } /// Create a new error, prepending `msg` to the /// description of `cause` #[track_caller] pub fn with_error(msg: impl Into>, cause: impl Into) -> Self { - let location = panic::Location::caller(); - Error { - msg: Some(msg.into()), - cause: Some(cause.into()), - file: location.file(), - line: location.line(), + fn do_with_error( + msg: Cow<'static, str>, + cause: anyhow::Error, + location: &'static panic::Location<'static>, + ) -> Error { + Error { + cause: cause.context(msg), + file: location.file(), + line: location.line(), + } } + do_with_error(msg.into(), cause.into(), panic::Location::caller()) } /// Consume a result, returning `false` if it is an error and @@ -326,8 +294,7 @@ impl FromForeign for Error { }; Error { - msg: FromForeign::cloned_from_foreign(error.msg), - cause: None, + cause: anyhow::Error::msg(String::cloned_from_foreign(error.msg)), file: file.unwrap(), line: error.line as u32, } @@ -376,8 +343,8 @@ macro_rules! ensure { }; ($cond:expr, $err:expr $(,)?) => { if !$cond { - let s = ::std::borrow::Cow::<'static, str>::from($err); - return $crate::Result::Err(s.into()); + let e = $crate::Error::msg($err); + return $crate::Result::Err(e); } }; } @@ -416,19 +383,10 @@ mod tests { unsafe { CStr::from_ptr(bindings::error_get_pretty(local_err)) } } - #[test] - #[allow(deprecated)] - fn test_description() { - use std::error::Error; - - assert_eq!(super::Error::from("msg").description(), "msg"); - assert_eq!(super::Error::from("msg".to_owned()).description(), "msg"); - } - #[test] fn test_display() { - assert_eq!(&*format!("{}", Error::from("msg")), "msg"); - assert_eq!(&*format!("{}", Error::from("msg".to_owned())), "msg"); + assert_eq!(&*format!("{}", Error::msg("msg")), "msg"); + assert_eq!(&*format!("{}", Error::msg("msg".to_owned())), "msg"); assert_eq!(&*format!("{}", Error::from(anyhow!("msg"))), "msg"); assert_eq!( @@ -445,7 +403,7 @@ mod tests { assert!(Error::bool_or_propagate(Ok(()), &mut local_err)); assert_eq!(local_err, ptr::null_mut()); - let my_err = Error::from("msg"); + let my_err = Error::msg("msg"); assert!(!Error::bool_or_propagate(Err(my_err), &mut local_err)); assert_ne!(local_err, ptr::null_mut()); assert_eq!(error_get_pretty(local_err), c"msg"); @@ -462,7 +420,7 @@ mod tests { assert_eq!(String::from_foreign(ret), "abc"); assert_eq!(local_err, ptr::null_mut()); - let my_err = Error::from("msg"); + let my_err = Error::msg("msg"); assert_eq!( Error::ptr_or_propagate(Err::(my_err), &mut local_err), ptr::null_mut() From 113a7f5bf3b0bea56e8961c63fe7e6abec32f53d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 19 Sep 2025 13:59:27 +0200 Subject: [PATCH 4/8] rust/util: replace Error::err_or_unit/err_or_else with Error::with_errp Introduce a simpler function that hides the creation of the Error**. Reviewed-by: Zhao Liu Signed-off-by: Paolo Bonzini --- rust/util/src/error.rs | 52 ++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/rust/util/src/error.rs b/rust/util/src/error.rs index 11b574ca59..346577e2e5 100644 --- a/rust/util/src/error.rs +++ b/rust/util/src/error.rs @@ -14,8 +14,7 @@ //! [`ptr_or_propagate`](crate::Error::ptr_or_propagate) can be used to build //! a C return value while also propagating an error condition //! -//! * [`err_or_else`](crate::Error::err_or_else) and -//! [`err_or_unit`](crate::Error::err_or_unit) can be used to build a `Result` +//! * [`with_errp`](crate::Error::with_errp) can be used to build a `Result` //! //! This module is most commonly used at the boundary between C and Rust code; //! other code will usually access it through the @@ -213,35 +212,21 @@ impl Error { } } - /// Convert a C `Error*` into a Rust `Result`, using - /// `Ok(())` if `c_error` is NULL. Free the `Error*`. + /// Pass a C `Error*` to the closure, and convert the result + /// (either the return value of the closure, or the error) + /// into a Rust `Result`. /// /// # Safety /// - /// `c_error` must be `NULL` or valid; typically it was initialized - /// with `ptr::null_mut()` and passed by reference to a C function. - pub unsafe fn err_or_unit(c_error: *mut bindings::Error) -> Result<()> { - // SAFETY: caller guarantees c_error is valid - unsafe { Self::err_or_else(c_error, || ()) } - } + /// One exit from `f`, `c_error` must be unchanged or point to a + /// valid C [`struct Error`](bindings::Error). + pub unsafe fn with_errp T>(f: F) -> Result { + let mut c_error: *mut bindings::Error = ptr::null_mut(); - /// Convert a C `Error*` into a Rust `Result`, calling `f()` to - /// obtain an `Ok` value if `c_error` is NULL. Free the `Error*`. - /// - /// # Safety - /// - /// `c_error` must be `NULL` or point to a valid C [`struct - /// Error`](bindings::Error); typically it was initialized with - /// `ptr::null_mut()` and passed by reference to a C function. - pub unsafe fn err_or_else T>( - c_error: *mut bindings::Error, - f: F, - ) -> Result { - // SAFETY: caller guarantees c_error is valid - let err = unsafe { Option::::from_foreign(c_error) }; - match err { - None => Ok(f()), - Some(err) => Err(err), + // SAFETY: guaranteed by the postcondition of `f` + match (f(&mut c_error), unsafe { c_error.into_native() }) { + (result, None) => Ok(result), + (_, Some(err)) => Err(err), } } } @@ -432,13 +417,16 @@ mod tests { } #[test] - fn test_err_or_unit() { + fn test_with_errp() { unsafe { - let result = Error::err_or_unit(ptr::null_mut()); - assert_match!(result, Ok(())); + let result = Error::with_errp(|_errp| true); + assert_match!(result, Ok(true)); - let err = error_for_test(c"msg"); - let err = Error::err_or_unit(err.into_inner()).unwrap_err(); + let err = Error::with_errp(|errp| { + *errp = error_for_test(c"msg").into_inner(); + false + }) + .unwrap_err(); assert_eq!(&*format!("{err}"), "msg"); } } From 8abea41ecd9fe5614f39226c04600b177eb94b52 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 7 Oct 2025 17:13:43 +0200 Subject: [PATCH 5/8] rust: pull error_fatal out of SysbusDeviceMethods::sysbus_realize Return a Result<()> from the method, and "unwrap" it into error_fatal in the caller. Reviewed-by: Zhao Liu Signed-off-by: Paolo Bonzini --- rust/hw/char/pl011/src/device.rs | 4 ++-- rust/hw/core/src/sysbus.rs | 13 ++++++------- rust/util/src/error.rs | 31 ++++++++++++++++++++++++++++++- rust/util/src/lib.rs | 2 +- 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs index 5e9b13fdf9..04155dabe1 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -17,7 +17,7 @@ use migration::{ }; use qom::{prelude::*, ObjectImpl, Owned, ParentField, ParentInit}; use system::{hwaddr, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder}; -use util::{log::Log, log_mask_ln}; +use util::{log::Log, log_mask_ln, ResultExt}; use crate::registers::{self, Interrupt, RegisterOffset}; @@ -697,7 +697,7 @@ pub unsafe extern "C" fn pl011_create( let chr = unsafe { Owned::::from(&*chr) }; dev.prop_set_chr("chardev", &chr); } - dev.sysbus_realize(); + dev.sysbus_realize().unwrap_fatal(); dev.mmio_map(0, addr); dev.connect_irq(0, &irq); diff --git a/rust/hw/core/src/sysbus.rs b/rust/hw/core/src/sysbus.rs index 282315fce9..68165e8929 100644 --- a/rust/hw/core/src/sysbus.rs +++ b/rust/hw/core/src/sysbus.rs @@ -4,12 +4,13 @@ //! Bindings to access `sysbus` functionality from Rust. -use std::{ffi::CStr, ptr::addr_of_mut}; +use std::ffi::CStr; pub use bindings::SysBusDeviceClass; use common::Opaque; use qom::{prelude::*, Owned}; use system::MemoryRegion; +use util::{Error, Result}; use crate::{ bindings, @@ -107,14 +108,12 @@ where } } - fn sysbus_realize(&self) { - // TODO: return an Error + fn sysbus_realize(&self) -> Result<()> { assert!(bql::is_locked()); unsafe { - bindings::sysbus_realize( - self.upcast().as_mut_ptr(), - addr_of_mut!(util::bindings::error_fatal), - ); + Error::with_errp(|errp| { + bindings::sysbus_realize(self.upcast().as_mut_ptr(), errp); + }) } } } diff --git a/rust/util/src/error.rs b/rust/util/src/error.rs index 346577e2e5..4edceff42f 100644 --- a/rust/util/src/error.rs +++ b/rust/util/src/error.rs @@ -38,7 +38,8 @@ use std::{ ffi::{c_char, c_int, c_void, CStr}, fmt::{self, Display}, ops::Deref, - panic, ptr, + panic, + ptr::{self, addr_of_mut}, }; use foreign::{prelude::*, OwnedPointer}; @@ -231,6 +232,34 @@ impl Error { } } +/// Extension trait for `std::result::Result`, providing extra +/// methods when the error type can be converted into a QEMU +/// Error. +pub trait ResultExt { + /// The success type `T` in `Result`. + type OkType; + + /// Report a fatal error and exit QEMU, or return the success value. + /// Note that, unlike [`unwrap()`](std::result::Result::unwrap), this + /// is not an abort and can be used for user errors. + fn unwrap_fatal(self) -> Self::OkType; +} + +impl ResultExt for std::result::Result +where + Error: From, +{ + type OkType = T; + + fn unwrap_fatal(self) -> T { + // SAFETY: errp is valid + self.map_err(|err| unsafe { + Error::from(err).propagate(addr_of_mut!(bindings::error_fatal)) + }) + .unwrap() + } +} + impl FreeForeign for Error { type Foreign = bindings::Error; diff --git a/rust/util/src/lib.rs b/rust/util/src/lib.rs index 16c89b9517..d14aa14ca7 100644 --- a/rust/util/src/lib.rs +++ b/rust/util/src/lib.rs @@ -6,4 +6,4 @@ pub mod log; pub mod module; pub mod timer; -pub use error::{Error, Result}; +pub use error::{Error, Result, ResultExt}; From 02d6b8cfd30b2da0a58a67206e9e48119b815731 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 3 Oct 2025 14:31:13 +0200 Subject: [PATCH 6/8] rust: do not add qemuutil to Rust crates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fails due to https://github.com/mesonbuild/meson/pull/15076. The config-host.h file from the qemuutil dependency ends up on the rustc command line for targets that do not use structured sources. It will be reverted once Meson 1.9.2 is released. Reported-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- rust/chardev/meson.build | 2 +- rust/util/meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/chardev/meson.build b/rust/chardev/meson.build index d365d8dd0f..36ada7c454 100644 --- a/rust/chardev/meson.build +++ b/rust/chardev/meson.build @@ -39,4 +39,4 @@ _chardev_rs = static_library( dependencies: [glib_sys_rs, common_rs, qemu_macros], ) -chardev_rs = declare_dependency(link_with: [_chardev_rs], dependencies: [chardev, qemuutil]) +chardev_rs = declare_dependency(link_with: [_chardev_rs], dependencies: [chardev]) diff --git a/rust/util/meson.build b/rust/util/meson.build index b0b75e93ff..8ad344dccb 100644 --- a/rust/util/meson.build +++ b/rust/util/meson.build @@ -43,7 +43,7 @@ _util_rs = static_library( dependencies: [anyhow_rs, libc_rs, foreign_rs, glib_sys_rs, common_rs, qom, qemuutil], ) -util_rs = declare_dependency(link_with: [_util_rs], dependencies: [qemuutil, qom]) +util_rs = declare_dependency(link_with: [_util_rs]) rust.test('rust-util-tests', _util_rs, dependencies: [qemuutil, qom], From ac561a3050aa642571735332e22d96334be083cf Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 21 Dec 2024 16:53:29 +0100 Subject: [PATCH 7/8] rust: migration: allow nested offset_of Nested offset_of was stabilized in Rust 1.82. Since the minimum supported version for QEMU is 1.83, allow nested field accesses in vmstate_of! Signed-off-by: Paolo Bonzini --- rust/migration/src/vmstate.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rust/migration/src/vmstate.rs b/rust/migration/src/vmstate.rs index 5a237c409a..267f9c8e05 100644 --- a/rust/migration/src/vmstate.rs +++ b/rust/migration/src/vmstate.rs @@ -141,24 +141,24 @@ pub const fn vmstate_varray_flag(_: PhantomData) -> VMStateFlags /// [`Owned`]: ../../qom/qom/struct.Owned.html #[macro_export] macro_rules! vmstate_of { - ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])? $(, $test_fn:expr)? $(,)?) => { + ($struct_name:ty, $($field_name:ident).+ $([0 .. $($num:ident).+ $(* $factor:expr)?])? $(, $test_fn:expr)? $(,)?) => { $crate::bindings::VMStateField { - name: ::core::concat!(::core::stringify!($field_name), "\0") + name: ::core::concat!(::core::stringify!($($field_name).+), "\0") .as_bytes() .as_ptr().cast::<::std::os::raw::c_char>(), - offset: ::std::mem::offset_of!($struct_name, $field_name), - $(num_offset: ::std::mem::offset_of!($struct_name, $num),)? + offset: ::std::mem::offset_of!($struct_name, $($field_name).+), + $(num_offset: ::std::mem::offset_of!($struct_name, $($num).+),)? $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)? // The calls to `call_func_with_field!` are the magic that // computes most of the VMStateField from the type of the field. ..$crate::call_func_with_field!( $crate::vmstate::vmstate_base, $struct_name, - $field_name + $($field_name).+ )$(.with_varray_flag($crate::call_func_with_field!( $crate::vmstate::vmstate_varray_flag, $struct_name, - $num)) + $($num).+)) $(.with_varray_multiply($factor))?)? } }; From fdeeb448458f0ed808a62314b57974ab16d3592e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 31 Oct 2025 14:24:18 +0100 Subject: [PATCH 8/8] rust: add back to Ubuntu 22.04 jobs Ubuntu is now including updated versions of Rust (up to 1.85) for its LTS releases. Adjust the CI containers and re-add --enable-rust to the Ubuntu jobs. Signed-off-by: Paolo Bonzini --- .gitlab-ci.d/buildtest.yml | 2 +- docs/about/build-platforms.rst | 10 +++++----- scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml | 2 +- scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml | 2 +- tests/docker/dockerfiles/ubuntu2204.docker | 6 +++--- tests/lcitool/mappings.yml | 4 ++-- tests/lcitool/refresh | 4 ++-- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index 21f6d7e96f..44df116139 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -39,7 +39,7 @@ build-system-ubuntu: - job: amd64-ubuntu2204-container variables: IMAGE: ubuntu2204 - CONFIGURE_ARGS: --enable-docs + CONFIGURE_ARGS: --enable-docs --enable-rust TARGETS: alpha-softmmu microblazeel-softmmu mips64el-softmmu MAKE_CHECK_ARGS: check-build diff --git a/docs/about/build-platforms.rst b/docs/about/build-platforms.rst index fc2743658d..e95784cdb5 100644 --- a/docs/about/build-platforms.rst +++ b/docs/about/build-platforms.rst @@ -117,14 +117,14 @@ Rust build dependencies a newer version using ``cargo install bindgen-cli``. QEMU requires Rust 1.83.0. This is available on all supported platforms - with two exception: Ubuntu LTS releases 22.04 and 24.04, and the - ``mips64el`` architecture on Debian bookworm. For all other + except for the ``mips64el`` architecture on Debian bookworm. For all other architectures, Debian bookworm provides a new-enough Rust compiler in the ``rustc-web`` package. - It is expected that in the future Ubuntu will provide updated packages - like the existing ``rustc-1.82`` package. The path to ``rustc`` and - ``rustdoc`` will have to be provided manually to the configure script. + For Ubuntu 22.04 ("Jammy") and 24.04 ("Noble") updated versions of + Rust are available through packages such as ``rustc-1.83`` package; + the path to ``rustc`` and ``rustdoc`` has to be provided manually to + the configure script. Some distros prefer to avoid vendored crate sources, and instead use local sources from e.g. ``/usr/share/cargo/registry``. QEMU includes a diff --git a/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml b/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml index 70063db198..d303411391 100644 --- a/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml +++ b/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml @@ -119,7 +119,7 @@ packages: - python3-wheel - python3-yaml - rpm2cpio - - rustc-1.77 + - rustc-1.83 - sed - socat - sparse diff --git a/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml b/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml index 4f1a49be34..4ee8630cc4 100644 --- a/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml +++ b/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml @@ -117,7 +117,7 @@ packages: - python3-wheel - python3-yaml - rpm2cpio - - rustc-1.77 + - rustc-1.83 - sed - socat - sparse diff --git a/tests/docker/dockerfiles/ubuntu2204.docker b/tests/docker/dockerfiles/ubuntu2204.docker index b393db55a8..602d419624 100644 --- a/tests/docker/dockerfiles/ubuntu2204.docker +++ b/tests/docker/dockerfiles/ubuntu2204.docker @@ -124,7 +124,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-wheel \ python3-yaml \ rpm2cpio \ - rustc-1.77 \ + rustc-1.83 \ sed \ socat \ sparse \ @@ -155,8 +155,8 @@ ENV LANG "en_US.UTF-8" ENV MAKE "/usr/bin/make" ENV NINJA "/usr/bin/ninja" ENV PYTHON "/usr/bin/python3" -ENV RUSTC=/usr/bin/rustc-1.77 -ENV RUSTDOC=/usr/bin/rustdoc-1.77 +ENV RUSTC=/usr/bin/rustc-1.83 +ENV RUSTDOC=/usr/bin/rustdoc-1.83 ENV CARGO_HOME=/usr/local/cargo ENV PATH=$CARGO_HOME/bin:$PATH RUN DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/lcitool/mappings.yml b/tests/lcitool/mappings.yml index 8f0e95e1c5..a749cf8c51 100644 --- a/tests/lcitool/mappings.yml +++ b/tests/lcitool/mappings.yml @@ -70,8 +70,8 @@ mappings: rust: Debian12: rustc-web - Ubuntu2204: rustc-1.77 - Ubuntu2404: rustc-1.77 + Ubuntu2204: rustc-1.83 + Ubuntu2404: rustc-1.83 pypi_mappings: # Request more recent version diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh index 7fbdf6f340..df186caffe 100755 --- a/tests/lcitool/refresh +++ b/tests/lcitool/refresh @@ -152,8 +152,8 @@ fedora_rustup_nightly_extras = [ ] ubuntu2204_rust_extras = [ - "ENV RUSTC=/usr/bin/rustc-1.77\n", - "ENV RUSTDOC=/usr/bin/rustdoc-1.77\n", + "ENV RUSTC=/usr/bin/rustc-1.83\n", + "ENV RUSTDOC=/usr/bin/rustdoc-1.83\n", "ENV CARGO_HOME=/usr/local/cargo\n", 'ENV PATH=$CARGO_HOME/bin:$PATH\n', "RUN DEBIAN_FRONTEND=noninteractive eatmydata \\\n",