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. 20# test_exec_root: The root path where tests should be run. 21config.test_source_root = os.path.dirname(__file__) 22config.test_exec_root = config.test_source_root 23 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# Propagate LLDB_CAPTURE_REPRODUCER 133if 'LLDB_CAPTURE_REPRODUCER' in os.environ: 134 config.environment['LLDB_CAPTURE_REPRODUCER'] = os.environ[ 135 'LLDB_CAPTURE_REPRODUCER'] 136 137# Support running the test suite under the lldb-repro wrapper. This makes it 138# possible to capture a test suite run and then rerun all the test from the 139# just captured reproducer. 140lldb_repro_mode = lit_config.params.get('lldb-run-with-repro', None) 141if lldb_repro_mode: 142 lit_config.note("Running API tests in {} mode.".format(lldb_repro_mode)) 143 mkdir_p(config.lldb_reproducer_directory) 144 if lldb_repro_mode == 'capture': 145 config.available_features.add('lldb-repro-capture') 146 elif lldb_repro_mode == 'replay': 147 config.available_features.add('lldb-repro-replay') 148 149lldb_use_simulator = lit_config.params.get('lldb-run-with-simulator', None) 150if lldb_use_simulator: 151 if lldb_use_simulator == "ios": 152 lit_config.note("Running API tests on iOS simulator") 153 config.available_features.add('lldb-simulator-ios') 154 elif lldb_use_simulator == "watchos": 155 lit_config.note("Running API tests on watchOS simulator") 156 config.available_features.add('lldb-simulator-watchos') 157 elif lldb_use_simulator == "tvos": 158 lit_config.note("Running API tests on tvOS simulator") 159 config.available_features.add('lldb-simulator-tvos') 160 else: 161 lit_config.error("Unknown simulator id '{}'".format(lldb_use_simulator)) 162 163# Set a default per-test timeout of 10 minutes. Setting a timeout per test 164# requires that killProcessAndChildren() is supported on the platform and 165# lit complains if the value is set but it is not supported. 166supported, errormsg = lit_config.maxIndividualTestTimeIsSupported 167if supported: 168 lit_config.maxIndividualTestTime = 600 169else: 170 lit_config.warning("Could not set a default per-test timeout. " + errormsg) 171 172# Build dotest command. 173dotest_cmd = [os.path.join(config.lldb_src_root, 'test', 'API', 'dotest.py')] 174 175if is_configured('dotest_args_str'): 176 dotest_cmd.extend(config.dotest_args_str.split(';')) 177 178# Library path may be needed to locate just-built clang. 179if is_configured('llvm_libs_dir'): 180 dotest_cmd += ['--env', 'LLVM_LIBS_DIR=' + config.llvm_libs_dir] 181 182# Forward ASan-specific environment variables to tests, as a test may load an 183# ASan-ified dylib. 184for env_var in ('ASAN_OPTIONS', 'DYLD_INSERT_LIBRARIES'): 185 if env_var in config.environment: 186 dotest_cmd += ['--inferior-env', env_var + '=' + config.environment[env_var]] 187 188if is_configured('test_arch'): 189 dotest_cmd += ['--arch', config.test_arch] 190 191if is_configured('lldb_build_directory'): 192 dotest_cmd += ['--build-dir', config.lldb_build_directory] 193 194if is_configured('lldb_module_cache'): 195 delete_module_cache(config.lldb_module_cache) 196 dotest_cmd += ['--lldb-module-cache-dir', config.lldb_module_cache] 197 198if is_configured('clang_module_cache'): 199 delete_module_cache(config.clang_module_cache) 200 dotest_cmd += ['--clang-module-cache-dir', config.clang_module_cache] 201 202if is_configured('lldb_executable'): 203 dotest_cmd += ['--executable', config.lldb_executable] 204 205if is_configured('test_compiler'): 206 dotest_cmd += ['--compiler', config.test_compiler] 207 208if is_configured('dsymutil'): 209 dotest_cmd += ['--dsymutil', config.dsymutil] 210 211if is_configured('filecheck'): 212 dotest_cmd += ['--filecheck', config.filecheck] 213 214if is_configured('yaml2obj'): 215 dotest_cmd += ['--yaml2obj', config.yaml2obj] 216 217if is_configured('server'): 218 dotest_cmd += ['--server', config.server] 219 220if is_configured('lldb_libs_dir'): 221 dotest_cmd += ['--lldb-libs-dir', config.lldb_libs_dir] 222 223if is_configured('lldb_framework_dir'): 224 dotest_cmd += ['--framework', config.lldb_framework_dir] 225 226if 'lldb-repro-capture' in config.available_features or \ 227 'lldb-repro-replay' in config.available_features: 228 dotest_cmd += ['--skip-category=lldb-vscode', '--skip-category=std-module'] 229 230if 'lldb-simulator-ios' in config.available_features: 231 dotest_cmd += ['--apple-sdk', 'iphonesimulator', 232 '--platform-name', 'ios-simulator'] 233elif 'lldb-simulator-watchos' in config.available_features: 234 dotest_cmd += ['--apple-sdk', 'watchsimulator', 235 '--platform-name', 'watchos-simulator'] 236elif 'lldb-simulator-tvos' in config.available_features: 237 dotest_cmd += ['--apple-sdk', 'appletvsimulator', 238 '--platform-name', 'tvos-simulator'] 239 240if is_configured('enabled_plugins'): 241 for plugin in config.enabled_plugins: 242 dotest_cmd += ['--enable-plugin', plugin] 243 244if is_configured('dotest_lit_args_str'): 245 # We don't want to force users passing arguments to lit to use `;` as a 246 # separator. We use Python's simple lexical analyzer to turn the args into a 247 # list. Pass there arguments last so they can override anything that was 248 # already configured. 249 dotest_cmd.extend(shlex.split(config.dotest_lit_args_str)) 250 251# Load LLDB test format. 252sys.path.append(os.path.join(config.lldb_src_root, "test", "API")) 253import lldbtest 254 255# testFormat: The test format to use to interpret tests. 256config.test_format = lldbtest.LLDBTest(dotest_cmd) 257 258# Propagate FREEBSD_LEGACY_PLUGIN 259if 'FREEBSD_LEGACY_PLUGIN' in os.environ: 260 config.environment['FREEBSD_LEGACY_PLUGIN'] = os.environ[ 261 'FREEBSD_LEGACY_PLUGIN'] 262