brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.9 KiB · a14df6b Raw
123 lines · python
1#!/usr/bin/env python32r"""Emulates the bits of CMake's configure_file() function needed in LLVM.3 4The CMake build uses configure_file() for several things.  This emulates that5function for the GN build.  In the GN build, this runs at build time instead6of at generator time.7 8Takes a list of KEY=VALUE pairs (where VALUE can be empty).9 10The sequence `\` `n` in each VALUE is replaced by a newline character.11 12On each line, replaces '${KEY}' or '@KEY@' with VALUE.13 14Then, handles these special cases (note that FOO= sets the value of FOO to the15empty string, which is falsy, but FOO=0 sets it to '0' which is truthy):16 171.) #cmakedefine01 FOO18    Checks if key FOO is set to a truthy value, and depending on that prints19    one of the following two lines:20 21        #define FOO 122        #define FOO 023 242.) #cmakedefine FOO [...]25    Checks if key FOO is set to a truthy value, and depending on that prints26    one of the following two lines:27 28        #define FOO [...]29        /* #undef FOO */30 31Fails if any of the KEY=VALUE arguments aren't needed for processing the32input file, or if the input file references keys that weren't passed in.33"""34 35import argparse36import os37import re38import sys39 40 41def main():42    parser = argparse.ArgumentParser(43        epilog=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter44    )45    parser.add_argument("input", help="input file")46    parser.add_argument("values", nargs="*", help="several KEY=VALUE pairs")47    parser.add_argument("-o", "--output", required=True, help="output file")48    args = parser.parse_args()49 50    values = {}51    for value in args.values:52        key, val = value.split("=", 1)53        if key in values:54            print('duplicate key "%s" in args' % key, file=sys.stderr)55            return 156        values[key] = val.replace("\\n", "\n")57    unused_values = set(values.keys())58 59    # Matches e.g. '${FOO}' or '@FOO@' and captures FOO in group 1 or 2.60    var_re = re.compile(r"\$\{([^}]*)\}|@([^@]*)@")61 62    with open(args.input) as f:63        in_lines = f.readlines()64    out_lines = []65    for in_line in in_lines:66 67        def repl(m):68            key = m.group(1) or m.group(2)69            unused_values.discard(key)70            return values[key]71 72        in_line = var_re.sub(repl, in_line)73        if in_line.startswith("#cmakedefine01 "):74            _, var = in_line.split()75            if values[var] == "0":76                print('error: "%s=0" used with #cmakedefine01 %s' % (var, var))77                print("       '0' evaluates as truthy with #cmakedefine01")78                print('       use "%s=" instead' % var)79                return 180            in_line = "#define %s %d\n" % (var, 1 if values[var] else 0)81            unused_values.discard(var)82        elif in_line.startswith("#cmakedefine "):83            _, var = in_line.split(None, 1)84            try:85                var, val = var.split(None, 1)86                in_line = "#define %s %s" % (var, val)  # val ends in \n.87            except:88                var = var.rstrip()89                in_line = "#define %s\n" % var90            if not values[var]:91                in_line = "/* #undef %s */\n" % var92            unused_values.discard(var)93        out_lines.append(in_line)94 95    if unused_values:96        print("unused values args:", file=sys.stderr)97        print("    " + "\n    ".join(unused_values), file=sys.stderr)98        return 199 100    output = "".join(out_lines)101 102    leftovers = var_re.findall(output)103    if leftovers:104        print(105            "unprocessed values:\n",106            "\n".join([x[0] or x[1] for x in leftovers]),107            file=sys.stderr,108        )109        return 1110 111    def read(filename):112        with open(args.output) as f:113            return f.read()114 115    if not os.path.exists(args.output) or read(args.output) != output:116        with open(args.output, "w") as f:117            f.write(output)118        os.chmod(args.output, os.stat(args.input).st_mode & 0o777)119 120 121if __name__ == "__main__":122    sys.exit(main())123