xref: /llvm-project/lldb/test/API/lit.cfg.py (revision 8941f898f1921857720034b9a0950e4ec32d5d87)
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