[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC PATCH v4 2/7] rust: add bindgen step as a meson dependency
From: |
Manos Pitsidianakis |
Subject: |
[RFC PATCH v4 2/7] rust: add bindgen step as a meson dependency |
Date: |
Thu, 4 Jul 2024 15:15:38 +0300 |
Add mechanism to generate rust hw targets that depend on a custom
bindgen target for rust bindings to C.
This way bindings will be created before the rust crate is compiled.
The bindings will end up in BUILDDIR/{target}-generated.rs and have the same
name
as a target:
ninja aarch64-softmmu-generated.rs
The way the bindings are generated is:
1. All required C headers are included in a single file, in our case
rust/wrapper.h for convenience. Otherwise we'd have to provide a list
of headers every time to the bindgen tool.
2. Meson creates a generated_rs target that runs bindgen making sure
the architecture etc header dependencies are present.
3. The generated_rs target takes a list of files, type symbols,
function symbols to block from being generated. This is not necessary
for the bindings to work, but saves us time and space.
4. Meson creates rust hardware target dependencies from the rust_targets
dictionary defined in rust/meson.build.
Since we cannot declare a dependency on generated_rs before it is
declared in meson.build, the rust crate targets must be defined after
the generated_rs target for each target architecture is defined. This
way meson sets up the dependency tree properly.
5. After compiling each rust crate with the cargo_wrapper.py script,
its static library artifact is linked as a `whole-archive` with the
final binary.
Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
---
MAINTAINERS | 3 ++
meson.build | 57 ++++++++++++++++++++
rust/.gitignore | 3 ++
rust/meson.build | 112 +++++++++++++++++++++++++++++++++++++++
rust/wrapper.h | 39 ++++++++++++++
scripts/cargo_wrapper.py | 18 +++----
6 files changed, 220 insertions(+), 12 deletions(-)
create mode 100644 rust/.gitignore
create mode 100644 rust/meson.build
create mode 100644 rust/wrapper.h
diff --git a/MAINTAINERS b/MAINTAINERS
index d01bd06ab7..6e7b8207fb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4230,6 +4230,9 @@ Rust build system integration
M: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
S: Maintained
F: scripts/cargo_wrapper.py
+F: rust/meson.build
+F: rust/wrapper.h
+F: rust/.gitignore
Miscellaneous
-------------
diff --git a/meson.build b/meson.build
index 11b8b146da..71011fd3b3 100644
--- a/meson.build
+++ b/meson.build
@@ -3929,6 +3929,63 @@ foreach target : target_dirs
lib_deps += dep.partial_dependency(compile_args: true, includes: true)
endforeach
+ if with_rust and target_type == 'system'
+ # FIXME: meson outputs the following warnings, which should be resolved
+ # before merging:
+ # > WARNING: Project specifies a minimum meson_version '>=0.63.0' but
+ # > uses features which were added in newer versions:
+ # > * 0.64.0: {'fs.copyfile'}
+ # > * 1.0.0: {'dependencies arg in rust.bindgen', 'module rust as
stable module'}
+ rust_bindgen = import('rust')
+
+ # We need one bindings_rs build target per arch target, so give them
+ # arch-specific names.
+ copy = fs.copyfile('rust/wrapper.h',
+ target + '_wrapper.h')
+ bindings_rs = rust_bindgen.bindgen(
+ input: copy,
+ dependencies: arch_deps + lib_deps,
+ output: 'bindings-' + target + '.rs',
+ include_directories: include_directories('.', 'include'),
+ args: [
+ '--ctypes-prefix', 'core::ffi',
+ '--formatter', 'rustfmt',
+ '--generate-block',
+ '--generate-cstr',
+ '--impl-debug',
+ '--merge-extern-blocks',
+ '--no-doc-comments',
+ '--no-include-path-detection',
+ '--use-core',
+ '--with-derive-default',
+ '--allowlist-file', meson.project_source_root() + '/include/.*',
+ '--allowlist-file', meson.project_source_root() + '/.*',
+ '--allowlist-file', meson.project_build_root() + '/.*'
+ ],
+ )
+
+ if target in rust_targets
+ rust_hw = ss.source_set()
+ foreach t: rust_targets[target]
+ rust_device_cargo_build = custom_target(t['name'],
+ output: t['output'],
+ depends: [bindings_rs],
+ build_always_stale: true,
+ command: t['command'])
+ rust_dep = declare_dependency(link_args: [
+ '-Wl,--whole-archive',
+ t['output'],
+ '-Wl,--no-whole-archive'
+ ],
+ sources: [rust_device_cargo_build])
+ rust_hw.add(rust_dep)
+ endforeach
+ rust_hw_config = rust_hw.apply(config_target, strict: false)
+ arch_srcs += rust_hw_config.sources()
+ arch_deps += rust_hw_config.dependencies()
+ endif
+ endif
+
lib = static_library('qemu-' + target,
sources: arch_srcs + genh,
dependencies: lib_deps,
diff --git a/rust/.gitignore b/rust/.gitignore
new file mode 100644
index 0000000000..1bf71b1f68
--- /dev/null
+++ b/rust/.gitignore
@@ -0,0 +1,3 @@
+# Ignore any cargo development build artifacts; for qemu-wide builds, all build
+# artifacts will go to the meson build directory.
+target
diff --git a/rust/meson.build b/rust/meson.build
new file mode 100644
index 0000000000..5fdc2621a3
--- /dev/null
+++ b/rust/meson.build
@@ -0,0 +1,112 @@
+# Supported hosts
+rust_supported_oses = {
+ 'linux': '-unknown-linux-gnu',
+ # 'darwin': '-apple-darwin',
+ # 'windows': '-pc-windows-gnu'
+}
+rust_supported_cpus = ['x86_64', 'aarch64']
+
+# Future-proof the above definitions against any change in the root
meson.build file:
+foreach rust_os: rust_supported_oses.keys()
+ if not supported_oses.contains(rust_os)
+ message()
+ warning('UNSUPPORTED OS VALUES IN ' + meson.current_source_dir() +
'/meson.build')
+ message()
+ message('This meson.build file claims OS `+' + rust_os + '` is supported
but')
+ message('it is not included in the global supported OSes list in')
+ message(meson.global_source_root() + '/meson.build.')
+ endif
+endforeach
+foreach rust_cpu: rust_supported_cpus
+ if not supported_cpus.contains(rust_cpu)
+ message()
+ warning('UNSUPPORTED CPU VALUES IN ' + meson.current_source_dir() +
'/meson.build')
+ message()
+ message('This meson.build file claims CPU `+' + rust_cpu + '` is supported
but')
+ message('it is not included in the global supported CPUs list in')
+ message(meson.global_source_root() + '/meson.build.')
+ endif
+endforeach
+
+msrv = {
+ 'rustc': '1.77.2',
+ 'cargo': '1.77.2',
+ 'bindgen': '0.69.4',
+}
+
+foreach bin_dep: msrv.keys()
+ bin = find_program(bin_dep, required: true)
+ if bin.version() < msrv[bin_dep]
+ message()
+ error(bin_dep + ' version ' + bin.version() + ' is unsupported: Please
upgrade to at least ' + msrv[bin_dep])
+ endif
+endforeach
+
+rust_target_triple = get_option('with_rust_target_triple')
+
+if rust_target_triple == ''
+ if not supported_oses.contains(host_os)
+ message()
+ error('QEMU does not support `' + host_os +'` as a Rust platform.')
+ elif not supported_cpus.contains(host_arch)
+ message()
+ error('QEMU does not support `' + host_arch +'` as a Rust architecture.')
+ endif
+ rust_target_triple = host_arch + rust_supported_oses[host_os]
+ # if host_os == 'windows' and host_arch == 'aarch64'
+ # rust_target_triple += 'llvm'
+ # endif
+else
+ # verify rust_target_triple if given as an option
+ rustc = find_program('rustc', required: true)
+ rustc_targets = run_command(rustc, '--print', 'target-list', capture: true,
check: true).stdout().strip().split()
+ if not rustc_targets.contains(rust_target_triple)
+ message()
+ error('Given rust_target_triple ' + rust_target_triple + ' is not listed
in rustc --print target-list output')
+ endif
+endif
+
+rust_targets = {}
+
+cargo_wrapper = [
+ find_program(meson.global_source_root() / 'scripts/cargo_wrapper.py'),
+ '--config-headers', meson.project_build_root() / 'config-host.h',
+ '--meson-build-root', meson.project_build_root(),
+]
+
+if get_option('b_colorout') != 'never'
+ cargo_wrapper += ['--color', 'always']
+endif
+
+if get_option('optimization') in ['0', '1', 'g']
+ rs_build_profile = 'dev'
+else
+ rs_build_profile = 'release'
+endif
+
+subdir('qemu-api')
+
+# Collect metadata for each (crate,qemu-target,compiler-target) combination.
+# Rust meson targets cannot be defined a priori because they depend on bindgen
+# generation that is created for each emulation target separately. Thus Rust
+# meson targets will be defined for each target after the target-specific
+# bindgen dependency is declared.
+rust_hw_target_list = {}
+
+foreach rust_hw_target, rust_hws: rust_hw_target_list
+ foreach rust_hw_dev: rust_hws
+ crate_metadata = {
+ 'name': rust_hw_dev['name'],
+ 'output': [rust_hw_dev['output']],
+ 'command': [cargo_wrapper,
+ '--crate-dir', meson.current_source_dir() / rust_hw_dev['dirname'],
+ '--profile', rs_build_profile,
+ '--target-triple', rust_target_triple,
+ '--private-dir', '@PRIVATE_DIR@',
+ '--outdir', '@OUTDIR@',
+ 'build-lib'
+ ]
+ }
+ rust_targets += { rust_hw_target: [crate_metadata] }
+ endforeach
+endforeach
diff --git a/rust/wrapper.h b/rust/wrapper.h
new file mode 100644
index 0000000000..51985f0ef1
--- /dev/null
+++ b/rust/wrapper.h
@@ -0,0 +1,39 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright 2024 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.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/module.h"
+#include "qemu-io.h"
+#include "sysemu/sysemu.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"
diff --git a/scripts/cargo_wrapper.py b/scripts/cargo_wrapper.py
index d2c7265461..e7d9238c16 100644
--- a/scripts/cargo_wrapper.py
+++ b/scripts/cargo_wrapper.py
@@ -111,6 +111,8 @@ def get_cargo_rustc(args: argparse.Namespace) ->
tuple[Dict[str, Any], List[str]
env = os.environ
env["CARGO_ENCODED_RUSTFLAGS"] = cfg
+ env["MESON_BUILD_DIR"] = str(target_dir)
+ env["MESON_BUILD_ROOT"] = str(args.meson_build_root)
return (env, cargo_cmd)
@@ -231,19 +233,11 @@ def main() -> None:
default=[],
)
parser.add_argument(
- "--meson-build-dir",
- metavar="BUILD_DIR",
- help="meson.current_build_dir()",
+ "--meson-build-root",
+ metavar="BUILD_ROOT",
+ help="meson.project_build_root(): the root build directory. Example:
'/path/to/qemu/build'",
type=Path,
- dest="meson_build_dir",
- required=True,
- )
- parser.add_argument(
- "--meson-source-dir",
- metavar="SOURCE_DIR",
- help="meson.current_source_dir()",
- type=Path,
- dest="meson_build_dir",
+ dest="meson_build_root",
required=True,
)
parser.add_argument(
--
γαῖα πυρί μιχθήτω
- [RFC PATCH v4 0/7] Add Rust support, implement ARM PL011, Manos Pitsidianakis, 2024/07/04
- [RFC PATCH v4 1/7] build-sys: Add rust feature option, Manos Pitsidianakis, 2024/07/04
- [RFC PATCH v4 3/7] rust: add crate to expose bindings and interfaces, Manos Pitsidianakis, 2024/07/04
- [RFC PATCH v4 2/7] rust: add bindgen step as a meson dependency,
Manos Pitsidianakis <=
- Re: [RFC PATCH v4 2/7] rust: add bindgen step as a meson dependency, Paolo Bonzini, 2024/07/08
- Re: [RFC PATCH v4 2/7] rust: add bindgen step as a meson dependency, Alex Bennée, 2024/07/09
- Re: [RFC PATCH v4 2/7] rust: add bindgen step as a meson dependency, Peter Maydell, 2024/07/09
- Re: [RFC PATCH v4 2/7] rust: add bindgen step as a meson dependency, Paolo Bonzini, 2024/07/09
- Re: [RFC PATCH v4 2/7] rust: add bindgen step as a meson dependency, Daniel P . Berrangé, 2024/07/09
- Re: [RFC PATCH v4 2/7] rust: add bindgen step as a meson dependency, Pierrick Bouvier, 2024/07/11
- Re: [RFC PATCH v4 2/7] rust: add bindgen step as a meson dependency, Manos Pitsidianakis, 2024/07/12
- Re: [RFC PATCH v4 2/7] rust: add bindgen step as a meson dependency, Alex Bennée, 2024/07/09
- Re: [RFC PATCH v4 2/7] rust: add bindgen step as a meson dependency, Zhao Liu, 2024/07/10
- Re: [RFC PATCH v4 2/7] rust: add bindgen step as a meson dependency, Paolo Bonzini, 2024/07/10