aboutsummaryrefslogtreecommitdiff
path: root/scripts/rust/rustc_args.py
blob: 942dd2b2babb7c6ae316c7971536a06fc5686a32 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#!/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 pathlib import Path
from typing import Any, Iterable, Mapping, Optional, Set

try:
    import tomllib
except ImportError:
    import tomli as tomllib


class CargoTOML:
    tomldata: Mapping[Any, Any]
    check_cfg: Set[str]

    def __init__(self, path: str):
        with open(path, 'rb') as f:
            self.tomldata = tomllib.load(f)

        self.check_cfg = set(self.find_check_cfg())

    def find_check_cfg(self) -> Iterable[str]:
        toml_lints = self.lints
        rust_lints = toml_lints.get("rust", {})
        cfg_lint = rust_lints.get("unexpected_cfgs", {})
        return cfg_lint.get("check-cfg", [])

    @property
    def lints(self) -> Mapping[Any, Any]:
        return self.get_table("lints")

    def get_table(self, key: str) -> Mapping[Any, Any]:
        table = self.tomldata.get(key, {})

        return table


def generate_cfg_flags(header: str, cargo_toml: CargoTOML) -> Iterable[str]:
    """Converts defines from config[..].h headers to rustc --cfg flags."""

    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[0]
        if f'cfg({name})' not in cargo_toml.check_cfg:
            continue
        if len(cfg) >= 2 and cfg[1] != "1":
            continue
        cfg_list.append("--cfg")
        cfg_list.append(name)
    return cfg_list


def main() -> None:
    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=[],
    )
    parser.add_argument(
        metavar="TOML_FILE",
        action="store",
        dest="cargo_toml",
        help="path to Cargo.toml file",
    )
    args = parser.parse_args()
    if args.verbose:
        logging.basicConfig(level=logging.DEBUG)
    logging.debug("args: %s", args)

    cargo_toml = CargoTOML(args.cargo_toml)

    for header in args.config_headers:
        for tok in generate_cfg_flags(header, cargo_toml):
            print(tok)


if __name__ == "__main__":
    main()