1# -*- Python -*- 2 3# Configuration file for the 'lit' test runner. 4 5import os 6import platform 7import shlex 8import shutil 9import subprocess 10import sys 11 12import lit.formats 13 14# name: The name of this test suite. 15config.name = "lldb-api" 16 17# suffixes: A list of file extensions to treat as test files. 18config.suffixes = [".py"] 19 20# test_source_root: The root path where tests are located. 21config.test_source_root = os.path.dirname(__file__) 22 23# test_exec_root: The root path where tests should be run. 24config.test_exec_root = os.path.join(config.lldb_obj_root, "test", "API") 25 26 27def mkdir_p(path): 28 import errno 29 30 try: 31 os.makedirs(path) 32 except OSError as e: 33 if e.errno != errno.EEXIST: 34 raise 35 if not os.path.isdir(path): 36 raise OSError(errno.ENOTDIR, "%s is not a directory" % path) 37 38 39def find_sanitizer_runtime(name): 40 resource_dir = ( 41 subprocess.check_output([config.cmake_cxx_compiler, "-print-resource-dir"]) 42 .decode("utf-8") 43 .strip() 44 ) 45 return os.path.join(resource_dir, "lib", "darwin", name) 46 47 48def find_shlibpath_var(): 49 if platform.system() in ["Linux", "FreeBSD", "NetBSD", "OpenBSD", "SunOS"]: 50 yield "LD_LIBRARY_PATH" 51 elif platform.system() == "Darwin": 52 yield "DYLD_LIBRARY_PATH" 53 elif platform.system() == "Windows": 54 yield "PATH" 55 56 57# On macOS, we can't do the DYLD_INSERT_LIBRARIES trick with a shim python 58# binary as the ASan interceptors get loaded too late. Also, when SIP is 59# enabled, we can't inject libraries into system binaries at all, so we need a 60# copy of the "real" python to work with. 61def find_python_interpreter(): 62 # This is only necessary when using DYLD_INSERT_LIBRARIES. 63 if "DYLD_INSERT_LIBRARIES" not in config.environment: 64 return None 65 66 # If we're running in a virtual environment, we have to copy Python into 67 # the virtual environment for it to work. 68 if sys.prefix != sys.base_prefix: 69 copied_python = os.path.join(sys.prefix, "bin", "copied-python") 70 else: 71 copied_python = os.path.join(config.lldb_build_directory, "copied-python") 72 73 # Avoid doing any work if we already copied the binary. 74 if os.path.isfile(copied_python): 75 return copied_python 76 77 # Find the "real" python binary. 78 real_python = ( 79 subprocess.check_output( 80 [ 81 config.python_executable, 82 os.path.join( 83 os.path.dirname(os.path.realpath(__file__)), 84 "get_darwin_real_python.py", 85 ), 86 ] 87 ) 88 .decode("utf-8") 89 .strip() 90 ) 91 92 shutil.copy(real_python, copied_python) 93 94 # Now make sure the copied Python works. The Python in Xcode has a relative 95 # RPATH and cannot be copied. 96 try: 97 # We don't care about the output, just make sure it runs. 98 subprocess.check_call([copied_python, "-V"]) 99 except subprocess.CalledProcessError: 100 # The copied Python didn't work. Assume we're dealing with the Python 101 # interpreter in Xcode. Given that this is not a system binary SIP 102 # won't prevent us form injecting the interceptors, but when running in 103 # a virtual environment, we can't use it directly. Create a symlink 104 # instead. 105 os.remove(copied_python) 106 os.symlink(real_python, copied_python) 107 108 # The copied Python works. 109 return copied_python 110 111 112def is_configured(attr): 113 """Return the configuration attribute if it exists and None otherwise. 114 115 This allows us to check if the attribute exists before trying to access it.""" 116 return getattr(config, attr, None) 117 118 119def delete_module_cache(path): 120 """Clean the module caches in the test build directory. 121 122 This is necessary in an incremental build whenever clang changes underneath, 123 so doing it once per lit.py invocation is close enough.""" 124 if os.path.isdir(path): 125 lit_config.note("Deleting module cache at %s." % path) 126 shutil.rmtree(path) 127 128 129if is_configured("llvm_use_sanitizer"): 130 config.environment["MallocNanoZone"] = "0" 131 if "Address" in config.llvm_use_sanitizer: 132 config.environment["ASAN_OPTIONS"] = "detect_stack_use_after_return=1" 133 if "Darwin" in config.host_os: 134 config.environment["DYLD_INSERT_LIBRARIES"] = find_sanitizer_runtime( 135 "libclang_rt.asan_osx_dynamic.dylib" 136 ) 137 138 if "Thread" in config.llvm_use_sanitizer: 139 config.environment["TSAN_OPTIONS"] = "halt_on_error=1" 140 if "Darwin" in config.host_os: 141 config.environment["DYLD_INSERT_LIBRARIES"] = find_sanitizer_runtime( 142 "libclang_rt.tsan_osx_dynamic.dylib" 143 ) 144 145if platform.system() == "Darwin": 146 python_executable = find_python_interpreter() 147 if python_executable: 148 lit_config.note( 149 "Using {} instead of {}".format(python_executable, config.python_executable) 150 ) 151 config.python_executable = python_executable 152 153# Shared library build of LLVM may require LD_LIBRARY_PATH or equivalent. 154if is_configured("shared_libs"): 155 for shlibpath_var in find_shlibpath_var(): 156 # In stand-alone build llvm_shlib_dir specifies LLDB's lib directory while 157 # llvm_libs_dir specifies LLVM's lib directory. 158 shlibpath = os.path.pathsep.join( 159 ( 160 config.llvm_shlib_dir, 161 config.llvm_libs_dir, 162 config.environment.get(shlibpath_var, ""), 163 ) 164 ) 165 config.environment[shlibpath_var] = shlibpath 166 else: 167 lit_config.warning( 168 "unable to inject shared library path on '{}'".format(platform.system()) 169 ) 170 171lldb_use_simulator = lit_config.params.get("lldb-run-with-simulator", None) 172if lldb_use_simulator: 173 if lldb_use_simulator == "ios": 174 lit_config.note("Running API tests on iOS simulator") 175 config.available_features.add("lldb-simulator-ios") 176 elif lldb_use_simulator == "watchos": 177 lit_config.note("Running API tests on watchOS simulator") 178 config.available_features.add("lldb-simulator-watchos") 179 elif lldb_use_simulator == "tvos": 180 lit_config.note("Running API tests on tvOS simulator") 181 config.available_features.add("lldb-simulator-tvos") 182 else: 183 lit_config.error("Unknown simulator id '{}'".format(lldb_use_simulator)) 184 185# Set a default per-test timeout of 10 minutes. Setting a timeout per test 186# requires that killProcessAndChildren() is supported on the platform and 187# lit complains if the value is set but it is not supported. 188supported, errormsg = lit_config.maxIndividualTestTimeIsSupported 189if supported: 190 lit_config.maxIndividualTestTime = 600 191else: 192 lit_config.warning("Could not set a default per-test timeout. " + errormsg) 193 194# Build dotest command. 195dotest_cmd = [os.path.join(config.lldb_src_root, "test", "API", "dotest.py")] 196 197if is_configured("dotest_common_args_str"): 198 dotest_cmd.extend(config.dotest_common_args_str.split(";")) 199 200# Library path may be needed to locate just-built clang and libcxx. 201if is_configured("llvm_libs_dir"): 202 dotest_cmd += ["--env", "LLVM_LIBS_DIR=" + config.llvm_libs_dir] 203 204# Include path may be needed to locate just-built libcxx. 205if is_configured("llvm_include_dir"): 206 dotest_cmd += ["--env", "LLVM_INCLUDE_DIR=" + config.llvm_include_dir] 207 208# This path may be needed to locate required llvm tools 209if is_configured("llvm_tools_dir"): 210 dotest_cmd += ["--env", "LLVM_TOOLS_DIR=" + config.llvm_tools_dir] 211 212# If we have a just-built libcxx, prefer it over the system one. 213if is_configured("has_libcxx") and config.has_libcxx: 214 if platform.system() != "Windows": 215 if is_configured("libcxx_include_dir") and is_configured("libcxx_libs_dir"): 216 dotest_cmd += ["--libcxx-include-dir", config.libcxx_include_dir] 217 if is_configured("libcxx_include_target_dir"): 218 dotest_cmd += [ 219 "--libcxx-include-target-dir", 220 config.libcxx_include_target_dir, 221 ] 222 dotest_cmd += ["--libcxx-library-dir", config.libcxx_libs_dir] 223 224# Forward ASan-specific environment variables to tests, as a test may load an 225# ASan-ified dylib. 226for env_var in ("ASAN_OPTIONS", "DYLD_INSERT_LIBRARIES"): 227 if env_var in config.environment: 228 dotest_cmd += ["--inferior-env", env_var + "=" + config.environment[env_var]] 229 230if is_configured("test_arch"): 231 dotest_cmd += ["--arch", config.test_arch] 232 233if is_configured("lldb_build_directory"): 234 dotest_cmd += ["--build-dir", config.lldb_build_directory] 235 236if is_configured("lldb_module_cache"): 237 delete_module_cache(config.lldb_module_cache) 238 dotest_cmd += ["--lldb-module-cache-dir", config.lldb_module_cache] 239 240if is_configured("clang_module_cache"): 241 delete_module_cache(config.clang_module_cache) 242 dotest_cmd += ["--clang-module-cache-dir", config.clang_module_cache] 243 244if is_configured("lldb_executable"): 245 dotest_cmd += ["--executable", config.lldb_executable] 246 247if is_configured("test_compiler"): 248 dotest_cmd += ["--compiler", config.test_compiler] 249 250if is_configured("dsymutil"): 251 dotest_cmd += ["--dsymutil", config.dsymutil] 252 253if is_configured("make"): 254 dotest_cmd += ["--make", config.make] 255 256if is_configured("llvm_tools_dir"): 257 dotest_cmd += ["--llvm-tools-dir", config.llvm_tools_dir] 258 259if is_configured("server"): 260 dotest_cmd += ["--server", config.server] 261 262if is_configured("lldb_obj_root"): 263 dotest_cmd += ["--lldb-obj-root", config.lldb_obj_root] 264 265if is_configured("lldb_libs_dir"): 266 dotest_cmd += ["--lldb-libs-dir", config.lldb_libs_dir] 267 268if is_configured("lldb_framework_dir"): 269 dotest_cmd += ["--framework", config.lldb_framework_dir] 270 271if "lldb-simulator-ios" in config.available_features: 272 dotest_cmd += ["--apple-sdk", "iphonesimulator", "--platform-name", "ios-simulator"] 273elif "lldb-simulator-watchos" in config.available_features: 274 dotest_cmd += [ 275 "--apple-sdk", 276 "watchsimulator", 277 "--platform-name", 278 "watchos-simulator", 279 ] 280elif "lldb-simulator-tvos" in config.available_features: 281 dotest_cmd += [ 282 "--apple-sdk", 283 "appletvsimulator", 284 "--platform-name", 285 "tvos-simulator", 286 ] 287 288if is_configured("enabled_plugins"): 289 for plugin in config.enabled_plugins: 290 dotest_cmd += ["--enable-plugin", plugin] 291 292# `dotest` args come from three different sources: 293# 1. Derived by CMake based on its configs (LLDB_TEST_COMMON_ARGS), which end 294# up in `dotest_common_args_str`. 295# 2. CMake user parameters (LLDB_TEST_USER_ARGS), which end up in 296# `dotest_user_args_str`. 297# 3. With `llvm-lit "--param=dotest-args=..."`, which end up in 298# `dotest_lit_args_str`. 299# Check them in this order, so that more specific overrides are visited last. 300# In particular, (1) is visited at the top of the file, since the script 301# derives other information from it. 302 303if is_configured("lldb_platform_url"): 304 dotest_cmd += ["--platform-url", config.lldb_platform_url] 305if is_configured("lldb_platform_working_dir"): 306 dotest_cmd += ["--platform-working-dir", config.lldb_platform_working_dir] 307if is_configured("cmake_sysroot"): 308 dotest_cmd += ["--sysroot", config.cmake_sysroot] 309 310if is_configured("dotest_user_args_str"): 311 dotest_cmd.extend(config.dotest_user_args_str.split(";")) 312 313if is_configured("dotest_lit_args_str"): 314 # We don't want to force users passing arguments to lit to use `;` as a 315 # separator. We use Python's simple lexical analyzer to turn the args into a 316 # list. Pass there arguments last so they can override anything that was 317 # already configured. 318 dotest_cmd.extend(shlex.split(config.dotest_lit_args_str)) 319 320# Load LLDB test format. 321sys.path.append(os.path.join(config.lldb_src_root, "test", "API")) 322import lldbtest 323 324# testFormat: The test format to use to interpret tests. 325config.test_format = lldbtest.LLDBTest(dotest_cmd) 326 327# Propagate TERM or default to vt100. 328config.environment["TERM"] = os.getenv("TERM", default="vt100") 329 330# Propagate FREEBSD_LEGACY_PLUGIN 331if "FREEBSD_LEGACY_PLUGIN" in os.environ: 332 config.environment["FREEBSD_LEGACY_PLUGIN"] = os.environ["FREEBSD_LEGACY_PLUGIN"] 333 334# Propagate XDG_CACHE_HOME 335if "XDG_CACHE_HOME" in os.environ: 336 config.environment["XDG_CACHE_HOME"] = os.environ["XDG_CACHE_HOME"] 337 338# Transfer some environment variables into the tests on Windows build host. 339if platform.system() == "Windows": 340 for v in ["SystemDrive"]: 341 if v in os.environ: 342 config.environment[v] = os.environ[v] 343