| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- #!/usr/bin/env python3
- __copyright__ = """
- Part of the Carbon Language project, under the Apache License v2.0 with LLVM
- Exceptions. See /LICENSE for license information.
- SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- """
- """Script to apply a set of defines to a CMake-style configure file.
- This serves as the action implementation for `configure_cmake_file.bzl`. See the
- documentation in the rule of that file for more details about how to use this,
- or `--help` on the script.
- """
- import argparse
- import re
- from typing import Dict
- # A set of CMake values that are considered "false".
- # Based on https://cmake.org/cmake/help/latest/command/if.html
- _CMAKE_FALSE_VALUES = {
- "",
- "0",
- "OFF",
- "NO",
- "N",
- "FALSE",
- "IGNORE",
- "NOTFOUND",
- }
- _VAR_AT_PATTERN = re.compile(r"@([^@]*)@")
- _VAR_DOLLAR_PATTERN = re.compile(r"${([^}]*)}")
- _DIRECTIVE_PATTERN = re.compile(
- r"^#(?P<indent>[ \t]*)cmakedefine\s+(?P<var>\w+)(?P<rest>.*)?$"
- )
- _DIRECTIVE_01_PATTERN = re.compile(
- r"^#(?P<indent>[ \t]*)cmakedefine01\s+(?P<var>\w+)$"
- )
- def _is_cmake_true(value: str) -> bool:
- """Returns true if the value is not a CMake false value.
- This is how CMake defines values as 'true' vs. 'false':
- https://cmake.org/cmake/help/latest/command/if.html
- """
- return (
- value.upper() not in _CMAKE_FALSE_VALUES
- and not value.upper().endswith("-NOTFOUND")
- )
- def _substitute_variables(text: str, defines: Dict[str, str]) -> str:
- """Substitutes @VAR@ and ${VAR} style variables in a string."""
- def repl(m: re.Match) -> str:
- return defines.get(str(m.group(1)), "")
- return re.sub(
- _VAR_AT_PATTERN, repl, re.sub(_VAR_DOLLAR_PATTERN, repl, text)
- )
- def main() -> None:
- parser = argparse.ArgumentParser()
- parser.add_argument("--src", required=True)
- parser.add_argument("--out", required=True)
- parser.add_argument("--defines", nargs=2, action="append", default=[])
- args = parser.parse_args()
- defines = dict(args.defines)
- with open(args.src, "r") as f:
- content = f.read()
- output_lines = []
- for line in content.splitlines():
- if m := re.match(_DIRECTIVE_PATTERN, line):
- var = m.group("var")
- if var in defines and _is_cmake_true(defines[var]):
- rest = _substitute_variables(m.group("rest"), defines)
- output_lines.append(
- "#%sdefine %s %s" % (m.group("indent"), var, rest)
- )
- else:
- # The variable is false, so leave it undefined.
- output_lines.append("/* #undef %s */" % var)
- elif m := re.match(_DIRECTIVE_01_PATTERN, line):
- var = m.group("var")
- indent = m.group("indent")
- if var in defines and _is_cmake_true(defines[var]):
- output_lines.append("#%sdefine %s 1" % (indent, var))
- else:
- output_lines.append("#%sdefine %s 0" % (indent, var))
- else:
- output_lines.append(_substitute_variables(line, defines))
- with open(args.out, "w") as f:
- f.write("\n".join(output_lines) + "\n")
- if __name__ == "__main__":
- main()
|