[AMDGPU] prevent shrinking udiv/urem if either operand is in (SignedMax,UnsignedMax...
[llvm-project.git] / llvm / utils / gn / build / write_cmake_config.py
bloba14df6b2cdeab415840ebba496a519096cd3ffa2
1 #!/usr/bin/env python3
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 import argparse
36 import os
37 import re
38 import sys
41 def main():
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()
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 1
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()
64 out_lines = []
65 for in_line in in_lines:
67 def repl(m):
68 key = m.group(1) or m.group(2)
69 unused_values.discard(key)
70 return values[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)
79 return 1
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)
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" % var
90 if not values[var]:
91 in_line = "/* #undef %s */\n" % var
92 unused_values.discard(var)
93 out_lines.append(in_line)
95 if unused_values:
96 print("unused values args:", file=sys.stderr)
97 print(" " + "\n ".join(unused_values), file=sys.stderr)
98 return 1
100 output = "".join(out_lines)
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,
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())