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