[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [RFC PATCH v1 1/6] build-sys: Add rust feature option
From: |
Alex Bennée |
Subject: |
Re: [RFC PATCH v1 1/6] build-sys: Add rust feature option |
Date: |
Tue, 11 Jun 2024 15:19:59 +0100 |
Stefan Hajnoczi <stefanha@redhat.com> writes:
> On Mon, Jun 10, 2024 at 09:22:36PM +0300, Manos Pitsidianakis wrote:
>> Add options for Rust in meson_options.txt, meson.build, configure to
>> prepare for adding Rust code in the followup commits.
>>
>> `rust` is a reserved meson name, so we have to use an alternative.
>> `with_rust` was chosen.
>>
>> Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
>> ---
>> The cargo wrapper script hardcodes some rust target triples. This is
>> just temporary.
>> ---
>> .gitignore | 2 +
>> configure | 12 +++
>> meson.build | 11 ++
>> meson_options.txt | 4 +
>> scripts/cargo_wrapper.py | 211 +++++++++++++++++++++++++++++++++++++++
>> 5 files changed, 240 insertions(+)
>> create mode 100644 scripts/cargo_wrapper.py
>>
>> diff --git a/.gitignore b/.gitignore
>> index 61fa39967b..f42b0d937e 100644
>> --- a/.gitignore
>> +++ b/.gitignore
>> @@ -2,6 +2,8 @@
>> /build/
>> /.cache/
>> /.vscode/
>> +/target/
>> +rust/**/target
>
> Are these necessary since the cargo build command-line below uses
> --target-dir <meson-build-dir>?
>
> Adding new build output directories outside build/ makes it harder to
> clean up the source tree and ensure no state from previous builds
> remains.
Indeed my tree looks like:
$SRC
/builds
/buildA
/buildB
etc. So I would expect the rust build stuff to be in the builddir
because I have multiple configurations.
>
>> *.pyc
>> .sdk
>> .stgit-*
>> diff --git a/configure b/configure
>> index 38ee257701..c195630771 100755
>> --- a/configure
>> +++ b/configure
>> @@ -302,6 +302,9 @@ else
>> objcc="${objcc-${cross_prefix}clang}"
>> fi
>>
>> +with_rust="auto"
>> +with_rust_target_triple=""
>> +
>> ar="${AR-${cross_prefix}ar}"
>> as="${AS-${cross_prefix}as}"
>> ccas="${CCAS-$cc}"
>> @@ -760,6 +763,12 @@ for opt do
>> ;;
>> --gdb=*) gdb_bin="$optarg"
>> ;;
>> + --enable-rust) with_rust=enabled
>> + ;;
>> + --disable-rust) with_rust=disabled
>> + ;;
>> + --rust-target-triple=*) with_rust_target_triple="$optarg"
>> + ;;
>> # everything else has the same name in configure and meson
>> --*) meson_option_parse "$opt" "$optarg"
>> ;;
>> @@ -1796,6 +1805,9 @@ if test "$skip_meson" = no; then
>> test -n "${LIB_FUZZING_ENGINE+xxx}" && meson_option_add
>> "-Dfuzzing_engine=$LIB_FUZZING_ENGINE"
>> test "$plugins" = yes && meson_option_add "-Dplugins=true"
>> test "$tcg" != enabled && meson_option_add "-Dtcg=$tcg"
>> + test "$with_rust" != enabled && meson_option_add "-Dwith_rust=$with_rust"
>> + test "$with_rust" != enabled && meson_option_add "-Dwith_rust=$with_rust"
>
> Duplicate line.
>
>> + test "$with_rust_target_triple" != "" && meson_option_add
>> "-Dwith_rust_target_triple=$with_rust_target_triple"
>> run_meson() {
>> NINJA=$ninja $meson setup "$@" "$PWD" "$source_path"
>> }
>> diff --git a/meson.build b/meson.build
>> index a9de71d450..3533889852 100644
>> --- a/meson.build
>> +++ b/meson.build
>> @@ -290,6 +290,12 @@ foreach lang : all_languages
>> endif
>> endforeach
>>
>> +cargo = not_found
>> +if get_option('with_rust').allowed()
>> + cargo = find_program('cargo', required: get_option('with_rust'))
>> +endif
>> +with_rust = cargo.found()
>> +
>> # default flags for all hosts
>> # We use -fwrapv to tell the compiler that we require a C dialect where
>> # left shift of signed integers is well defined and has the expected
>> @@ -2066,6 +2072,7 @@ endif
>>
>> config_host_data = configuration_data()
>>
>> +config_host_data.set('CONFIG_WITH_RUST', with_rust)
>> audio_drivers_selected = []
>> if have_system
>> audio_drivers_available = {
>> @@ -4190,6 +4197,10 @@ if 'objc' in all_languages
>> else
>> summary_info += {'Objective-C compiler': false}
>> endif
>> +summary_info += {'Rust support': with_rust}
>> +if with_rust and get_option('with_rust_target_triple') != ''
>> + summary_info += {'Rust target': get_option('with_rust_target_triple')}
>> +endif
>> option_cflags = (get_option('debug') ? ['-g'] : [])
>> if get_option('optimization') != 'plain'
>> option_cflags += ['-O' + get_option('optimization')]
>> diff --git a/meson_options.txt b/meson_options.txt
>> index 4c1583eb40..223491b731 100644
>> --- a/meson_options.txt
>> +++ b/meson_options.txt
>> @@ -366,3 +366,7 @@ option('qemu_ga_version', type: 'string', value: '',
>>
>> option('hexagon_idef_parser', type : 'boolean', value : true,
>> description: 'use idef-parser to automatically generate TCG code for
>> the Hexagon frontend')
>> +option('with_rust', type: 'feature', value: 'auto',
>> + description: 'Enable Rust support')
>> +option('with_rust_target_triple', type : 'string', value: '',
>> + description: 'Rust target triple')
>> diff --git a/scripts/cargo_wrapper.py b/scripts/cargo_wrapper.py
>> new file mode 100644
>> index 0000000000..d338effdaa
>> --- /dev/null
>> +++ b/scripts/cargo_wrapper.py
>> @@ -0,0 +1,211 @@
>> +#!/usr/bin/env python3
>> +# Copyright (c) 2020 Red Hat, Inc.
>> +# Copyright (c) 2023 Linaro Ltd.
>> +#
>> +# Authors:
>> +# Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
>> +# Marc-André Lureau <marcandre.lureau@redhat.com>
>> +#
>> +# This work is licensed under the terms of the GNU GPL, version 2 or
>> +# later. See the COPYING file in the top-level directory.
>> +
>> +import argparse
>> +import configparser
>> +import distutils.file_util
>> +import json
>> +import logging
>> +import os
>> +import os.path
>> +import re
>> +import subprocess
>> +import sys
>> +import pathlib
>> +import shutil
>> +import tomllib
>> +
>> +from pathlib import Path
>> +from typing import Any, Dict, List, Tuple
>> +
>> +RUST_TARGET_TRIPLES = (
>> + "aarch64-unknown-linux-gnu",
>> + "x86_64-unknown-linux-gnu",
>> + "x86_64-apple-darwin",
>> + "aarch64-apple-darwin",
>> +)
>
> Is this hardcoded to avoid calling `rustc --print target-list`?
>
> Or is this the support matrix? In that case it would be interesting to
> figure out the target triples for all host OSes and CPUs that QEMU is
> supported on.
>
>> +
>> +
>> +def cfg_name(name: str) -> str:
>> + if (
>> + name.startswith("CONFIG_")
>> + or name.startswith("TARGET_")
>> + or name.startswith("HAVE_")
>> + ):
>> + return name
>> + return ""
>> +
>> +
>> +def generate_cfg_flags(header: str) -> List[str]:
>> + 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 cargo_target_dir(args: argparse.Namespace) -> pathlib.Path:
>> + return args.meson_build_dir
>> +
>> +
>> +def manifest_path(args: argparse.Namespace) -> pathlib.Path:
>> + return args.crate_dir / "Cargo.toml"
>> +
>> +
>> +def get_cargo_rustc(args: argparse.Namespace) -> tuple[Dict[str, Any],
>> List[str]]:
>> + # See
>> https://doc.rust-lang.org/cargo/reference/environment-variables.html
>> + # Item `CARGO_ENCODED_RUSTFLAGS — A list of custom flags separated by
>> + # 0x1f (ASCII Unit Separator) to pass to all compiler invocations that
>> Cargo
>> + # performs`
>> + cfg = chr(0x1F).join(
>> + [c for h in args.config_headers for c in generate_cfg_flags(h)]
>> + )
>> + target_dir = cargo_target_dir(args)
>> + cargo_path = manifest_path(args)
>> +
>> + cargo_cmd = [
>> + "cargo",
>> + "build",
>> + "--target-dir",
>> + str(target_dir),
>> + "--manifest-path",
>> + str(cargo_path),
>> + ]
>> + if args.target_triple:
>> + cargo_cmd += ["--target", args.target_triple]
>> + if args.profile == "release":
>> + cargo_cmd += ["--release"]
>> +
>> + env = os.environ
>> + env["CARGO_ENCODED_RUSTFLAGS"] = cfg
>> +
>> + return (env, cargo_cmd)
>> +
>> +
>> +def run_cargo(env: Dict[str, Any], cargo_cmd: List[str]) -> str:
>> + envlog = " ".join(["{}={}".format(k, v) for k, v in env.items()])
>> + cmdlog = " ".join(cargo_cmd)
>> + logging.debug("Running %s %s", envlog, cmdlog)
>> + try:
>> + out = subprocess.check_output(
>> + cargo_cmd,
>> + env=dict(os.environ, **env),
>> + stderr=subprocess.STDOUT,
>> + universal_newlines=True,
>> + )
>> + except subprocess.CalledProcessError as err:
>> + print("Environment: " + envlog)
>> + print("Command: " + cmdlog)
>> + print(err.output)
>> + sys.exit(1)
>> +
>> + return out
>> +
>> +
>> +def build_lib(args: argparse.Namespace) -> None:
>> + logging.debug("build-lib")
>> + target_dir = cargo_target_dir(args)
>> + cargo_toml_path = manifest_path(args)
>> +
>> + with open(cargo_toml_path, "rb") as f:
>> + config = tomllib.load(f)
>> +
>> + package_name = config["package"]["name"].strip('"').replace("-", "_")
>> +
>> + liba_filename = "lib" + package_name + ".a"
>> + liba = target_dir / args.target_triple / args.profile / liba_filename
>> +
>> + env, cargo_cmd = get_cargo_rustc(args)
>> + out = run_cargo(env, cargo_cmd)
>> + logging.debug("cp %s %s", liba, args.outdir)
>> + shutil.copy2(liba, args.outdir)
>> +
>> +
>> +def main() -> None:
>> + parser = argparse.ArgumentParser()
>> + parser.add_argument("-v", "--verbose", action="store_true")
>> + parser.add_argument(
>> + "--color",
>> + metavar="WHEN",
>> + choices=["auto", "always", "never"],
>> + default="auto",
>> + help="Coloring: auto, always, never",
>> + )
>> + parser.add_argument(
>> + "--config-headers",
>> + metavar="CONFIG_HEADER",
>> + action="append",
>> + dest="config_headers",
>> + required=False,
>> + default=[],
>> + )
>> + parser.add_argument(
>> + "--meson-build-dir",
>> + metavar="BUILD_DIR",
>> + help="meson.current_build_dir()",
>> + type=pathlib.Path,
>> + dest="meson_build_dir",
>> + required=True,
>> + )
>> + parser.add_argument(
>> + "--meson-source-dir",
>> + metavar="SOURCE_DIR",
>> + help="meson.current_source_dir()",
>> + type=pathlib.Path,
>> + dest="meson_source_dir",
>> + required=True,
>> + )
>> + parser.add_argument(
>> + "--crate-dir",
>> + metavar="CRATE_DIR",
>> + type=pathlib.Path,
>> + dest="crate_dir",
>> + help="Absolute path that contains the manifest file of the crate to
>> compile",
>> + required=True,
>> + )
>> + parser.add_argument(
>> + "--outdir",
>> + metavar="OUTDIR",
>> + type=pathlib.Path,
>> + dest="outdir",
>> + help="Path to copy compiled artifacts to for Meson to use.",
>> + required=True,
>> + )
>> + parser.add_argument(
>> + "--profile", type=str, choices=["release", "debug"], required=True
>> + )
>> + parser.add_argument(
>> + "--target-triple", type=str, choices=RUST_TARGET_TRIPLES,
>> required=True
>> + )
>> +
>> + subparsers = parser.add_subparsers()
>> +
>> + buildlib = subparsers.add_parser("build-lib")
>> + buildlib.set_defaults(func=build_lib)
>> +
>> + args = parser.parse_args()
>> + if args.verbose:
>> + logging.basicConfig(level=logging.DEBUG)
>> + logging.debug("args: %s", args)
>> +
>> + args.func(args)
>> +
>> +
>> +if __name__ == "__main__":
>> + main()
>> --
>> γαῖα πυρί μιχθήτω
>>
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
[RFC PATCH v1 2/6] rust: add PL011 device model, Manos Pitsidianakis, 2024/06/10
[RFC PATCH v1 3/6] DO NOT MERGE: add rustdoc build for gitlab pages, Manos Pitsidianakis, 2024/06/10
[RFC PATCH v1 4/6] DO NOT MERGE: replace TYPE_PL011 with x-pl011-rust in arm virt machine, Manos Pitsidianakis, 2024/06/10
[RFC PATCH v1 6/6] DO NOT MERGE: update rustdoc gitlab pages gen, Manos Pitsidianakis, 2024/06/10
[RFC PATCH v1 5/6] rust: add bindgen step as a meson dependency, Manos Pitsidianakis, 2024/06/10
Re: [RFC PATCH v1 0/6] Implement ARM PL011 in Rust, Pierrick Bouvier, 2024/06/10