1# -*- Python -*- 2 3# Configuration file for the 'lit' test runner. 4 5import os 6import platform 7import shlex 8import shutil 9import subprocess 10 11import lit.formats 12 13# name: The name of this test suite. 14config.name = 'lldb-api' 15 16# suffixes: A list of file extensions to treat as test files. 17config.suffixes = ['.py'] 18 19# test_source_root: The root path where tests are located. 20config.test_source_root = os.path.dirname(__file__) 21 22# test_exec_root: The root path where tests should be run. 23config.test_exec_root = os.path.join(config.lldb_obj_root, 'test', 'API') 24 25def mkdir_p(path): 26 import errno 27 try: 28 os.makedirs(path) 29 except OSError as e: 30 if e.errno != errno.EEXIST: 31 raise 32 if not os.path.isdir(path): 33 raise OSError(errno.ENOTDIR, "%s is not a directory"%path) 34 35 36def find_sanitizer_runtime(name): 37 resource_dir = subprocess.check_output( 38 [config.cmake_cxx_compiler, 39 '-print-resource-dir']).decode('utf-8').strip() 40 return os.path.join(resource_dir, 'lib', 'darwin', name) 41 42 43def find_shlibpath_var(): 44 if platform.system() in ['Linux', 'FreeBSD', 'NetBSD', 'SunOS']: 45 yield 'LD_LIBRARY_PATH' 46 elif platform.system() == 'Darwin': 47 yield 'DYLD_LIBRARY_PATH' 48 elif platform.system() == 'Windows': 49 yield 'PATH' 50 51 52# On macOS, we can't do the DYLD_INSERT_LIBRARIES trick with a shim python 53# binary as the ASan interceptors get loaded too late. Also, when SIP is 54# enabled, we can't inject libraries into system binaries at all, so we need a 55# copy of the "real" python to work with. 56def find_python_interpreter(): 57 # Avoid doing any work if we already copied the binary. 58 copied_python = os.path.join(config.lldb_build_directory, 'copied-python') 59 if os.path.isfile(copied_python): 60 return copied_python 61 62 # Find the "real" python binary. 63 real_python = subprocess.check_output([ 64 config.python_executable, 65 os.path.join(os.path.dirname(os.path.realpath(__file__)), 66 'get_darwin_real_python.py') 67 ]).decode('utf-8').strip() 68 69 shutil.copy(real_python, copied_python) 70 71 # Now make sure the copied Python works. The Python in Xcode has a relative 72 # RPATH and cannot be copied. 73 try: 74 # We don't care about the output, just make sure it runs. 75 subprocess.check_output([copied_python, '-V'], stderr=subprocess.STDOUT) 76 except subprocess.CalledProcessError: 77 # The copied Python didn't work. Assume we're dealing with the Python 78 # interpreter in Xcode. Given that this is not a system binary SIP 79 # won't prevent us form injecting the interceptors so we get away with 80 # not copying the executable. 81 os.remove(copied_python) 82 return real_python 83 84 # The copied Python works. 85 return copied_python 86 87 88def is_configured(attr): 89 """Return the configuration attribute if it exists and None otherwise. 90 91 This allows us to check if the attribute exists before trying to access it.""" 92 return getattr(config, attr, None) 93 94 95def delete_module_cache(path): 96 """Clean the module caches in the test build directory. 97 98 This is necessary in an incremental build whenever clang changes underneath, 99 so doing it once per lit.py invocation is close enough. """ 100 if os.path.isdir(path): 101 print("Deleting module cache at %s." % path) 102 shutil.rmtree(path) 103 104if is_configured('llvm_use_sanitizer'): 105 if 'Address' in config.llvm_use_sanitizer: 106 config.environment['ASAN_OPTIONS'] = 'detect_stack_use_after_return=1' 107 if 'Darwin' in config.host_os and 'x86' in config.host_triple: 108 config.environment['DYLD_INSERT_LIBRARIES'] = find_sanitizer_runtime( 109 'libclang_rt.asan_osx_dynamic.dylib') 110 111 if 'Thread' in config.llvm_use_sanitizer: 112 if 'Darwin' in config.host_os and 'x86' in config.host_triple: 113 config.environment['DYLD_INSERT_LIBRARIES'] = find_sanitizer_runtime( 114 'libclang_rt.tsan_osx_dynamic.dylib') 115 116if 'DYLD_INSERT_LIBRARIES' in config.environment and platform.system() == 'Darwin': 117 config.python_executable = find_python_interpreter() 118 119# Shared library build of LLVM may require LD_LIBRARY_PATH or equivalent. 120if is_configured('shared_libs'): 121 for shlibpath_var in find_shlibpath_var(): 122 # In stand-alone build llvm_shlib_dir specifies LLDB's lib directory while 123 # llvm_libs_dir specifies LLVM's lib directory. 124 shlibpath = os.path.pathsep.join( 125 (config.llvm_shlib_dir, config.llvm_libs_dir, 126 config.environment.get(shlibpath_var, ''))) 127 config.environment[shlibpath_var] = shlibpath 128 else: 129 lit_config.warning("unable to inject shared library path on '{}'".format( 130 platform.system())) 131 132# Support running the test suite under the lldb-repro wrapper. This makes it 133# possible to capture a test suite run and then rerun all the test from the 134# just captured reproducer. 135lldb_repro_mode = lit_config.params.get('lldb-run-with-repro', None) 136if lldb_repro_mode: 137 lit_config.note("Running API tests in {} mode.".format(lldb_repro_mode)) 138 mkdir_p(config.lldb_reproducer_directory) 139 if lldb_repro_mode == 'capture': 140 config.available_features.add('lldb-repro-capture') 141 elif lldb_repro_mode == 'replay': 142 config.available_features.add('lldb-repro-replay') 143 144lldb_use_simulator = lit_config.params.get('lldb-run-with-simulator', None) 145if lldb_use_simulator: 146 if lldb_use_simulator == "ios": 147 lit_config.note("Running API tests on iOS simulator") 148 config.available_features.add('lldb-simulator-ios') 149 elif lldb_use_simulator == "watchos": 150 lit_config.note("Running API tests on watchOS simulator") 151 config.available_features.add('lldb-simulator-watchos') 152 elif lldb_use_simulator == "tvos": 153 lit_config.note("Running API tests on tvOS simulator") 154 config.available_features.add('lldb-simulator-tvos') 155 else: 156 lit_config.error("Unknown simulator id '{}'".format(lldb_use_simulator)) 157 158# Set a default per-test timeout of 10 minutes. Setting a timeout per test 159# requires that killProcessAndChildren() is supported on the platform and 160# lit complains if the value is set but it is not supported. 161supported, errormsg = lit_config.maxIndividualTestTimeIsSupported 162if supported: 163 lit_config.maxIndividualTestTime = 600 164else: 165 lit_config.warning("Could not set a default per-test timeout. " + errormsg) 166 167# Build dotest command. 168dotest_cmd = [os.path.join(config.lldb_src_root, 'test', 'API', 'dotest.py')] 169 170if is_configured('dotest_args_str'): 171 dotest_cmd.extend(config.dotest_args_str.split(';')) 172 173# Library path may be needed to locate just-built clang. 174if is_configured('llvm_libs_dir'): 175 dotest_cmd += ['--env', 'LLVM_LIBS_DIR=' + config.llvm_libs_dir] 176 177# Forward ASan-specific environment variables to tests, as a test may load an 178# ASan-ified dylib. 179for env_var in ('ASAN_OPTIONS', 'DYLD_INSERT_LIBRARIES'): 180 if env_var in config.environment: 181 dotest_cmd += ['--inferior-env', env_var + '=' + config.environment[env_var]] 182 183if is_configured('test_arch'): 184 dotest_cmd += ['--arch', config.test_arch] 185 186if is_configured('lldb_build_directory'): 187 dotest_cmd += ['--build-dir', config.lldb_build_directory] 188 189if is_configured('lldb_module_cache'): 190 delete_module_cache(config.lldb_module_cache) 191 dotest_cmd += ['--lldb-module-cache-dir', config.lldb_module_cache] 192 193if is_configured('clang_module_cache'): 194 delete_module_cache(config.clang_module_cache) 195 dotest_cmd += ['--clang-module-cache-dir', config.clang_module_cache] 196 197if is_configured('lldb_executable'): 198 dotest_cmd += ['--executable', config.lldb_executable] 199 200if is_configured('test_compiler'): 201 dotest_cmd += ['--compiler', config.test_compiler] 202 203if is_configured('dsymutil'): 204 dotest_cmd += ['--dsymutil', config.dsymutil] 205 206if is_configured('llvm_tools_dir'): 207 dotest_cmd += ['--llvm-tools-dir', config.llvm_tools_dir] 208 209if is_configured('server'): 210 dotest_cmd += ['--server', config.server] 211 212if is_configured('lldb_libs_dir'): 213 dotest_cmd += ['--lldb-libs-dir', config.lldb_libs_dir] 214 215if is_configured('lldb_framework_dir'): 216 dotest_cmd += ['--framework', config.lldb_framework_dir] 217 218if 'lldb-repro-capture' in config.available_features or \ 219 'lldb-repro-replay' in config.available_features: 220 dotest_cmd += ['--skip-category=lldb-vscode', '--skip-category=std-module'] 221 222if 'lldb-simulator-ios' in config.available_features: 223 dotest_cmd += ['--apple-sdk', 'iphonesimulator', 224 '--platform-name', 'ios-simulator'] 225elif 'lldb-simulator-watchos' in config.available_features: 226 dotest_cmd += ['--apple-sdk', 'watchsimulator', 227 '--platform-name', 'watchos-simulator'] 228elif 'lldb-simulator-tvos' in config.available_features: 229 dotest_cmd += ['--apple-sdk', 'appletvsimulator', 230 '--platform-name', 'tvos-simulator'] 231 232if is_configured('enabled_plugins'): 233 for plugin in config.enabled_plugins: 234 dotest_cmd += ['--enable-plugin', plugin] 235 236if is_configured('dotest_lit_args_str'): 237 # We don't want to force users passing arguments to lit to use `;` as a 238 # separator. We use Python's simple lexical analyzer to turn the args into a 239 # list. Pass there arguments last so they can override anything that was 240 # already configured. 241 dotest_cmd.extend(shlex.split(config.dotest_lit_args_str)) 242 243# Load LLDB test format. 244sys.path.append(os.path.join(config.lldb_src_root, "test", "API")) 245import lldbtest 246 247# testFormat: The test format to use to interpret tests. 248config.test_format = lldbtest.LLDBTest(dotest_cmd) 249 250# Propagate FREEBSD_LEGACY_PLUGIN 251if 'FREEBSD_LEGACY_PLUGIN' in os.environ: 252 config.environment['FREEBSD_LEGACY_PLUGIN'] = os.environ[ 253 'FREEBSD_LEGACY_PLUGIN'] 254 255# Propagate XDG_CACHE_HOME 256if 'XDG_CACHE_HOME' in os.environ: 257 config.environment['XDG_CACHE_HOME'] = os.environ['XDG_CACHE_HOME'] 258