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
|
||||
M: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
S: Maintained
|
||||
F: scripts/rust/
|
||||
F: rust/.gitignore
|
||||
F: rust/Kconfig
|
||||
F: rust/meson.build
|
||||
F: rust/wrapper.h
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
|
7
configure
vendored
7
configure
vendored
@ -2060,3 +2060,10 @@ echo ' "$@"' >>config.status
|
||||
chmod +x config.status
|
||||
|
||||
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,
|
||||
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')
|
||||
|
||||
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