1import itertools 2import os 3import platform 4import re 5import subprocess 6import sys 7import errno 8 9import lit.util 10from lit.llvm.subst import FindTool 11from lit.llvm.subst import ToolSubst 12 13lit_path_displayed = False 14 15class LLVMConfig(object): 16 17 def __init__(self, lit_config, config): 18 self.lit_config = lit_config 19 self.config = config 20 21 features = config.available_features 22 23 self.use_lit_shell = False 24 # Tweak PATH for Win32 to decide to use bash.exe or not. 25 if sys.platform == 'win32': 26 # Seek necessary tools in directories and set to $PATH. 27 path = None 28 lit_tools_dir = getattr(config, 'lit_tools_dir', None) 29 required_tools = [ 30 'cmp.exe', 'grep.exe', 'sed.exe', 'diff.exe', 'echo.exe'] 31 path = self.lit_config.getToolsPath(lit_tools_dir, 32 config.environment['PATH'], 33 required_tools) 34 if path is None: 35 path = self._find_git_windows_unix_tools(required_tools) 36 if path is not None: 37 self.with_environment('PATH', path, append_path=True) 38 # Many tools behave strangely if these environment variables aren't 39 # set. 40 self.with_system_environment( 41 ['SystemDrive', 'SystemRoot', 'TEMP', 'TMP', 'PLATFORM']) 42 self.use_lit_shell = True 43 44 global lit_path_displayed 45 if not self.lit_config.quiet and lit_path_displayed is False: 46 self.lit_config.note("using lit tools: {}".format(path)) 47 lit_path_displayed = True 48 49 # Choose between lit's internal shell pipeline runner and a real shell. 50 # If LIT_USE_INTERNAL_SHELL is in the environment, we use that as an 51 # override. 52 lit_shell_env = os.environ.get('LIT_USE_INTERNAL_SHELL') 53 if lit_shell_env: 54 self.use_lit_shell = lit.util.pythonize_bool(lit_shell_env) 55 56 if not self.use_lit_shell: 57 features.add('shell') 58 59 self.with_system_environment([ 60 'ASAN_SYMBOLIZER_PATH', 61 'HWASAN_SYMBOLIZER_PATH', 62 'MSAN_SYMBOLIZER_PATH', 63 'TSAN_SYMBOLIZER_PATH', 64 'UBSAN_SYMBOLIZER_PATH' 65 'ASAN_OPTIONS', 66 'HWASAN_OPTIONS', 67 'MSAN_OPTIONS', 68 'TSAN_OPTIONS', 69 'UBSAN_OPTIONS', 70 ]) 71 72 # Running on Darwin OS 73 if platform.system() == 'Darwin': 74 # FIXME: lld uses the first, other projects use the second. 75 # We should standardize on the former. 76 features.add('system-linker-mach-o') 77 features.add('system-darwin') 78 elif platform.system() == 'Windows': 79 # For tests that require Windows to run. 80 features.add('system-windows') 81 elif platform.system() == 'Linux': 82 features.add('system-linux') 83 elif platform.system() in ['FreeBSD']: 84 features.add('system-freebsd') 85 elif platform.system() == 'NetBSD': 86 features.add('system-netbsd') 87 elif platform.system() == 'AIX': 88 features.add('system-aix') 89 elif platform.system() == 'SunOS': 90 features.add('system-solaris') 91 elif platform.system() == 'OS/390': 92 features.add('system-zos') 93 94 # Native compilation: host arch == default triple arch 95 # Both of these values should probably be in every site config (e.g. as 96 # part of the standard header. But currently they aren't) 97 host_triple = getattr(config, 'host_triple', None) 98 target_triple = getattr(config, 'target_triple', None) 99 features.add('target=%s' % target_triple) 100 if host_triple and host_triple == target_triple: 101 features.add('native') 102 103 # Sanitizers. 104 sanitizers = getattr(config, 'llvm_use_sanitizer', '') 105 sanitizers = frozenset(x.lower() for x in sanitizers.split(';')) 106 if 'address' in sanitizers: 107 features.add('asan') 108 if 'hwaddress' in sanitizers: 109 features.add('hwasan') 110 if 'memory' in sanitizers or 'memorywithorigins' in sanitizers: 111 features.add('msan') 112 if 'undefined' in sanitizers: 113 features.add('ubsan') 114 115 have_zlib = getattr(config, 'have_zlib', None) 116 if have_zlib: 117 features.add('zlib') 118 have_zstd = getattr(config, 'have_zstd', None) 119 if have_zstd: 120 features.add('zstd') 121 122 # Check if we should run long running tests. 123 long_tests = lit_config.params.get('run_long_tests', None) 124 if lit.util.pythonize_bool(long_tests): 125 features.add('long_tests') 126 127 if target_triple: 128 if re.match(r'^x86_64.*-apple', target_triple): 129 features.add('x86_64-apple') 130 host_cxx = getattr(config, 'host_cxx', None) 131 if ('address' in sanitizers and 132 self.get_clang_has_lsan(host_cxx, target_triple)): 133 self.with_environment( 134 'ASAN_OPTIONS', 'detect_leaks=1', append_path=True) 135 if re.match(r'^x86_64.*-linux', target_triple): 136 features.add('x86_64-linux') 137 if re.match(r'^i.86.*', target_triple): 138 features.add('target-x86') 139 elif re.match(r'^x86_64.*', target_triple): 140 features.add('target-x86_64') 141 elif re.match(r'^aarch64.*', target_triple): 142 features.add('target-aarch64') 143 elif re.match(r'^arm64.*', target_triple): 144 features.add('target-aarch64') 145 elif re.match(r'^arm.*', target_triple): 146 features.add('target-arm') 147 148 use_gmalloc = lit_config.params.get('use_gmalloc', None) 149 if lit.util.pythonize_bool(use_gmalloc): 150 # Allow use of an explicit path for gmalloc library. 151 # Will default to '/usr/lib/libgmalloc.dylib' if not set. 152 gmalloc_path_str = lit_config.params.get( 153 'gmalloc_path', '/usr/lib/libgmalloc.dylib') 154 if gmalloc_path_str is not None: 155 self.with_environment( 156 'DYLD_INSERT_LIBRARIES', gmalloc_path_str) 157 158 def _find_git_windows_unix_tools(self, tools_needed): 159 assert(sys.platform == 'win32') 160 if sys.version_info.major >= 3: 161 import winreg 162 else: 163 import _winreg as winreg 164 165 # Search both the 64 and 32-bit hives, as well as HKLM + HKCU 166 masks = [0, winreg.KEY_WOW64_64KEY] 167 hives = [winreg.HKEY_LOCAL_MACHINE, winreg.HKEY_CURRENT_USER] 168 for mask, hive in itertools.product(masks, hives): 169 try: 170 with winreg.OpenKey(hive, r"SOFTWARE\GitForWindows", 0, 171 winreg.KEY_READ | mask) as key: 172 install_root, _ = winreg.QueryValueEx(key, 'InstallPath') 173 174 if not install_root: 175 continue 176 candidate_path = os.path.join(install_root, 'usr', 'bin') 177 if not lit.util.checkToolsPath( 178 candidate_path, tools_needed): 179 continue 180 181 # We found it, stop enumerating. 182 return lit.util.to_string(candidate_path) 183 except: 184 continue 185 186 return None 187 188 def with_environment(self, variable, value, append_path=False): 189 if append_path: 190 # For paths, we should be able to take a list of them and process 191 # all of them. 192 paths_to_add = value 193 if lit.util.is_string(paths_to_add): 194 paths_to_add = [paths_to_add] 195 196 def norm(x): 197 return os.path.normcase(os.path.normpath(x)) 198 199 current_paths = self.config.environment.get(variable, None) 200 if current_paths: 201 current_paths = current_paths.split(os.path.pathsep) 202 paths = [norm(p) for p in current_paths] 203 else: 204 paths = [] 205 206 # If we are passed a list [a b c], then iterating this list forwards 207 # and adding each to the beginning would result in c b a. So we 208 # need to iterate in reverse to end up with the original ordering. 209 for p in reversed(paths_to_add): 210 # Move it to the front if it already exists, otherwise insert 211 # it at the beginning. 212 p = norm(p) 213 try: 214 paths.remove(p) 215 except ValueError: 216 pass 217 paths = [p] + paths 218 value = os.pathsep.join(paths) 219 self.config.environment[variable] = value 220 221 def with_system_environment(self, variables, append_path=False): 222 if lit.util.is_string(variables): 223 variables = [variables] 224 for v in variables: 225 value = os.environ.get(v) 226 if value: 227 self.with_environment(v, value, append_path) 228 229 def clear_environment(self, variables): 230 for name in variables: 231 if name in self.config.environment: 232 del self.config.environment[name] 233 234 def get_process_output(self, command): 235 try: 236 cmd = subprocess.Popen( 237 command, stdout=subprocess.PIPE, 238 stderr=subprocess.PIPE, env=self.config.environment) 239 stdout, stderr = cmd.communicate() 240 stdout = lit.util.to_string(stdout) 241 stderr = lit.util.to_string(stderr) 242 return (stdout, stderr) 243 except OSError: 244 self.lit_config.fatal('Could not run process %s' % command) 245 246 def feature_config(self, features): 247 # Ask llvm-config about the specified feature. 248 arguments = [x for (x, _) in features] 249 config_path = os.path.join(self.config.llvm_tools_dir, 'llvm-config') 250 251 output, _ = self.get_process_output([config_path] + arguments) 252 lines = output.split('\n') 253 254 for (feature_line, (_, patterns)) in zip(lines, features): 255 # We should have either a callable or a dictionary. If it's a 256 # dictionary, grep each key against the output and use the value if 257 # it matches. If it's a callable, it does the entire translation. 258 if callable(patterns): 259 features_to_add = patterns(feature_line) 260 self.config.available_features.update(features_to_add) 261 else: 262 for (re_pattern, feature) in patterns.items(): 263 if re.search(re_pattern, feature_line): 264 self.config.available_features.add(feature) 265 266 # Note that when substituting %clang_cc1 also fill in the include directory 267 # of the builtin headers. Those are part of even a freestanding 268 # environment, but Clang relies on the driver to locate them. 269 def get_clang_builtin_include_dir(self, clang): 270 # FIXME: Rather than just getting the version, we should have clang 271 # print out its resource dir here in an easy to scrape form. 272 clang_dir, _ = self.get_process_output( 273 [clang, '-print-file-name=include']) 274 275 if not clang_dir: 276 print(clang) 277 self.lit_config.fatal( 278 "Couldn't find the include dir for Clang ('%s')" % clang) 279 280 clang_dir = clang_dir.strip() 281 if sys.platform in ['win32'] and not self.use_lit_shell: 282 # Don't pass dosish path separator to msys bash.exe. 283 clang_dir = clang_dir.replace('\\', '/') 284 # Ensure the result is an ascii string, across Python2.5+ - Python3. 285 return clang_dir 286 287 # On macOS, LSan is only supported on clang versions 5 and higher 288 def get_clang_has_lsan(self, clang, triple): 289 if not clang: 290 self.lit_config.warning( 291 'config.host_cxx is unset but test suite is configured ' 292 'to use sanitizers.') 293 return False 294 295 clang_binary = clang.split()[0] 296 version_string, _ = self.get_process_output( 297 [clang_binary, '--version']) 298 if not 'clang' in version_string: 299 self.lit_config.warning( 300 "compiler '%s' does not appear to be clang, " % clang_binary + 301 'but test suite is configured to use sanitizers.') 302 return False 303 304 if re.match(r'.*-linux', triple): 305 return True 306 307 if re.match(r'^x86_64.*-apple', triple): 308 version_regex = re.search(r'version ([0-9]+)\.([0-9]+).([0-9]+)', 309 version_string) 310 major_version_number = int(version_regex.group(1)) 311 minor_version_number = int(version_regex.group(2)) 312 patch_version_number = int(version_regex.group(3)) 313 if ('Apple LLVM' in version_string or 314 'Apple clang' in version_string): 315 # Apple clang doesn't yet support LSan 316 return False 317 return major_version_number >= 5 318 319 return False 320 321 def make_itanium_abi_triple(self, triple): 322 m = re.match(r'(\w+)-(\w+)-(\w+)', triple) 323 if not m: 324 self.lit_config.fatal( 325 "Could not turn '%s' into Itanium ABI triple" % triple) 326 if m.group(3).lower() != 'windows': 327 # All non-windows triples use the Itanium ABI. 328 return triple 329 return m.group(1) + '-' + m.group(2) + '-' + m.group(3) + '-gnu' 330 331 def make_msabi_triple(self, triple): 332 m = re.match(r'(\w+)-(\w+)-(\w+)', triple) 333 if not m: 334 self.lit_config.fatal( 335 "Could not turn '%s' into MS ABI triple" % triple) 336 isa = m.group(1).lower() 337 vendor = m.group(2).lower() 338 os = m.group(3).lower() 339 if os == 'windows' and re.match(r'.*-msvc$', triple): 340 # If the OS is windows and environment is msvc, we're done. 341 return triple 342 if isa.startswith('x86') or isa == 'amd64' or re.match(r'i\d86', isa): 343 # For x86 ISAs, adjust the OS. 344 return isa + '-' + vendor + '-windows-msvc' 345 # -msvc is not supported for non-x86 targets; use a default. 346 return 'i686-pc-windows-msvc' 347 348 def add_tool_substitutions(self, tools, search_dirs=None): 349 if not search_dirs: 350 search_dirs = [self.config.llvm_tools_dir] 351 352 if lit.util.is_string(search_dirs): 353 search_dirs = [search_dirs] 354 355 tools = [x if isinstance(x, ToolSubst) else ToolSubst(x) 356 for x in tools] 357 358 search_dirs = os.pathsep.join(search_dirs) 359 substitutions = [] 360 361 for tool in tools: 362 match = tool.resolve(self, search_dirs) 363 364 # Either no match occurred, or there was an unresolved match that 365 # is ignored. 366 if not match: 367 continue 368 369 subst_key, tool_pipe, command = match 370 371 # An unresolved match occurred that can't be ignored. Fail without 372 # adding any of the previously-discovered substitutions. 373 if not command: 374 return False 375 376 substitutions.append((subst_key, tool_pipe + command)) 377 378 self.config.substitutions.extend(substitutions) 379 return True 380 381 def add_err_msg_substitutions(self): 382 # Python's strerror may not supply the same message 383 # as C++ std::error_code. One example of such a platform is 384 # Visual Studio. errc_messages may be supplied which contains the error 385 # messages for ENOENT, EISDIR, EINVAL and EACCES as a semi colon 386 # separated string. LLVM testsuites can use get_errc_messages in cmake 387 # to automatically get the messages and pass them into lit. 388 errc_messages = getattr(self.config, 'errc_messages', '') 389 if len(errc_messages) != 0: 390 (errc_enoent, errc_eisdir, 391 errc_einval, errc_eacces) = errc_messages.split(';') 392 self.config.substitutions.append( 393 ('%errc_ENOENT', '\'' + errc_enoent + '\'')) 394 self.config.substitutions.append( 395 ('%errc_EISDIR', '\'' + errc_eisdir + '\'')) 396 self.config.substitutions.append( 397 ('%errc_EINVAL', '\'' + errc_einval + '\'')) 398 self.config.substitutions.append( 399 ('%errc_EACCES', '\'' + errc_eacces + '\'')) 400 else: 401 self.config.substitutions.append( 402 ('%errc_ENOENT', '\'' + os.strerror(errno.ENOENT) + '\'')) 403 self.config.substitutions.append( 404 ('%errc_EISDIR', '\'' + os.strerror(errno.EISDIR) + '\'')) 405 self.config.substitutions.append( 406 ('%errc_EINVAL', '\'' + os.strerror(errno.EINVAL) + '\'')) 407 self.config.substitutions.append( 408 ('%errc_EACCES', '\'' + os.strerror(errno.EACCES) + '\'')) 409 410 def use_default_substitutions(self): 411 tool_patterns = [ 412 ToolSubst('FileCheck', unresolved='fatal'), 413 # Handle these specially as they are strings searched for during 414 # testing. 415 ToolSubst(r'\| \bcount\b', command=FindTool('count'), 416 verbatim=True, unresolved='fatal'), 417 ToolSubst(r'\| \bnot\b', command=FindTool('not'), 418 verbatim=True, unresolved='fatal')] 419 420 self.config.substitutions.append(('%python', '"%s"' % (sys.executable))) 421 422 self.add_tool_substitutions( 423 tool_patterns, [self.config.llvm_tools_dir]) 424 425 self.add_err_msg_substitutions() 426 427 def use_llvm_tool(self, name, search_env=None, required=False, quiet=False, 428 search_paths=None, use_installed=False): 429 """Find the executable program 'name', optionally using the specified 430 environment variable as an override before searching the build directory 431 and then optionally the configuration's PATH.""" 432 # If the override is specified in the environment, use it without 433 # validation. 434 tool = None 435 if search_env: 436 tool = self.config.environment.get(search_env) 437 438 if not tool: 439 if search_paths is None: 440 search_paths = [self.config.llvm_tools_dir] 441 # Use the specified search paths. 442 path = os.pathsep.join(search_paths) 443 tool = lit.util.which(name, path) 444 445 if not tool and use_installed: 446 # Otherwise look in the path, if enabled. 447 tool = lit.util.which(name, self.config.environment['PATH']) 448 449 if required and not tool: 450 message = "couldn't find '{}' program".format(name) 451 if search_env: 452 message = message + \ 453 ', try setting {} in your environment'.format(search_env) 454 self.lit_config.fatal(message) 455 456 if tool: 457 tool = os.path.normpath(tool) 458 if not self.lit_config.quiet and not quiet: 459 self.lit_config.note('using {}: {}'.format(name, tool)) 460 return tool 461 462 def use_clang(self, additional_tool_dirs=[], additional_flags=[], 463 required=True, use_installed=False): 464 """Configure the test suite to be able to invoke clang. 465 466 Sets up some environment variables important to clang, locates a 467 just-built or optionally an installed clang, and add a set of standard 468 substitutions useful to any test suite that makes use of clang. 469 470 """ 471 # Clear some environment variables that might affect Clang. 472 # 473 # This first set of vars are read by Clang, but shouldn't affect tests 474 # that aren't specifically looking for these features, or are required 475 # simply to run the tests at all. 476 # 477 # FIXME: Should we have a tool that enforces this? 478 479 # safe_env_vars = ( 480 # 'TMPDIR', 'TEMP', 'TMP', 'USERPROFILE', 'PWD', 481 # 'MACOSX_DEPLOYMENT_TARGET', 'IPHONEOS_DEPLOYMENT_TARGET', 482 # 'VCINSTALLDIR', 'VC100COMNTOOLS', 'VC90COMNTOOLS', 483 # 'VC80COMNTOOLS') 484 possibly_dangerous_env_vars = [ 485 'COMPILER_PATH', 'RC_DEBUG_OPTIONS', 486 'CINDEXTEST_PREAMBLE_FILE', 'LIBRARY_PATH', 487 'CPATH', 'C_INCLUDE_PATH', 'CPLUS_INCLUDE_PATH', 488 'OBJC_INCLUDE_PATH', 'OBJCPLUS_INCLUDE_PATH', 489 'LIBCLANG_TIMING', 'LIBCLANG_OBJTRACKING', 490 'LIBCLANG_LOGGING', 'LIBCLANG_BGPRIO_INDEX', 491 'LIBCLANG_BGPRIO_EDIT', 'LIBCLANG_NOTHREADS', 492 'LIBCLANG_RESOURCE_USAGE', 493 'LIBCLANG_CODE_COMPLETION_LOGGING', 494 ] 495 # Clang/Win32 may refer to %INCLUDE%. vsvarsall.bat sets it. 496 if platform.system() != 'Windows': 497 possibly_dangerous_env_vars.append('INCLUDE') 498 499 self.clear_environment(possibly_dangerous_env_vars) 500 501 # Tweak the PATH to include the tools dir and the scripts dir. 502 # Put Clang first to avoid LLVM from overriding out-of-tree clang 503 # builds. 504 exe_dir_props = [self.config.name.lower() + '_tools_dir', 505 'clang_tools_dir', 'llvm_tools_dir'] 506 paths = [getattr(self.config, pp) for pp in exe_dir_props 507 if getattr(self.config, pp, None)] 508 paths = additional_tool_dirs + paths 509 self.with_environment('PATH', paths, append_path=True) 510 511 lib_dir_props = [ 512 self.config.name.lower() + '_libs_dir', 513 'llvm_shlib_dir', 514 'llvm_libs_dir', 515 ] 516 lib_paths = [getattr(self.config, pp) for pp in lib_dir_props 517 if getattr(self.config, pp, None)] 518 519 self.with_environment('LD_LIBRARY_PATH', lib_paths, append_path=True) 520 521 shl = getattr(self.config, 'llvm_shlib_dir', None) 522 pext = getattr(self.config, 'llvm_plugin_ext', None) 523 if shl: 524 self.config.substitutions.append(('%llvmshlibdir', shl)) 525 if pext: 526 self.config.substitutions.append(('%pluginext', pext)) 527 528 # Discover the 'clang' and 'clangcc' to use. 529 self.config.clang = self.use_llvm_tool( 530 'clang', search_env='CLANG', required=required, 531 search_paths=paths, use_installed=use_installed) 532 if self.config.clang: 533 self.config.available_features.add('clang') 534 builtin_include_dir = self.get_clang_builtin_include_dir( 535 self.config.clang) 536 tool_substitutions = [ 537 ToolSubst('%clang', command=self.config.clang, 538 extra_args=additional_flags), 539 ToolSubst('%clang_analyze_cc1', command='%clang_cc1', 540 extra_args=['-analyze', '%analyze', 541 '-setup-static-analyzer']+additional_flags), 542 ToolSubst('%clang_cc1', command=self.config.clang, 543 extra_args=['-cc1', '-internal-isystem', 544 builtin_include_dir, '-nostdsysteminc'] + 545 additional_flags), 546 ToolSubst('%clang_cpp', command=self.config.clang, 547 extra_args=['--driver-mode=cpp']+additional_flags), 548 ToolSubst('%clang_cl', command=self.config.clang, 549 extra_args=['--driver-mode=cl']+additional_flags), 550 ToolSubst('%clang_dxc', command=self.config.clang, 551 extra_args=['--driver-mode=dxc']+additional_flags), 552 ToolSubst('%clangxx', command=self.config.clang, 553 extra_args=['--driver-mode=g++']+additional_flags), 554 ] 555 self.add_tool_substitutions(tool_substitutions) 556 self.config.substitutions.append( 557 ('%resource_dir', builtin_include_dir)) 558 559 self.config.substitutions.append( 560 ('%itanium_abi_triple', 561 self.make_itanium_abi_triple(self.config.target_triple))) 562 self.config.substitutions.append( 563 ('%ms_abi_triple', 564 self.make_msabi_triple(self.config.target_triple))) 565 566 # The host triple might not be set, at least if we're compiling clang 567 # from an already installed llvm. 568 if (self.config.host_triple and 569 self.config.host_triple != '@LLVM_HOST_TRIPLE@'): 570 self.config.substitutions.append( 571 ('%target_itanium_abi_host_triple', 572 '--target=' + self.make_itanium_abi_triple( 573 self.config.host_triple))) 574 else: 575 self.config.substitutions.append( 576 ('%target_itanium_abi_host_triple', '')) 577 578 # TODO: Many tests work across many language standards. Before 579 # https://discourse.llvm.org/t/lit-run-a-run-line-multiple-times-with-different-replacements/64932 580 # has a solution, provide substitutions to conveniently try every standard with LIT_CLANG_STD_GROUP. 581 clang_std_group = int(os.environ.get('LIT_CLANG_STD_GROUP', '0')) 582 clang_std_values = ('98', '11', '14', '17', '20', '2b') 583 def add_std_cxx(s): 584 t = s[8:] 585 if t.endswith('-'): 586 t += clang_std_values[-1] 587 l = clang_std_values.index(t[0:2] if t[0:2] != '23' else '2b') 588 h = clang_std_values.index(t[3:5]) 589 # Let LIT_CLANG_STD_GROUP=0 pick the highest value (likely the most relevant 590 # standard). 591 l = h - clang_std_group % (h-l+1) 592 self.config.substitutions.append((s, '-std=c++' + clang_std_values[l])) 593 594 add_std_cxx('%std_cxx98-14') 595 add_std_cxx('%std_cxx98-') 596 add_std_cxx('%std_cxx11-14') 597 add_std_cxx('%std_cxx11-') 598 add_std_cxx('%std_cxx14-') 599 add_std_cxx('%std_cxx17-20') 600 add_std_cxx('%std_cxx17-') 601 add_std_cxx('%std_cxx20-') 602 add_std_cxx('%std_cxx23-') 603 604 # FIXME: Find nicer way to prohibit this. 605 def prefer(this, to): 606 return '''\"*** Do not use '%s' in tests, use '%s'. ***\"''' % ( 607 to, this) 608 self.config.substitutions.append( 609 (' clang ', prefer('%clang', 'clang'))) 610 self.config.substitutions.append( 611 (r' clang\+\+ ', prefer('%clangxx', 'clang++'))) 612 self.config.substitutions.append( 613 (' clang-cc ', prefer('%clang_cc1', 'clang-cc'))) 614 self.config.substitutions.append( 615 (' clang-cl ', prefer('%clang_cl', 'clang-cl'))) 616 self.config.substitutions.append( 617 (' clang -cc1 -analyze ', 618 prefer('%clang_analyze_cc1', 'clang -cc1 -analyze'))) 619 self.config.substitutions.append( 620 (' clang -cc1 ', prefer('%clang_cc1', 'clang -cc1'))) 621 self.config.substitutions.append( 622 (' %clang-cc1 ', 623 '''\"*** invalid substitution, use '%clang_cc1'. ***\"''')) 624 self.config.substitutions.append( 625 (' %clang-cpp ', 626 '''\"*** invalid substitution, use '%clang_cpp'. ***\"''')) 627 self.config.substitutions.append( 628 (' %clang-cl ', 629 '''\"*** invalid substitution, use '%clang_cl'. ***\"''')) 630 631 def use_lld(self, additional_tool_dirs=[], required=True, 632 use_installed=False): 633 """Configure the test suite to be able to invoke lld. 634 635 Sets up some environment variables important to lld, locates a 636 just-built or optionally an installed lld, and add a set of standard 637 substitutions useful to any test suite that makes use of lld. 638 639 """ 640 641 # Tweak the PATH to include the tools dir and the scripts dir. 642 exe_dir_props = [self.config.name.lower() + '_tools_dir', 643 'lld_tools_dir', 'llvm_tools_dir'] 644 paths = [getattr(self.config, pp) for pp in exe_dir_props 645 if getattr(self.config, pp, None)] 646 paths = additional_tool_dirs + paths 647 self.with_environment('PATH', paths, append_path=True) 648 649 lib_dir_props = [self.config.name.lower() + '_libs_dir', 650 'lld_libs_dir', 'llvm_shlib_dir', 'llvm_libs_dir'] 651 lib_paths = [getattr(self.config, pp) for pp in lib_dir_props 652 if getattr(self.config, pp, None)] 653 654 self.with_environment('LD_LIBRARY_PATH', lib_paths, append_path=True) 655 656 # Discover the LLD executables to use. 657 658 ld_lld = self.use_llvm_tool('ld.lld', required=required, 659 search_paths=paths, 660 use_installed=use_installed) 661 lld_link = self.use_llvm_tool('lld-link', required=required, 662 search_paths=paths, 663 use_installed=use_installed) 664 ld64_lld = self.use_llvm_tool('ld64.lld', required=required, 665 search_paths=paths, 666 use_installed=use_installed) 667 wasm_ld = self.use_llvm_tool('wasm-ld', required=required, 668 search_paths=paths, 669 use_installed=use_installed) 670 671 was_found = ld_lld and lld_link and ld64_lld and wasm_ld 672 tool_substitutions = [] 673 if ld_lld: 674 tool_substitutions.append(ToolSubst(r'ld\.lld', command=ld_lld)) 675 self.config.available_features.add('ld.lld') 676 if lld_link: 677 tool_substitutions.append(ToolSubst('lld-link', command=lld_link)) 678 self.config.available_features.add('lld-link') 679 if ld64_lld: 680 tool_substitutions.append(ToolSubst(r'ld64\.lld', command=ld64_lld)) 681 self.config.available_features.add('ld64.lld') 682 if wasm_ld: 683 tool_substitutions.append(ToolSubst('wasm-ld', command=wasm_ld)) 684 self.config.available_features.add('wasm-ld') 685 self.add_tool_substitutions(tool_substitutions) 686 687 return was_found 688