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