• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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