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 in 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.
35 from __future__
import print_function
44 parser
= argparse
.ArgumentParser(
46 formatter_class
=argparse
.RawDescriptionHelpFormatter
)
47 parser
.add_argument('input', help='input file')
48 parser
.add_argument('values', nargs
='*', help='several KEY=VALUE pairs')
49 parser
.add_argument('-o', '--output', required
=True,
51 args
= parser
.parse_args()
54 for value
in args
.values
:
55 key
, val
= value
.split('=', 1)
57 print('duplicate key "%s" in args' % key
, file=sys
.stderr
)
59 values
[key
] = val
.replace('\\n', '\n')
60 unused_values
= set(values
.keys())
62 # Matches e.g. '${FOO}' or '@FOO@' and captures FOO in group 1 or 2.
63 var_re
= re
.compile(r
'\$\{([^}]*)\}|@([^@]*)@')
65 with
open(args
.input) as f
:
66 in_lines
= f
.readlines()
68 for in_line
in in_lines
:
70 key
= m
.group(1) or m
.group(2)
71 unused_values
.discard(key
)
73 in_line
= var_re
.sub(repl
, in_line
)
74 if in_line
.startswith('#cmakedefine01 '):
75 _
, var
= in_line
.split()
76 in_line
= '#define %s %d\n' % (var
, 1 if values
[var
] else 0)
77 unused_values
.discard(var
)
78 elif in_line
.startswith('#cmakedefine '):
79 _
, var
= in_line
.split(None, 1)
81 var
, val
= var
.split(None, 1)
82 in_line
= '#define %s %s' % (var
, val
) # val ends in \n.
85 in_line
= '#define %s\n' % var
87 in_line
= '/* #undef %s */\n' % var
88 unused_values
.discard(var
)
89 out_lines
.append(in_line
)
92 print('unused values args:', file=sys
.stderr
)
93 print(' ' + '\n '.join(unused_values
), file=sys
.stderr
)
96 output
= ''.join(out_lines
)
98 leftovers
= var_re
.findall(output
)
101 'unprocessed values:\n',
102 '\n'.join([x
[0] or x
[1] for x
in leftovers
]),
107 with
open(args
.output
) as f
:
110 if not os
.path
.exists(args
.output
) or read(args
.output
) != output
:
111 with
open(args
.output
, 'w') as f
:
113 os
.chmod(args
.output
, os
.stat(args
.input).st_mode
& 0o777)
116 if __name__
== '__main__':