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