[ORC] Add std::tuple support to SimplePackedSerialization.
[llvm-project.git] / llvm / utils / gn / build / write_cmake_config.py
blob4fb9031795e661df67cdad9fb634f2a15a426d73
1 #!/usr/bin/env python
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
6 of at generator time.
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:
21 #define FOO 1
22 #define FOO 0
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:
28 #define FOO [...]
29 /* #undef FOO */
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.
33 """
35 from __future__ import print_function
37 import argparse
38 import os
39 import re
40 import sys
43 def main():
44 parser = argparse.ArgumentParser(
45 epilog=__doc__,
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,
50 help='output file')
51 args = parser.parse_args()
53 values = {}
54 for value in args.values:
55 key, val = value.split('=', 1)
56 if key in values:
57 print('duplicate key "%s" in args' % key, file=sys.stderr)
58 return 1
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()
67 out_lines = []
68 for in_line in in_lines:
69 def repl(m):
70 key = m.group(1) or m.group(2)
71 unused_values.discard(key)
72 return values[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)
80 return 1
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)
85 try:
86 var, val = var.split(None, 1)
87 in_line = '#define %s %s' % (var, val) # val ends in \n.
88 except:
89 var = var.rstrip()
90 in_line = '#define %s\n' % var
91 if not values[var]:
92 in_line = '/* #undef %s */\n' % var
93 unused_values.discard(var)
94 out_lines.append(in_line)
96 if unused_values:
97 print('unused values args:', file=sys.stderr)
98 print(' ' + '\n '.join(unused_values), file=sys.stderr)
99 return 1
101 output = ''.join(out_lines)
103 leftovers = var_re.findall(output)
104 if leftovers:
105 print(
106 'unprocessed values:\n',
107 '\n'.join([x[0] or x[1] for x in leftovers]),
108 file=sys.stderr)
109 return 1
111 def read(filename):
112 with open(args.output) as f:
113 return f.read()
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)
121 if __name__ == '__main__':
122 sys.exit(main())