rust: add bindgen step as a meson dependency
Add bindings_rs target for generating rust bindings to target-independent qemu C APIs. The bindings need be created before any rust crate that uses them is compiled. The bindings.rs file will end up in BUILDDIR/bindings.rs and have the same name as a target: ninja bindings.rs Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org> Link: https://lore.kernel.org/r/1be89a27719049b7203eaf2eca8bbb75b33f18d4.1727961605.git.manos.pitsidianakis@linaro.org Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
1a6ef6ff62
commit
6fdc5bc173
@ -4191,7 +4191,11 @@ F: docs/devel/docs.rst
|
|||||||
Rust build system integration
|
Rust build system integration
|
||||||
M: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
M: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
F: scripts/rust/
|
||||||
|
F: rust/.gitignore
|
||||||
F: rust/Kconfig
|
F: rust/Kconfig
|
||||||
|
F: rust/meson.build
|
||||||
|
F: rust/wrapper.h
|
||||||
|
|
||||||
Miscellaneous
|
Miscellaneous
|
||||||
-------------
|
-------------
|
||||||
|
7
configure
vendored
7
configure
vendored
@ -2060,3 +2060,10 @@ echo ' "$@"' >>config.status
|
|||||||
chmod +x config.status
|
chmod +x config.status
|
||||||
|
|
||||||
rm -r "$TMPDIR1"
|
rm -r "$TMPDIR1"
|
||||||
|
|
||||||
|
if test "$rust" != disabled; then
|
||||||
|
echo '\nINFO: Rust bindings generation with `bindgen` might fail in some cases where'
|
||||||
|
echo 'the detected `libclang` does not match the expected `clang` version/target. In'
|
||||||
|
echo 'this case you must pass the path to `clang` and `libclang` to your build'
|
||||||
|
echo 'command invocation using the environment variables CLANG_PATH and LIBCLANG_PATH'
|
||||||
|
fi
|
||||||
|
68
meson.build
68
meson.build
@ -3892,6 +3892,74 @@ common_all = static_library('common',
|
|||||||
implicit_include_directories: false,
|
implicit_include_directories: false,
|
||||||
dependencies: common_ss.all_dependencies())
|
dependencies: common_ss.all_dependencies())
|
||||||
|
|
||||||
|
if have_rust and have_system
|
||||||
|
rustc_args = run_command(
|
||||||
|
find_program('scripts/rust/rustc_args.py'),
|
||||||
|
'--config-headers', meson.project_build_root() / 'config-host.h',
|
||||||
|
capture : true,
|
||||||
|
check: true).stdout().strip().split()
|
||||||
|
rustc_args += ['-D', 'unsafe_op_in_unsafe_fn']
|
||||||
|
bindgen_args = [
|
||||||
|
'--disable-header-comment',
|
||||||
|
'--raw-line', '// @generated',
|
||||||
|
'--ctypes-prefix', 'core::ffi',
|
||||||
|
'--formatter', 'rustfmt',
|
||||||
|
'--generate-block',
|
||||||
|
'--generate-cstr',
|
||||||
|
'--impl-debug',
|
||||||
|
'--merge-extern-blocks',
|
||||||
|
'--no-doc-comments',
|
||||||
|
'--use-core',
|
||||||
|
'--with-derive-default',
|
||||||
|
'--no-size_t-is-usize',
|
||||||
|
'--no-layout-tests',
|
||||||
|
'--no-prepend-enum-name',
|
||||||
|
'--allowlist-file', meson.project_source_root() + '/include/.*',
|
||||||
|
'--allowlist-file', meson.project_source_root() + '/.*',
|
||||||
|
'--allowlist-file', meson.project_build_root() + '/.*'
|
||||||
|
]
|
||||||
|
c_enums = [
|
||||||
|
'DeviceCategory',
|
||||||
|
'GpioPolarity',
|
||||||
|
'MachineInitPhase',
|
||||||
|
'MemoryDeviceInfoKind',
|
||||||
|
'MigrationPolicy',
|
||||||
|
'MigrationPriority',
|
||||||
|
'QEMUChrEvent',
|
||||||
|
'QEMUClockType',
|
||||||
|
'device_endian',
|
||||||
|
'module_init_type',
|
||||||
|
]
|
||||||
|
foreach enum : c_enums
|
||||||
|
bindgen_args += ['--rustified-enum', enum]
|
||||||
|
endforeach
|
||||||
|
c_bitfields = [
|
||||||
|
'ClockEvent',
|
||||||
|
'VMStateFlags',
|
||||||
|
]
|
||||||
|
foreach enum : c_bitfields
|
||||||
|
bindgen_args += ['--bitfield-enum', enum]
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
# TODO: Remove this comment when the clang/libclang mismatch issue is solved.
|
||||||
|
#
|
||||||
|
# Rust bindings generation with `bindgen` might fail in some cases where the
|
||||||
|
# detected `libclang` does not match the expected `clang` version/target. In
|
||||||
|
# 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 = import('rust').bindgen(
|
||||||
|
input: 'rust/wrapper.h',
|
||||||
|
dependencies: common_ss.all_dependencies(),
|
||||||
|
output: 'bindings.rs',
|
||||||
|
include_directories: include_directories('.', 'include'),
|
||||||
|
bindgen_version: ['>=0.69.4'],
|
||||||
|
args: bindgen_args,
|
||||||
|
)
|
||||||
|
subdir('rust')
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
feature_to_c = find_program('scripts/feature_to_c.py')
|
feature_to_c = find_program('scripts/feature_to_c.py')
|
||||||
|
|
||||||
if host_os == 'darwin'
|
if host_os == 'darwin'
|
||||||
|
3
rust/.gitignore
vendored
Normal file
3
rust/.gitignore
vendored
Normal file
@ -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
|
0
rust/meson.build
Normal file
0
rust/meson.build
Normal file
47
rust/wrapper.h
Normal file
47
rust/wrapper.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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"
|
84
scripts/rust/rustc_args.py
Normal file
84
scripts/rust/rustc_args.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""Generate rustc arguments for meson rust builds.
|
||||||
|
|
||||||
|
This program generates --cfg compile flags for the configuration headers passed
|
||||||
|
as arguments.
|
||||||
|
|
||||||
|
Copyright (c) 2024 Linaro Ltd.
|
||||||
|
|
||||||
|
Authors:
|
||||||
|
Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
|
def generate_cfg_flags(header: str) -> List[str]:
|
||||||
|
"""Converts defines from config[..].h headers to rustc --cfg flags."""
|
||||||
|
|
||||||
|
def cfg_name(name: str) -> str:
|
||||||
|
"""Filter function for C #defines"""
|
||||||
|
if (
|
||||||
|
name.startswith("CONFIG_")
|
||||||
|
or name.startswith("TARGET_")
|
||||||
|
or name.startswith("HAVE_")
|
||||||
|
):
|
||||||
|
return name
|
||||||
|
return ""
|
||||||
|
|
||||||
|
with open(header, encoding="utf-8") as cfg:
|
||||||
|
config = [l.split()[1:] for l in cfg if l.startswith("#define")]
|
||||||
|
|
||||||
|
cfg_list = []
|
||||||
|
for cfg in config:
|
||||||
|
name = cfg_name(cfg[0])
|
||||||
|
if not name:
|
||||||
|
continue
|
||||||
|
if len(cfg) >= 2 and cfg[1] != "1":
|
||||||
|
continue
|
||||||
|
cfg_list.append("--cfg")
|
||||||
|
cfg_list.append(name)
|
||||||
|
return cfg_list
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
# pylint: disable=missing-function-docstring
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("-v", "--verbose", action="store_true")
|
||||||
|
parser.add_argument(
|
||||||
|
"--config-headers",
|
||||||
|
metavar="CONFIG_HEADER",
|
||||||
|
action="append",
|
||||||
|
dest="config_headers",
|
||||||
|
help="paths to any configuration C headers (*.h files), if any",
|
||||||
|
required=False,
|
||||||
|
default=[],
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
if args.verbose:
|
||||||
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
logging.debug("args: %s", args)
|
||||||
|
for header in args.config_headers:
|
||||||
|
for tok in generate_cfg_flags(header):
|
||||||
|
print(tok)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in New Issue
Block a user