362 lines · python
1# -*- Python -*-2 3# Configuration file for the 'lit' test runner.4 5import os6import platform7import shlex8import shutil9import subprocess10import sys11 12import lit.formats13 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 errno29 30 try:31 os.makedirs(path)32 except OSError as e:33 if e.errno != errno.EEXIST:34 raise35 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 python58# binary as the ASan interceptors get loaded too late. Also, when SIP is59# enabled, we can't inject libraries into system binaries at all, so we need a60# 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 None65 66 # If we're running in a virtual environment, we have to copy Python into67 # 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_python76 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 # macOS 15+ restricts injecting the ASAN runtime to only user-compiled code.94 subprocess.check_call(["/usr/bin/codesign", "--remove-signature", copied_python])95 96 # Now make sure the copied Python works. The Python in Xcode has a relative97 # RPATH and cannot be copied.98 try:99 # We don't care about the output, just make sure it runs.100 subprocess.check_call([copied_python, "-V"])101 except subprocess.CalledProcessError:102 # The copied Python didn't work. Assume we're dealing with the Python103 # interpreter in Xcode. Given that this is not a system binary SIP104 # won't prevent us form injecting the interceptors, but when running in105 # a virtual environment, we can't use it directly. Create a symlink106 # instead.107 os.remove(copied_python)108 os.symlink(real_python, copied_python)109 110 # The copied Python works.111 return copied_python112 113 114def is_configured(attr):115 """Return the configuration attribute if it exists and None otherwise.116 117 This allows us to check if the attribute exists before trying to access it."""118 return getattr(config, attr, None)119 120 121def delete_module_cache(path):122 """Clean the module caches in the test build directory.123 124 This is necessary in an incremental build whenever clang changes underneath,125 so doing it once per lit.py invocation is close enough."""126 if os.path.isdir(path):127 lit_config.note("Deleting module cache at %s." % path)128 shutil.rmtree(path)129 130 131if is_configured("llvm_use_sanitizer"):132 config.environment["MallocNanoZone"] = "0"133 if "Address" in config.llvm_use_sanitizer:134 config.environment["ASAN_OPTIONS"] = "detect_stack_use_after_return=1"135 if "Darwin" in config.target_os:136 config.environment["DYLD_INSERT_LIBRARIES"] = find_sanitizer_runtime(137 "libclang_rt.asan_osx_dynamic.dylib"138 )139 140 if "Thread" in config.llvm_use_sanitizer:141 config.environment["TSAN_OPTIONS"] = "halt_on_error=1"142 if "Darwin" in config.target_os:143 config.environment["DYLD_INSERT_LIBRARIES"] = find_sanitizer_runtime(144 "libclang_rt.tsan_osx_dynamic.dylib"145 )146 147if platform.system() == "Darwin":148 python_executable = find_python_interpreter()149 if python_executable:150 lit_config.note(151 "Using {} instead of {}".format(python_executable, config.python_executable)152 )153 config.python_executable = python_executable154 155# Shared library build of LLVM may require LD_LIBRARY_PATH or equivalent.156if is_configured("shared_libs"):157 for shlibpath_var in find_shlibpath_var():158 # In stand-alone build llvm_shlib_dir specifies LLDB's lib directory while159 # llvm_libs_dir specifies LLVM's lib directory.160 shlibpath = os.path.pathsep.join(161 (162 config.llvm_shlib_dir,163 config.llvm_libs_dir,164 config.environment.get(shlibpath_var, ""),165 )166 )167 config.environment[shlibpath_var] = shlibpath168 else:169 lit_config.warning(170 "unable to inject shared library path on '{}'".format(platform.system())171 )172 173lldb_use_simulator = lit_config.params.get("lldb-run-with-simulator", None)174if lldb_use_simulator:175 if lldb_use_simulator == "ios":176 lit_config.note("Running API tests on iOS simulator")177 config.available_features.add("lldb-simulator-ios")178 elif lldb_use_simulator == "watchos":179 lit_config.note("Running API tests on watchOS simulator")180 config.available_features.add("lldb-simulator-watchos")181 elif lldb_use_simulator == "tvos":182 lit_config.note("Running API tests on tvOS simulator")183 config.available_features.add("lldb-simulator-tvos")184 elif lldb_use_simulator == "qemu-user":185 lit_config.note("Running API tests on qemu-user simulator")186 config.available_features.add("lldb-simulator-qemu-user")187 else:188 lit_config.error("Unknown simulator id '{}'".format(lldb_use_simulator))189 190# Set a default per-test timeout of 10 minutes. Setting a timeout per test191# requires that killProcessAndChildren() is supported on the platform and192# lit complains if the value is set but it is not supported.193supported, errormsg = lit_config.maxIndividualTestTimeIsSupported194if supported:195 lit_config.maxIndividualTestTime = 600196else:197 lit_config.warning("Could not set a default per-test timeout. " + errormsg)198 199# Build dotest command.200dotest_cmd = [os.path.join(config.lldb_src_root, "test", "API", "dotest.py")]201 202if is_configured("dotest_common_args_str"):203 dotest_cmd.extend(config.dotest_common_args_str.split(";"))204 205# Library path may be needed to locate just-built clang and libcxx.206if is_configured("llvm_libs_dir"):207 dotest_cmd += ["--env", "LLVM_LIBS_DIR=" + config.llvm_libs_dir]208 209# Include path may be needed to locate just-built libcxx.210if is_configured("llvm_include_dir"):211 dotest_cmd += ["--env", "LLVM_INCLUDE_DIR=" + config.llvm_include_dir]212 213# This path may be needed to locate required llvm tools214if is_configured("llvm_tools_dir"):215 dotest_cmd += ["--env", "LLVM_TOOLS_DIR=" + config.llvm_tools_dir]216 217# If we have a just-built libcxx, prefer it over the system one.218if is_configured("has_libcxx") and config.has_libcxx:219 if platform.system() != "Windows":220 if is_configured("libcxx_include_dir") and is_configured("libcxx_libs_dir"):221 dotest_cmd += ["--libcxx-include-dir", config.libcxx_include_dir]222 if is_configured("libcxx_include_target_dir"):223 dotest_cmd += [224 "--libcxx-include-target-dir",225 config.libcxx_include_target_dir,226 ]227 dotest_cmd += ["--libcxx-library-dir", config.libcxx_libs_dir]228 229# Forward ASan-specific environment variables to tests, as a test may load an230# ASan-ified dylib.231for env_var in ("ASAN_OPTIONS", "DYLD_INSERT_LIBRARIES"):232 if env_var in config.environment:233 dotest_cmd += ["--inferior-env", env_var + "=" + config.environment[env_var]]234 235if is_configured("test_arch"):236 dotest_cmd += ["--arch", config.test_arch]237 238if is_configured("lldb_build_directory"):239 dotest_cmd += ["--build-dir", config.lldb_build_directory]240 241if is_configured("lldb_module_cache"):242 delete_module_cache(config.lldb_module_cache)243 dotest_cmd += ["--lldb-module-cache-dir", config.lldb_module_cache]244 245if is_configured("clang_module_cache"):246 delete_module_cache(config.clang_module_cache)247 dotest_cmd += ["--clang-module-cache-dir", config.clang_module_cache]248 249if is_configured("lldb_executable"):250 dotest_cmd += ["--executable", config.lldb_executable]251 252if is_configured("test_compiler"):253 dotest_cmd += ["--compiler", config.test_compiler]254 255if is_configured("dsymutil"):256 dotest_cmd += ["--dsymutil", config.dsymutil]257 258if is_configured("make"):259 dotest_cmd += ["--make", config.make]260 261if is_configured("llvm_tools_dir"):262 dotest_cmd += ["--llvm-tools-dir", config.llvm_tools_dir]263 264if is_configured("server"):265 dotest_cmd += ["--server", config.server]266 267if is_configured("lldb_obj_root"):268 dotest_cmd += ["--lldb-obj-root", config.lldb_obj_root]269 270if is_configured("lldb_libs_dir"):271 dotest_cmd += ["--lldb-libs-dir", config.lldb_libs_dir]272 273if is_configured("lldb_framework_dir"):274 dotest_cmd += ["--framework", config.lldb_framework_dir]275 276if is_configured("cmake_build_type"):277 dotest_cmd += ["--cmake-build-type", config.cmake_build_type]278 279if "lldb-simulator-ios" in config.available_features:280 dotest_cmd += ["--apple-sdk", "iphonesimulator", "--platform-name", "ios-simulator"]281elif "lldb-simulator-watchos" in config.available_features:282 dotest_cmd += [283 "--apple-sdk",284 "watchsimulator",285 "--platform-name",286 "watchos-simulator",287 ]288elif "lldb-simulator-tvos" in config.available_features:289 dotest_cmd += [290 "--apple-sdk",291 "appletvsimulator",292 "--platform-name",293 "tvos-simulator",294 ]295 296if "lldb-simulator-qemu-user" in config.available_features:297 dotest_cmd += ["--platform-name", "qemu-user"]298 299if is_configured("enabled_plugins"):300 for plugin in config.enabled_plugins:301 dotest_cmd += ["--enable-plugin", plugin]302 303# `dotest` args come from three different sources:304# 1. Derived by CMake based on its configs (LLDB_TEST_COMMON_ARGS), which end305# up in `dotest_common_args_str`.306# 2. CMake user parameters (LLDB_TEST_USER_ARGS), which end up in307# `dotest_user_args_str`.308# 3. With `llvm-lit "--param=dotest-args=..."`, which end up in309# `dotest_lit_args_str`.310# Check them in this order, so that more specific overrides are visited last.311# In particular, (1) is visited at the top of the file, since the script312# derives other information from it.313 314if is_configured("lldb_platform_url"):315 dotest_cmd += ["--platform-url", config.lldb_platform_url]316if is_configured("lldb_platform_working_dir"):317 dotest_cmd += ["--platform-working-dir", config.lldb_platform_working_dir]318if is_configured("cmake_sysroot"):319 dotest_cmd += ["--sysroot", config.cmake_sysroot]320 321if is_configured("dotest_user_args_str"):322 dotest_cmd.extend(config.dotest_user_args_str.split(";"))323 324if is_configured("dotest_lit_args_str"):325 # We don't want to force users passing arguments to lit to use `;` as a326 # separator. We use Python's simple lexical analyzer to turn the args into a327 # list. Pass there arguments last so they can override anything that was328 # already configured.329 dotest_cmd.extend(shlex.split(config.dotest_lit_args_str))330 331# Load LLDB test format.332sys.path.append(os.path.join(config.lldb_src_root, "test", "API"))333import lldbtest334 335# testFormat: The test format to use to interpret tests.336config.test_format = lldbtest.LLDBTest(dotest_cmd)337 338# Propagate TERM or default to vt100.339config.environment["TERM"] = os.getenv("TERM", default="vt100")340 341# Propagate FREEBSD_LEGACY_PLUGIN342if "FREEBSD_LEGACY_PLUGIN" in os.environ:343 config.environment["FREEBSD_LEGACY_PLUGIN"] = os.environ["FREEBSD_LEGACY_PLUGIN"]344 345# Propagate XDG_CACHE_HOME346if "XDG_CACHE_HOME" in os.environ:347 config.environment["XDG_CACHE_HOME"] = os.environ["XDG_CACHE_HOME"]348 349# Transfer some environment variables into the tests on Windows build host.350if platform.system() == "Windows":351 for v in ["SystemDrive"]:352 if v in os.environ:353 config.environment[v] = os.environ[v]354 355# Some steps required to initialize the tests dynamically link with python.dll356# and need to know the location of the Python libraries. This ensures that we357# use the same version of Python that was used to build lldb to run our tests.358config.environment["PYTHONHOME"] = config.python_root_dir359config.environment["PATH"] = os.path.pathsep.join(360 (config.python_root_dir, config.environment.get("PATH", ""))361)362