[LLD][COFF] Ignore DEBUG_S_XFGHASH_TYPE/VIRTUAL
[llvm-project.git] / libcxx / utils / generate_header_tests.py
blob897e0228d0673ae39c73f2b5f86d82e52f2497ab
1 #!/usr/bin/env python
3 import contextlib
4 import glob
5 import io
6 import os
7 import pathlib
8 import re
10 header_restrictions = {
11 "barrier": "!defined(_LIBCPP_HAS_NO_THREADS)",
12 "future": "!defined(_LIBCPP_HAS_NO_THREADS)",
13 "latch": "!defined(_LIBCPP_HAS_NO_THREADS)",
14 "mutex": "!defined(_LIBCPP_HAS_NO_THREADS)",
15 "semaphore": "!defined(_LIBCPP_HAS_NO_THREADS)",
16 "shared_mutex": "!defined(_LIBCPP_HAS_NO_THREADS)",
17 "stdatomic.h": "__cplusplus > 202002L && !defined(_LIBCPP_HAS_NO_THREADS)",
18 "thread": "!defined(_LIBCPP_HAS_NO_THREADS)",
20 "filesystem": "!defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY)",
22 "clocale": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
23 "codecvt": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
24 "fstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
25 "iomanip": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
26 "ios": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
27 "iostream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
28 "istream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
29 "locale.h": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
30 "locale": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
31 "ostream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
32 "regex": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
33 "sstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
34 "streambuf": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
35 "strstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
37 "wctype.h": "!defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)",
38 "cwctype": "!defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)",
39 "cwchar": "!defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)",
40 "wchar.h": "!defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)",
42 "experimental/algorithm": "__cplusplus >= 201103L",
43 "experimental/coroutine": "__cplusplus >= 201103L && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES)",
44 "experimental/deque": "__cplusplus >= 201103L",
45 "experimental/forward_list": "__cplusplus >= 201103L",
46 "experimental/functional": "__cplusplus >= 201103L",
47 "experimental/iterator": "__cplusplus >= 201103L",
48 "experimental/list": "__cplusplus >= 201103L",
49 "experimental/map": "__cplusplus >= 201103L",
50 "experimental/memory_resource": "__cplusplus >= 201103L",
51 "experimental/propagate_const": "__cplusplus >= 201103L",
52 "experimental/regex": "!defined(_LIBCPP_HAS_NO_LOCALIZATION) && __cplusplus >= 201103L",
53 "experimental/set": "__cplusplus >= 201103L",
54 "experimental/simd": "__cplusplus >= 201103L",
55 "experimental/span": "__cplusplus >= 201103L",
56 "experimental/string": "__cplusplus >= 201103L",
57 "experimental/type_traits": "__cplusplus >= 201103L",
58 "experimental/unordered_map": "__cplusplus >= 201103L",
59 "experimental/unordered_set": "__cplusplus >= 201103L",
60 "experimental/utility": "__cplusplus >= 201103L",
61 "experimental/vector": "__cplusplus >= 201103L",
64 private_headers_still_public_in_modules = [
65 '__assert', '__bsd_locale_defaults.h', '__bsd_locale_fallbacks.h', '__config',
66 '__config_site.in', '__debug', '__hash_table',
67 '__threading_support', '__tree', '__undef_macros', '__verbose_abort'
70 def find_script(file):
71 """Finds the script used to generate a file inside the file itself. The script is delimited by
72 BEGIN-SCRIPT and END-SCRIPT markers.
73 """
74 with open(file, 'r') as f:
75 content = f.read()
77 match = re.search(r'^BEGIN-SCRIPT$(.+)^END-SCRIPT$', content, flags=re.MULTILINE | re.DOTALL)
78 if not match:
79 raise RuntimeError("Was unable to find a script delimited with BEGIN-SCRIPT/END-SCRIPT markers in {}".format(test_file))
80 return match.group(1)
82 def execute_script(script, variables):
83 """Executes the provided Mako template with the given variables available during the
84 evaluation of the script, and returns the result.
85 """
86 code = compile(script, 'fake-filename', 'exec')
87 output = io.StringIO()
88 with contextlib.redirect_stdout(output):
89 exec(code, variables)
90 output = output.getvalue()
91 return output
93 def generate_new_file(file, new_content):
94 """Generates the new content of the file by inserting the new content in-between
95 two '// GENERATED-MARKER' markers located in the file.
96 """
97 with open(file, 'r') as f:
98 old_content = f.read()
100 try:
101 before, begin_marker, _, end_marker, after = re.split(r'(// GENERATED-MARKER\n)', old_content, flags=re.MULTILINE | re.DOTALL)
102 except ValueError:
103 raise RuntimeError("Failed to split {} based on markers, please make sure the file has exactly two '// GENERATED-MARKER' occurrences".format(file))
105 return before + begin_marker + new_content + end_marker + after
107 def produce(test_file, variables):
108 script = find_script(test_file)
109 result = execute_script(script, variables)
110 new_content = generate_new_file(test_file, result)
111 with open(test_file, 'w', newline='\n') as f:
112 f.write(new_content)
114 def is_header(file):
115 """Returns whether the given file is a header (i.e. not a directory or the modulemap file)."""
116 return not file.is_dir() and not file.name == 'module.modulemap.in'
118 def main():
119 monorepo_root = pathlib.Path(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
120 include = pathlib.Path(os.path.join(monorepo_root, 'libcxx', 'include'))
121 test = pathlib.Path(os.path.join(monorepo_root, 'libcxx', 'test'))
122 assert(monorepo_root.exists())
124 toplevel_headers = sorted(str(p.relative_to(include)) for p in include.glob('[a-z]*') if is_header(p))
125 experimental_headers = sorted(str(p.relative_to(include)) for p in include.glob('experimental/[a-z]*') if is_header(p))
126 extended_headers = sorted(str(p.relative_to(include)) for p in include.glob('ext/[a-z]*') if is_header(p))
127 public_headers = toplevel_headers + experimental_headers + extended_headers
128 private_headers = sorted(str(p.relative_to(include)) for p in include.rglob('*') if is_header(p) and str(p.relative_to(include)).startswith('__'))
129 variables = {
130 'toplevel_headers': toplevel_headers,
131 'experimental_headers': experimental_headers,
132 'extended_headers': extended_headers,
133 'public_headers': public_headers,
134 'private_headers': private_headers,
135 'header_restrictions': header_restrictions,
136 'private_headers_still_public_in_modules': private_headers_still_public_in_modules
139 produce(test.joinpath('libcxx/assertions/headers_declare_verbose_abort.sh.cpp'), variables)
140 produce(test.joinpath('libcxx/clang_tidy.sh.cpp'), variables)
141 produce(test.joinpath('libcxx/double_include.sh.cpp'), variables)
142 produce(test.joinpath('libcxx/min_max_macros.compile.pass.cpp'), variables)
143 produce(test.joinpath('libcxx/modules_include.sh.cpp'), variables)
144 produce(test.joinpath('libcxx/nasty_macros.compile.pass.cpp'), variables)
145 produce(test.joinpath('libcxx/no_assert_include.compile.pass.cpp'), variables)
146 produce(test.joinpath('libcxx/private_headers.verify.cpp'), variables)
147 produce(test.joinpath('libcxx/transitive_includes.sh.cpp'), variables)
150 if __name__ == '__main__':
151 main()