[lldb/Test] Fix ASan/TSan workaround for Xcode Python 3
[lldb.git] / lldb / test / API / lit.cfg.py
1 # -*- Python -*-
2
3 # Configuration file for the 'lit' test runner.
4
5 import os
6 import platform
7 import shlex
8 import shutil
9
10 import lit.formats
11
12 # name: The name of this test suite.
13 config.name = 'lldb-api'
14
15 # suffixes: A list of file extensions to treat as test files.
16 config.suffixes = ['.py']
17
18 # test_source_root: The root path where tests are located.
19 # test_exec_root: The root path where tests should be run.
20 config.test_source_root = os.path.dirname(__file__)
21 config.test_exec_root = config.test_source_root
22
23
24 def mkdir_p(path):
25     import errno
26     try:
27         os.makedirs(path)
28     except OSError as e:
29         if e.errno != errno.EEXIST:
30             raise
31     if not os.path.isdir(path):
32         raise OSError(errno.ENOTDIR, "%s is not a directory"%path)
33
34
35 def find_sanitizer_runtime(name):
36   import subprocess
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
43 def 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.
56 def 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   import shutil, subprocess
64   real_python = subprocess.check_output([
65       config.python_executable,
66       os.path.join(os.path.dirname(os.path.realpath(__file__)),
67                    'get_darwin_real_python.py')
68   ]).decode('utf-8').strip()
69
70   shutil.copy(real_python, copied_python)
71
72   # Now make sure the copied Python works. The Python in Xcode has a relative
73   # RPATH and cannot be copied.
74   try:
75     # We don't care about the output, just make sure it runs.
76     subprocess.check_output([copied_python, '-V'], stderr=subprocess.STDOUT)
77   except subprocess.CalledProcessError:
78     # The copied Python didn't work. Assume we're dealing with the Python
79     # interpreter in Xcode. Given that this is not a system binary SIP
80     # won't prevent us form injecting the interceptors so we get away with
81     # not copying the executable.
82     os.remove(copied_python)
83     return real_python
84
85   # The copied Python works.
86   return copied_python
87
88
89 if 'Address' in config.llvm_use_sanitizer:
90   config.environment['ASAN_OPTIONS'] = 'detect_stack_use_after_return=1'
91   if 'Darwin' in config.host_os and 'x86' in config.host_triple:
92     config.environment['DYLD_INSERT_LIBRARIES'] = find_sanitizer_runtime(
93         'libclang_rt.asan_osx_dynamic.dylib')
94
95 if 'Thread' in config.llvm_use_sanitizer:
96   if 'Darwin' in config.host_os and 'x86' in config.host_triple:
97     config.environment['DYLD_INSERT_LIBRARIES'] = find_sanitizer_runtime(
98         'libclang_rt.tsan_osx_dynamic.dylib')
99
100 if 'DYLD_INSERT_LIBRARIES' in config.environment and platform.system() == 'Darwin':
101   config.python_executable = find_python_interpreter()
102
103 # Shared library build of LLVM may require LD_LIBRARY_PATH or equivalent.
104 if config.shared_libs:
105   for shlibpath_var in find_shlibpath_var():
106     # In stand-alone build llvm_shlib_dir specifies LLDB's lib directory while
107     # llvm_libs_dir specifies LLVM's lib directory.
108     shlibpath = os.path.pathsep.join(
109         (config.llvm_shlib_dir, config.llvm_libs_dir,
110          config.environment.get(shlibpath_var, '')))
111     config.environment[shlibpath_var] = shlibpath
112   else:
113     lit_config.warning("unable to inject shared library path on '{}'".format(
114         platform.system()))
115
116 # Propagate LLDB_CAPTURE_REPRODUCER
117 if 'LLDB_CAPTURE_REPRODUCER' in os.environ:
118   config.environment['LLDB_CAPTURE_REPRODUCER'] = os.environ[
119       'LLDB_CAPTURE_REPRODUCER']
120
121 # Support running the test suite under the lldb-repro wrapper. This makes it
122 # possible to capture a test suite run and then rerun all the test from the
123 # just captured reproducer.
124 lldb_repro_mode = lit_config.params.get('lldb-run-with-repro', None)
125 if lldb_repro_mode:
126   lit_config.note("Running API tests in {} mode.".format(lldb_repro_mode))
127   if lldb_repro_mode == 'capture':
128     config.available_features.add('lldb-repro-capture')
129   elif lldb_repro_mode == 'replay':
130     config.available_features.add('lldb-repro-replay')
131
132 # Clean the module caches in the test build directory. This is necessary in an
133 # incremental build whenever clang changes underneath, so doing it once per
134 # lit.py invocation is close enough.
135 for cachedir in [config.clang_module_cache, config.lldb_module_cache]:
136   if os.path.isdir(cachedir):
137     print("Deleting module cache at %s." % cachedir)
138     shutil.rmtree(cachedir)
139
140 # Set a default per-test timeout of 10 minutes. Setting a timeout per test
141 # requires that killProcessAndChildren() is supported on the platform and
142 # lit complains if the value is set but it is not supported.
143 supported, errormsg = lit_config.maxIndividualTestTimeIsSupported
144 if supported:
145   lit_config.maxIndividualTestTime = 600
146 else:
147   lit_config.warning("Could not set a default per-test timeout. " + errormsg)
148
149 # Build dotest command.
150 dotest_cmd = [config.dotest_path]
151 dotest_cmd += ['--arch', config.test_arch]
152 dotest_cmd.extend(config.dotest_args_str.split(';'))
153
154 # Library path may be needed to locate just-built clang.
155 if config.llvm_libs_dir:
156   dotest_cmd += ['--env', 'LLVM_LIBS_DIR=' + config.llvm_libs_dir]
157
158 # Forward ASan-specific environment variables to tests, as a test may load an
159 # ASan-ified dylib.
160 for env_var in ('ASAN_OPTIONS', 'DYLD_INSERT_LIBRARIES'):
161   if env_var in config.environment:
162     dotest_cmd += ['--inferior-env', env_var + '=' + config.environment[env_var]]
163
164 if config.lldb_build_directory:
165   dotest_cmd += ['--build-dir', config.lldb_build_directory]
166
167 if config.lldb_module_cache:
168   dotest_cmd += ['--lldb-module-cache-dir', config.lldb_module_cache]
169
170 if config.clang_module_cache:
171   dotest_cmd += ['--clang-module-cache-dir', config.clang_module_cache]
172
173 if config.lldb_executable:
174   dotest_cmd += ['--executable', config.lldb_executable]
175
176 if config.test_compiler:
177   dotest_cmd += ['--compiler', config.test_compiler]
178
179 if config.dsymutil:
180   dotest_cmd += ['--dsymutil', config.dsymutil]
181
182 if config.filecheck:
183   dotest_cmd += ['--filecheck', config.filecheck]
184
185 if config.lldb_libs_dir:
186   dotest_cmd += ['--lldb-libs-dir', config.lldb_libs_dir]
187
188 if 'lldb-repro-capture' in config.available_features or \
189     'lldb-repro-replay' in config.available_features:
190   dotest_cmd += ['--skip-category=lldb-vscode', '--skip-category=std-module']
191
192 if config.enabled_plugins:
193   for plugin in config.enabled_plugins:
194     dotest_cmd += ['--enable-plugin', plugin]
195
196 # We don't want to force users passing arguments to lit to use `;` as a
197 # separator. We use Python's simple lexical analyzer to turn the args into a
198 # list. Pass there arguments last so they can override anything that was
199 # already configured.
200 if config.dotest_lit_args_str:
201   dotest_cmd.extend(shlex.split(config.dotest_lit_args_str))
202
203
204 # Load LLDB test format.
205 sys.path.append(os.path.join(config.lldb_src_root, "test", "API"))
206 import lldbtest
207
208 # testFormat: The test format to use to interpret tests.
209 config.test_format = lldbtest.LLDBTest(dotest_cmd)