xref: /qemu/scripts/rust/rustc_args.py (revision 1de82059aa097340d0ffde9140d338cddef478e5)
1#!/usr/bin/env python3
2
3"""Generate rustc arguments for meson rust builds.
4
5This program generates --cfg compile flags for the configuration headers passed
6as arguments.
7
8Copyright (c) 2024 Linaro Ltd.
9
10Authors:
11 Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
12
13This program is free software; you can redistribute it and/or modify
14it under the terms of the GNU General Public License as published by
15the Free Software Foundation; either version 2 of the License, or
16(at your option) any later version.
17
18This program is distributed in the hope that it will be useful,
19but WITHOUT ANY WARRANTY; without even the implied warranty of
20MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21GNU General Public License for more details.
22
23You should have received a copy of the GNU General Public License
24along with this program.  If not, see <http://www.gnu.org/licenses/>.
25"""
26
27import argparse
28import logging
29from pathlib import Path
30from typing import Any, Iterable, Mapping, Optional, Set
31
32try:
33    import tomllib
34except ImportError:
35    import tomli as tomllib
36
37
38class CargoTOML:
39    tomldata: Mapping[Any, Any]
40    check_cfg: Set[str]
41
42    def __init__(self, path: str):
43        with open(path, 'rb') as f:
44            self.tomldata = tomllib.load(f)
45
46        self.check_cfg = set(self.find_check_cfg())
47
48    def find_check_cfg(self) -> Iterable[str]:
49        toml_lints = self.lints
50        rust_lints = toml_lints.get("rust", {})
51        cfg_lint = rust_lints.get("unexpected_cfgs", {})
52        return cfg_lint.get("check-cfg", [])
53
54    @property
55    def lints(self) -> Mapping[Any, Any]:
56        return self.get_table("lints")
57
58    def get_table(self, key: str) -> Mapping[Any, Any]:
59        table = self.tomldata.get(key, {})
60
61        return table
62
63
64def generate_cfg_flags(header: str, cargo_toml: CargoTOML) -> Iterable[str]:
65    """Converts defines from config[..].h headers to rustc --cfg flags."""
66
67    with open(header, encoding="utf-8") as cfg:
68        config = [l.split()[1:] for l in cfg if l.startswith("#define")]
69
70    cfg_list = []
71    for cfg in config:
72        name = cfg[0]
73        if f'cfg({name})' not in cargo_toml.check_cfg:
74            continue
75        if len(cfg) >= 2 and cfg[1] != "1":
76            continue
77        cfg_list.append("--cfg")
78        cfg_list.append(name)
79    return cfg_list
80
81
82def main() -> None:
83    parser = argparse.ArgumentParser()
84    parser.add_argument("-v", "--verbose", action="store_true")
85    parser.add_argument(
86        "--config-headers",
87        metavar="CONFIG_HEADER",
88        action="append",
89        dest="config_headers",
90        help="paths to any configuration C headers (*.h files), if any",
91        required=False,
92        default=[],
93    )
94    parser.add_argument(
95        metavar="TOML_FILE",
96        action="store",
97        dest="cargo_toml",
98        help="path to Cargo.toml file",
99    )
100    args = parser.parse_args()
101    if args.verbose:
102        logging.basicConfig(level=logging.DEBUG)
103    logging.debug("args: %s", args)
104
105    cargo_toml = CargoTOML(args.cargo_toml)
106
107    for header in args.config_headers:
108        for tok in generate_cfg_flags(header, cargo_toml):
109            print(tok)
110
111
112if __name__ == "__main__":
113    main()
114