2 r
"""Emulates the bits of CMake's configure_file() function needed in LLVM.
4 The CMake build uses configure_file() for several things. This emulates that
5 function for the GN build. In the GN build, this runs at build time instead
8 Takes a list of KEY=VALUE pairs (where VALUE can be empty).
10 The sequence `\` `n` in each VALUE is replaced by a newline character.
12 On each line, replaces '${KEY}' or '@KEY@' with VALUE.
14 Then, handles these special cases (note that FOO= sets the value of FOO to the
15 empty string, which is falsy, but FOO=0 sets it to '0' which is truthy):
17 1.) #cmakedefine01 FOO
18 Checks if key FOO is set to a truthy value, and depending on that prints
19 one of the following two lines:
24 2.) #cmakedefine FOO [...]
25 Checks if key FOO is set to a truthy value, and depending on that prints
26 one of the following two lines:
31 Fails if any of the KEY=VALUE arguments aren't needed for processing the
32 input file, or if the input file references keys that weren't passed in.
42 parser
= argparse
.ArgumentParser(
43 epilog
=__doc__
, formatter_class
=argparse
.RawDescriptionHelpFormatter
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()
51 for value
in args
.values
:
52 key
, val
= value
.split("=", 1)
54 print('duplicate key "%s" in args' % key
, file=sys
.stderr
)
56 values
[key
] = val
.replace("\\n", "\n")
57 unused_values
= set(values
.keys())
59 # Matches e.g. '${FOO}' or '@FOO@' and captures FOO in group 1 or 2.
60 var_re
= re
.compile(r
"\$\{([^}]*)\}|@([^@]*)@")
62 with
open(args
.input) as f
:
63 in_lines
= f
.readlines()
65 for in_line
in in_lines
:
68 key
= m
.group(1) or m
.group(2)
69 unused_values
.discard(key
)
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
)
80 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)
85 var
, val
= var
.split(None, 1)
86 in_line
= "#define %s %s" % (var
, val
) # val ends in \n.
89 in_line
= "#define %s\n" % var
91 in_line
= "/* #undef %s */\n" % var
92 unused_values
.discard(var
)
93 out_lines
.append(in_line
)
96 print("unused values args:", file=sys
.stderr
)
97 print(" " + "\n ".join(unused_values
), file=sys
.stderr
)
100 output
= "".join(out_lines
)
102 leftovers
= var_re
.findall(output
)
105 "unprocessed values:\n",
106 "\n".join([x
[0] or x
[1] for x
in leftovers
]),
112 with
open(args
.output
) as f
:
115 if not os
.path
.exists(args
.output
) or read(args
.output
) != output
:
116 with
open(args
.output
, "w") as f
:
118 os
.chmod(args
.output
, os
.stat(args
.input).st_mode
& 0o777)
121 if __name__
== "__main__":