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.
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 if values
[var
] == '0':
77 print('error: "%s=0" used with #cmakedefine01 %s' % (var
, var
))
78 print(" '0' evaluates as truthy with #cmakedefine01")
79 print(' use "%s=" instead' % var
)
81 in_line
= '#define %s %d\n' % (var
, 1 if values
[var
] else 0)
82 unused_values
.discard(var
)
83 elif in_line
.startswith('#cmakedefine '):
84 _
, var
= in_line
.split(None, 1)
86 var
, val
= var
.split(None, 1)
87 in_line
= '#define %s %s' % (var
, val
) # val ends in \n.
90 in_line
= '#define %s\n' % var
92 in_line
= '/* #undef %s */\n' % var
93 unused_values
.discard(var
)
94 out_lines
.append(in_line
)
97 print('unused values args:', file=sys
.stderr
)
98 print(' ' + '\n '.join(unused_values
), file=sys
.stderr
)
101 output
= ''.join(out_lines
)
103 leftovers
= var_re
.findall(output
)
106 'unprocessed values:\n',
107 '\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__':