1#!/usr/bin/env python 2 3import glob 4import os 5import posixpath 6import re 7 8 9def get_libcxx_paths(): 10 utils_path = os.path.dirname(os.path.abspath(__file__)) 11 script_name = os.path.basename(__file__) 12 assert os.path.exists(utils_path) 13 src_root = os.path.dirname(utils_path) 14 include_path = os.path.join(src_root, 'include') 15 assert os.path.exists(include_path) 16 libcxx_test_path = os.path.join(src_root, 'test', 'libcxx') 17 assert os.path.exists(libcxx_test_path) 18 return script_name, src_root, include_path, libcxx_test_path 19 20 21script_name, source_root, include_path, libcxx_test_path = get_libcxx_paths() 22 23header_markup = { 24 "atomic": ["ifndef _LIBCPP_HAS_NO_THREADS"], 25 "barrier": ["ifndef _LIBCPP_HAS_NO_THREADS"], 26 "future": ["ifndef _LIBCPP_HAS_NO_THREADS"], 27 "latch": ["ifndef _LIBCPP_HAS_NO_THREADS"], 28 "mutex": ["ifndef _LIBCPP_HAS_NO_THREADS"], 29 "shared_mutex": ["ifndef _LIBCPP_HAS_NO_THREADS"], 30 "semaphore": ["ifndef _LIBCPP_HAS_NO_THREADS"], 31 "thread": ["ifndef _LIBCPP_HAS_NO_THREADS"], 32 33 "filesystem": ["ifndef _LIBCPP_HAS_NO_FILESYSTEM_LIBRARY"], 34 "experimental/filesystem": ["ifndef _LIBCPP_HAS_NO_FILESYSTEM_LIBRARY"], 35 36 "clocale": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], 37 "codecvt": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], 38 "fstream": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], 39 "iomanip": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], 40 "ios": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], 41 "iostream": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], 42 "istream": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], 43 "locale": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], 44 "locale.h": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], 45 "ostream": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], 46 "regex": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], 47 "sstream": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], 48 "streambuf": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], 49 "strstream": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], 50 51 "experimental/coroutine": ["if defined(__cpp_coroutines)"], 52 "experimental/regex": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], 53} 54 55allowed_extensions = ['', '.h'] 56indent_width = 4 57 58 59begin_pattern = """\ 60//////////////////////////////////////////////////////////////////////////////// 61// BEGIN-GENERATED-HEADERS 62//////////////////////////////////////////////////////////////////////////////// 63""" 64 65warning_note = """\ 66// WARNING: This test was generated by {script_name} 67// and should not be edited manually. 68 69""".format(script_name=script_name) 70 71end_pattern = """\ 72//////////////////////////////////////////////////////////////////////////////// 73// END-GENERATED-HEADERS 74//////////////////////////////////////////////////////////////////////////////// 75""" 76 77generated_part_pattern = re.compile(re.escape(begin_pattern) + ".*" + re.escape(end_pattern), 78 re.MULTILINE | re.DOTALL) 79 80headers_template = """\ 81// Top level headers 82{top_level_headers} 83 84// experimental headers 85#if __cplusplus >= 201103L 86{experimental_headers} 87#endif // __cplusplus >= 201103L 88 89// extended headers 90{extended_headers} 91""" 92 93 94def should_keep_header(p, exclusions=None): 95 if os.path.isdir(p): 96 return False 97 98 if exclusions: 99 relpath = os.path.relpath(p, include_path) 100 relpath = posixpath.join(*os.path.split(relpath)) 101 if relpath in exclusions: 102 return False 103 104 return os.path.splitext(p)[1] in allowed_extensions 105 106 107def produce_include(relpath, indent_level, post_include=None): 108 relpath = posixpath.join(*os.path.split(relpath)) 109 template = "{preambule}#{indentation}include <{include}>{post_include}{postambule}" 110 111 base_indentation = ' '*(indent_width * indent_level) 112 next_indentation = base_indentation + ' '*(indent_width) 113 post_include = "\n{}".format(post_include) if post_include else '' 114 115 markup = header_markup.get(relpath, None) 116 if markup: 117 preambule = '#{indentation}{directive}\n'.format( 118 directive=markup[0], 119 indentation=base_indentation, 120 ) 121 postambule = '\n#{indentation}endif'.format( 122 indentation=base_indentation, 123 ) 124 indentation = next_indentation 125 else: 126 preambule = '' 127 postambule = '' 128 indentation = base_indentation 129 130 return template.format( 131 include=relpath, 132 post_include=post_include, 133 preambule=preambule, 134 postambule=postambule, 135 indentation=indentation, 136 ) 137 138 139def produce_headers(path_parts, indent_level, post_include=None, exclusions=None): 140 pattern = os.path.join(*path_parts, '[a-z]*') 141 142 files = sorted(glob.glob(pattern, recursive=False)) 143 144 include_headers = [ 145 produce_include(os.path.relpath(p, include_path), 146 indent_level, post_include=post_include) 147 for p in files 148 if should_keep_header(p, exclusions) 149 ] 150 151 return '\n'.join(include_headers) 152 153 154def produce_top_level_headers(post_include=None, exclusions=None): 155 return produce_headers([include_path], 0, post_include=post_include, exclusions=exclusions) 156 157 158def produce_experimental_headers(post_include=None, exclusions=None): 159 return produce_headers([include_path, 'experimental'], 1, post_include=post_include, exclusions=exclusions) 160 161 162def produce_extended_headers(post_include=None, exclusions=None): 163 return produce_headers([include_path, 'ext'], 0, post_include=post_include, exclusions=exclusions) 164 165 166def replace_generated_headers(test_path, test_str): 167 with open(test_path, 'r') as f: 168 content = f.read() 169 170 preambule = begin_pattern + '\n// clang-format off\n\n' + warning_note 171 postambule = '\n// clang-format on\n\n' + end_pattern 172 content = generated_part_pattern.sub( 173 preambule + test_str + postambule, content) 174 175 with open(test_path, 'w', newline='\n') as f: 176 f.write(content) 177 178 179def produce_test(test_filename, exclusions=None, post_include=None): 180 test_str = headers_template.format( 181 top_level_headers=produce_top_level_headers( 182 post_include=post_include, 183 exclusions=exclusions, 184 ), 185 experimental_headers=produce_experimental_headers( 186 post_include=post_include, 187 ), 188 extended_headers=produce_extended_headers( 189 post_include=post_include, 190 ), 191 ) 192 193 replace_generated_headers(os.path.join( 194 libcxx_test_path, test_filename), test_str) 195 196 197def main(): 198 produce_test('double_include.sh.cpp') 199 produce_test('min_max_macros.compile.pass.cpp', 200 post_include='TEST_MACROS();') 201 produce_test('no_assert_include.compile.pass.cpp', 202 exclusions=['cassert']) 203 204 205if __name__ == '__main__': 206 main() 207