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
|
#!/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)",
"clocale": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
"codecvt": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
"fstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
"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'
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()
|