new file mode 100644
@@ -0,0 +1,46 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2024 Linaro Ltd.
+ *
+ * Authors: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+/*
+ * This header file is meant to be used as input to the `bindgen` application
+ * in order to generate C FFI compatible Rust bindings.
+ */
+
+/* The system emulator has all of the bindings tools have */
+#include "wrapper.h"
+
+#include "exec/address-spaces.h"
+#include "exec/memattrs.h"
+#include "exec/memory.h"
+#include "hw/clock.h"
+#include "hw/irq.h"
+#include "hw/qdev-clock.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
+#include "hw/sysbus.h"
+#include "migration/vmstate.h"
+#include "system/system.h"
@@ -50,18 +50,7 @@ typedef enum memory_order {
#include "qemu/osdep.h"
#include "qemu/module.h"
#include "qemu-io.h"
-#include "system/system.h"
-#include "hw/sysbus.h"
-#include "exec/memory.h"
#include "chardev/char-fe.h"
-#include "hw/clock.h"
-#include "hw/qdev-clock.h"
-#include "hw/qdev-properties.h"
-#include "hw/qdev-properties-system.h"
-#include "hw/irq.h"
#include "qapi/error.h"
-#include "migration/vmstate.h"
#include "chardev/char-serial.h"
-#include "exec/memattrs.h"
#include "qemu/timer.h"
-#include "exec/address-spaces.h"
@@ -4102,10 +4102,17 @@ if have_rust
# this case you must pass the path to `clang` and `libclang` to your build
# command invocation using the environment variables CLANG_PATH and
# LIBCLANG_PATH
- bindings_rs = rust.bindgen(
+ bindings_rs_tools = rust.bindgen(
input: 'rust/wrapper.h',
+ output: 'bindings_tools.inc.rs',
+ include_directories: include_directories('.', 'include'),
+ bindgen_version: ['>=0.60.0'],
+ args: bindgen_args,
+ )
+ bindings_rs_system = rust.bindgen(
+ input: 'rust/wrapper-system.h',
dependencies: common_ss.all_dependencies(),
- output: 'bindings.inc.rs',
+ output: 'bindings_system.inc.rs',
include_directories: include_directories('.', 'include'),
bindgen_version: ['>=0.60.0'],
args: bindgen_args,
@@ -12,9 +12,10 @@ _libpl011_rs = static_library(
dependencies: [
bilge_dep,
bilge_impl_dep,
- qemu_api,
+ qemu_api_system,
qemu_api_macros,
],
+ rust_dependency_map: {'qemu_api_system': 'qemu_api'},
)
rust_devices_ss.add(when: 'CONFIG_X_PL011_RUST', if_true: [declare_dependency(
@@ -4,9 +4,10 @@ _libhpet_rs = static_library(
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_abi: 'rust',
dependencies: [
- qemu_api,
+ qemu_api_system,
qemu_api_macros,
],
+ rust_dependency_map: {'qemu_api_system': 'qemu_api'},
)
rust_devices_ss.add(when: 'CONFIG_X_HPET_RUST', if_true: [declare_dependency(
@@ -9,18 +9,19 @@ if cargo.found()
run_target('clippy',
command: [config_host['MESON'], 'devenv',
'--workdir', '@CURRENT_SOURCE_DIR@',
- cargo, 'clippy', '--tests'],
- depends: bindings_rs)
+ cargo, 'clippy', '--tests', '--features', 'system'],
+ depends: bindings_rs_system)
run_target('rustfmt',
command: [config_host['MESON'], 'devenv',
'--workdir', '@CURRENT_SOURCE_DIR@',
cargo, 'fmt'],
- depends: bindings_rs)
+ depends: bindings_rs_system)
run_target('rustdoc',
command: [config_host['MESON'], 'devenv',
'--workdir', '@CURRENT_SOURCE_DIR@',
- cargo, 'doc', '--no-deps', '--document-private-items'],
- depends: bindings_rs)
+ cargo, 'doc', '--no-deps', '--document-private-items',
+ '--features', 'system'],
+ depends: bindings_rs_system)
endif
@@ -25,6 +25,7 @@ version_check = "~0.9"
default = ["debug_cell"]
allocator = []
debug_cell = []
+system= []
[lints]
workspace = true
@@ -16,7 +16,13 @@ fn main() -> Result<()> {
let path = env::var("MESON_BUILD_ROOT")
.unwrap_or_else(|_| format!("{}/src", env!("CARGO_MANIFEST_DIR")));
- let file = format!("{}/bindings.inc.rs", path);
+ let basename = if cfg!(feature = "system") {
+ "bindings_system.inc.rs"
+ } else {
+ "bindings_tools.inc.rs"
+ };
+
+ let file = format!("{}/{}", path, basename);
let file = Path::new(&file);
if !Path::new(&file).exists() {
panic!(concat!(
@@ -31,7 +37,7 @@ fn main() -> Result<()> {
}
let out_dir = env::var("OUT_DIR").unwrap();
- let dest_path = format!("{}/bindings.inc.rs", out_dir);
+ let dest_path = format!("{}/{}", out_dir, basename);
let dest_path = Path::new(&dest_path);
if dest_path.symlink_metadata().is_ok() {
remove_file(dest_path)?;
@@ -12,44 +12,64 @@ if get_option('debug_mutex')
_qemu_api_cfg += ['--cfg', 'feature="debug_cell"']
endif
-_qemu_api_rs = static_library(
- 'qemu_api',
+sources_core = [
+ 'src/lib.rs',
+ 'src/assertions.rs',
+ 'src/bindings.rs',
+ 'src/bitops.rs',
+ 'src/callbacks.rs',
+ 'src/cell.rs',
+ 'src/chardev.rs',
+ 'src/c_str.rs',
+ 'src/errno.rs',
+ 'src/module.rs',
+ 'src/offset_of.rs',
+ 'src/prelude.rs',
+ 'src/qom.rs',
+ 'src/timer.rs',
+ 'src/zeroable.rs',
+]
+sources_system = sources_core + [
+ 'src/irq.rs',
+ 'src/memory.rs',
+ 'src/qdev.rs',
+ 'src/sysbus.rs',
+ 'src/vmstate.rs',
+]
+
+
+_qemu_api_tools_rs = static_library(
+ 'qemu_api_tools',
structured_sources(
- [
- 'src/lib.rs',
- 'src/assertions.rs',
- 'src/bindings.rs',
- 'src/bitops.rs',
- 'src/callbacks.rs',
- 'src/cell.rs',
- 'src/chardev.rs',
- 'src/c_str.rs',
- 'src/errno.rs',
- 'src/irq.rs',
- 'src/memory.rs',
- 'src/module.rs',
- 'src/offset_of.rs',
- 'src/prelude.rs',
- 'src/qdev.rs',
- 'src/qom.rs',
- 'src/sysbus.rs',
- 'src/timer.rs',
- 'src/vmstate.rs',
- 'src/zeroable.rs',
- ],
- {'.' : bindings_rs},
+ sources_core,
+ {'.' : bindings_rs_tools},
),
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_abi: 'rust',
rust_args: _qemu_api_cfg,
dependencies: libc_dep,
)
+_qemu_api_system_rs = static_library(
+ 'qemu_api_system',
+ structured_sources(
+ sources_system,
+ {'.' : bindings_rs_system},
+ ),
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_abi: 'rust',
+ rust_args: _qemu_api_cfg + ['--cfg', 'feature="system"'],
+ dependencies: libc_dep,
+)
-rust.test('rust-qemu-api-tests', _qemu_api_rs,
+rust.test('rust-qemu-api-tests', _qemu_api_system_rs,
suite: ['unit', 'rust'])
-qemu_api = declare_dependency(
- link_with: _qemu_api_rs,
+qemu_api_tools = declare_dependency(
+ link_with: _qemu_api_tools_rs,
+ dependencies: qemu_api_macros,
+)
+qemu_api_system = declare_dependency(
+ link_with: _qemu_api_system_rs,
dependencies: qemu_api_macros,
)
@@ -66,7 +86,8 @@ test('rust-qemu-api-integration',
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_args: ['--test'],
install: false,
- dependencies: [qemu_api, qemu_api_macros],
+ dependencies: [qemu_api_system, qemu_api_macros],
+ rust_dependency_map: {'qemu_api_system': 'qemu_api'},
link_whole: [rust_qemu_api_objs, libqemuutil]),
args: [
'--test', '--test-threads', '1',
@@ -17,11 +17,15 @@
//! `bindgen`-generated declarations.
-#[cfg(MESON)]
-include!("bindings.inc.rs");
+#[cfg(all(MESON, not(feature="system")))]
+include!("bindings_tools.inc.rs");
+#[cfg(all(MESON, feature="system"))]
+include!("bindings_system.inc.rs");
-#[cfg(not(MESON))]
-include!(concat!(env!("OUT_DIR"), "/bindings.inc.rs"));
+#[cfg(all(not(MESON), not(feature="system")))]
+include!(concat!(env!("OUT_DIR"), "/bindings_tools.inc.rs"));
+#[cfg(all(not(MESON), feature="system"))]
+include!(concat!(env!("OUT_DIR"), "/bindings_system.inc.rs"));
// SAFETY: these are implemented in C; the bindings need to assert that the
// BQL is taken, either directly or via `BqlCell` and `BqlRefCell`.
@@ -49,29 +53,33 @@ unsafe impl Sync for ObjectClass {}
unsafe impl Send for Object {}
unsafe impl Sync for Object {}
-unsafe impl Send for SysBusDevice {}
-unsafe impl Sync for SysBusDevice {}
-
-// SAFETY: this is a pure data struct
-unsafe impl Send for CoalescedMemoryRange {}
-unsafe impl Sync for CoalescedMemoryRange {}
-
-// SAFETY: these are constants and vtables; the Send and Sync requirements
-// are deferred to the unsafe callbacks that they contain
-unsafe impl Send for MemoryRegionOps {}
-unsafe impl Sync for MemoryRegionOps {}
-
unsafe impl Send for Property {}
unsafe impl Sync for Property {}
unsafe impl Send for TypeInfo {}
unsafe impl Sync for TypeInfo {}
-unsafe impl Send for VMStateDescription {}
-unsafe impl Sync for VMStateDescription {}
+#[cfg(feature="system")]
+mod system_impls {
+ use super::*;
+
+ unsafe impl Send for SysBusDevice {}
+ unsafe impl Sync for SysBusDevice {}
+
+ // SAFETY: this is a pure data struct
+ unsafe impl Send for CoalescedMemoryRange {}
+ unsafe impl Sync for CoalescedMemoryRange {}
+
+ // SAFETY: these are constants and vtables; the Send and Sync requirements
+ // are deferred to the unsafe callbacks that they contain
+ unsafe impl Send for MemoryRegionOps {}
+ unsafe impl Sync for MemoryRegionOps {}
+
+ unsafe impl Send for VMStateDescription {}
+ unsafe impl Sync for VMStateDescription {}
-unsafe impl Send for VMStateField {}
-unsafe impl Sync for VMStateField {}
+ unsafe impl Send for VMStateField {}
+ unsafe impl Sync for VMStateField {}
-unsafe impl Send for VMStateInfo {}
-unsafe impl Sync for VMStateInfo {}
+ unsafe impl Send for VMStateInfo {}
+}
@@ -20,14 +20,19 @@
pub mod cell;
pub mod chardev;
pub mod errno;
+#[cfg(feature = "system")]
pub mod irq;
+#[cfg(feature = "system")]
pub mod memory;
pub mod module;
pub mod offset_of;
+#[cfg(feature = "system")]
pub mod qdev;
pub mod qom;
+#[cfg(feature = "system")]
pub mod sysbus;
pub mod timer;
+#[cfg(feature = "system")]
pub mod vmstate;
pub mod zeroable;
@@ -11,6 +11,7 @@
pub use crate::errno;
+#[cfg(feature="system")]
pub use crate::qdev::DeviceMethods;
pub use crate::qom::InterfaceType;
@@ -25,6 +26,8 @@
pub use crate::qom_isa;
+#[cfg(feature="system")]
pub use crate::sysbus::SysBusDeviceMethods;
+#[cfg(feature="system")]
pub use crate::vmstate::VMState;
@@ -58,6 +58,7 @@ pub unsafe trait Zeroable: Default {
/// ## Differences with `core::mem::zeroed`
///
/// `const_zero` zeroes padding bits, while `core::mem::zeroed` doesn't
+#[allow(unused)]
#[macro_export]
macro_rules! const_zero {
// This macro to produce a type-generic zero constant is taken from the
@@ -80,6 +81,7 @@ union TypeAsBytes {
}
/// A wrapper to implement the `Zeroable` trait through the `const_zero` macro.
+#[allow(unused)]
#[macro_export]
macro_rules! impl_zeroable {
($type:ty) => {
@@ -89,20 +91,23 @@ unsafe impl $crate::zeroable::Zeroable for $type {
};
}
-// bindgen does not derive Default here
-#[allow(clippy::derivable_impls)]
-impl Default for crate::bindings::VMStateFlags {
- fn default() -> Self {
- Self(0)
+#[cfg(feature = "system")]
+mod system_impls {
+ // bindgen does not derive Default here
+ #[allow(clippy::derivable_impls)]
+ impl Default for crate::bindings::VMStateFlags {
+ fn default() -> Self {
+ Self(0)
+ }
}
-}
-impl_zeroable!(crate::bindings::Property__bindgen_ty_1);
-impl_zeroable!(crate::bindings::Property);
-impl_zeroable!(crate::bindings::VMStateFlags);
-impl_zeroable!(crate::bindings::VMStateField);
-impl_zeroable!(crate::bindings::VMStateDescription);
-impl_zeroable!(crate::bindings::MemoryRegionOps__bindgen_ty_1);
-impl_zeroable!(crate::bindings::MemoryRegionOps__bindgen_ty_2);
-impl_zeroable!(crate::bindings::MemoryRegionOps);
-impl_zeroable!(crate::bindings::MemTxAttrs);
+ impl_zeroable!(crate::bindings::Property__bindgen_ty_1);
+ impl_zeroable!(crate::bindings::Property);
+ impl_zeroable!(crate::bindings::VMStateFlags);
+ impl_zeroable!(crate::bindings::VMStateField);
+ impl_zeroable!(crate::bindings::VMStateDescription);
+ impl_zeroable!(crate::bindings::MemoryRegionOps__bindgen_ty_1);
+ impl_zeroable!(crate::bindings::MemoryRegionOps__bindgen_ty_2);
+ impl_zeroable!(crate::bindings::MemoryRegionOps);
+ impl_zeroable!(crate::bindings::MemTxAttrs);
+}
The existing qemu_api library can't be linked into tools because it contains a few bindings for things that only exist in the system emulator. This adds a new "system" feature to the qemu_api crate that enables the system emulator parts in it, and build the crate twice: qemu_api_tools is the core library that can be linked into tools, and qemu_api_system is the full one for the system emulator. Unfortunately, since library names have to be unique in meson, this means that every user of the library now needs to specify a rust_dependency_map to make either qemu_api_tools or qemu_api_system show up as the qemu_api crate in Rust. Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- rust/wrapper-system.h | 46 ++++++++++++++++++++ rust/wrapper.h | 11 ----- meson.build | 11 ++++- rust/hw/char/pl011/meson.build | 3 +- rust/hw/timer/hpet/meson.build | 3 +- rust/meson.build | 11 ++--- rust/qemu-api/Cargo.toml | 1 + rust/qemu-api/build.rs | 10 ++++- rust/qemu-api/meson.build | 79 +++++++++++++++++++++------------- rust/qemu-api/src/bindings.rs | 52 ++++++++++++---------- rust/qemu-api/src/lib.rs | 5 +++ rust/qemu-api/src/prelude.rs | 3 ++ rust/qemu-api/src/zeroable.rs | 35 ++++++++------- 13 files changed, 182 insertions(+), 88 deletions(-) create mode 100644 rust/wrapper-system.h