1import os 2import itertools 3import platform 4import re 5import subprocess 6import sys 7 8import lit.util 9from lit.formats import ShTest 10from lit.llvm import llvm_config 11from lit.llvm.subst import FindTool 12from lit.llvm.subst import ToolSubst 13 14import posixpath 15 16def _get_lldb_init_path(config): 17 return os.path.join(config.test_exec_root, "lit-lldb-init-quiet") 18 19 20def _disallow(config, execName): 21 warning = """ 22 echo '*** Do not use \'{0}\' in tests; use \'%''{0}\'. ***' && 23 exit 1 && echo 24 """ 25 config.substitutions.append((" {0} ".format(execName), warning.format(execName))) 26 27 28def get_lldb_args(config, suffix=""): 29 lldb_args = [] 30 if "remote-linux" in config.available_features: 31 lldb_args += [ 32 "-O", 33 '"platform select remote-linux"', 34 "-O", 35 f'"platform connect {config.lldb_platform_url}"', 36 ] 37 if config.lldb_platform_working_dir: 38 dir = posixpath.join(f"{config.lldb_platform_working_dir}", "shell") 39 if suffix: 40 dir += posixpath.join(dir, f"{suffix}") 41 lldb_args += [ 42 "-O", 43 f'"platform shell mkdir -p {dir}"', 44 "-O", 45 f'"platform settings -w {dir}"', 46 ] 47 lldb_args += ["--no-lldbinit", "-S", _get_lldb_init_path(config)] 48 return lldb_args 49 50 51class ShTestLldb(ShTest): 52 def __init__( 53 self, execute_external=False, extra_substitutions=[], preamble_commands=[] 54 ): 55 super().__init__(execute_external, extra_substitutions, preamble_commands) 56 57 def execute(self, test, litConfig): 58 # Run each Shell test in a separate directory (on remote). 59 60 # Find directory change command in %lldb substitution. 61 for i, t in enumerate(test.config.substitutions): 62 if re.match(t[0], "%lldb"): 63 cmd = t[1] 64 if '-O "platform settings -w ' in cmd: 65 # If command is present, it is added by get_lldb_args. 66 # Replace the path with the tests' path in suite. 67 # Example: 68 # bin/lldb 69 # -O "platform shell mkdir -p /home/user/shell" 70 # -O "platform settings -w /home/user/shell" ... 71 # => 72 # bin/lldb 73 # -O "platform shell mkdir -p /home/user/shell/SymbolFile/Breakpad/inline-record.test" 74 # -O "platform settings -w /home/user/shell/SymbolFile/Breakpad/inline-record.test" ... 75 args_def = " ".join(get_lldb_args(test.config)) 76 args_unique = " ".join( 77 get_lldb_args( 78 test.config, 79 posixpath.join(*test.path_in_suite), 80 ) 81 ) 82 test.config.substitutions[i] = ( 83 t[0], 84 cmd.replace(args_def, args_unique), 85 ) 86 break 87 return super().execute(test, litConfig) 88 89 90def use_lldb_substitutions(config): 91 # Set up substitutions for primary tools. These tools must come from config.lldb_tools_dir 92 # which is basically the build output directory. We do not want to find these in path or 93 # anywhere else, since they are specifically the programs which are actually being tested. 94 95 dsname = "debugserver" if platform.system() in ["Darwin"] else "lldb-server" 96 dsargs = [] if platform.system() in ["Darwin"] else ["gdbserver"] 97 98 build_script = os.path.dirname(__file__) 99 build_script = os.path.join(build_script, "build.py") 100 build_script_args = [ 101 build_script, 102 ( 103 "--compiler=clang" if config.enable_remote else "--compiler=any" 104 ), # Default to best compiler 105 "--arch=" + str(config.lldb_bitness), 106 ] 107 if config.lldb_lit_tools_dir: 108 build_script_args.append("--tools-dir={0}".format(config.lldb_lit_tools_dir)) 109 if config.lldb_tools_dir: 110 build_script_args.append("--tools-dir={0}".format(config.lldb_tools_dir)) 111 if config.llvm_libs_dir: 112 build_script_args.append("--libs-dir={0}".format(config.llvm_libs_dir)) 113 if config.objc_gnustep_dir: 114 build_script_args.append( 115 '--objc-gnustep-dir="{0}"'.format(config.objc_gnustep_dir) 116 ) 117 if config.cmake_sysroot: 118 build_script_args.append("--sysroot={0}".format(config.cmake_sysroot)) 119 120 lldb_init = _get_lldb_init_path(config) 121 122 primary_tools = [ 123 ToolSubst( 124 "%lldb", 125 command=FindTool("lldb"), 126 extra_args=get_lldb_args(config), 127 unresolved="fatal", 128 ), 129 ToolSubst( 130 "%lldb-init", 131 command=FindTool("lldb"), 132 extra_args=["-S", lldb_init], 133 unresolved="fatal", 134 ), 135 ToolSubst( 136 "%lldb-noinit", 137 command=FindTool("lldb"), 138 extra_args=["--no-lldbinit"], 139 unresolved="fatal", 140 ), 141 ToolSubst( 142 "%lldb-server", 143 command=FindTool("lldb-server"), 144 extra_args=[], 145 unresolved="ignore", 146 ), 147 ToolSubst( 148 "%debugserver", 149 command=FindTool(dsname), 150 extra_args=dsargs, 151 unresolved="ignore", 152 ), 153 ToolSubst( 154 "%platformserver", 155 command=FindTool("lldb-server"), 156 extra_args=["platform"], 157 unresolved="ignore", 158 ), 159 "lldb-test", 160 "lldb-dap", 161 ToolSubst( 162 "%build", command="'" + sys.executable + "'", extra_args=build_script_args 163 ), 164 ] 165 166 _disallow(config, "lldb") 167 _disallow(config, "lldb-server") 168 _disallow(config, "debugserver") 169 _disallow(config, "platformserver") 170 171 llvm_config.add_tool_substitutions(primary_tools, [config.lldb_tools_dir]) 172 173 174def _use_msvc_substitutions(config): 175 # If running from a Visual Studio Command prompt (e.g. vcvars), this will 176 # detect the include and lib paths, and find cl.exe and link.exe and create 177 # substitutions for each of them that explicitly specify /I and /L paths 178 cl = lit.util.which("cl") 179 180 if not cl: 181 return 182 183 # Don't use lit.util.which() for link.exe: In `git bash`, it will pick 184 # up /usr/bin/link (another name for ln). 185 link = os.path.join(os.path.dirname(cl), "link.exe") 186 187 cl = '"' + cl + '"' 188 link = '"' + link + '"' 189 includes = os.getenv("INCLUDE", "").split(";") 190 libs = os.getenv("LIB", "").split(";") 191 192 config.available_features.add("msvc") 193 compiler_flags = ['"/I{}"'.format(x) for x in includes if os.path.exists(x)] 194 linker_flags = ['"/LIBPATH:{}"'.format(x) for x in libs if os.path.exists(x)] 195 196 tools = [ 197 ToolSubst("%msvc_cl", command=cl, extra_args=compiler_flags), 198 ToolSubst("%msvc_link", command=link, extra_args=linker_flags), 199 ] 200 llvm_config.add_tool_substitutions(tools) 201 return 202 203 204def use_support_substitutions(config): 205 # Set up substitutions for support tools. These tools can be overridden at the CMake 206 # level (by specifying -DLLDB_LIT_TOOLS_DIR), installed, or as a last resort, we can use 207 # the just-built version. 208 if config.enable_remote: 209 host_flags = ["--target=" + config.target_triple] 210 else: 211 host_flags = ["--target=" + config.host_triple] 212 if platform.system() in ["Darwin"]: 213 try: 214 out = subprocess.check_output(["xcrun", "--show-sdk-path"]).strip() 215 res = 0 216 except OSError: 217 res = -1 218 if res == 0 and out: 219 sdk_path = lit.util.to_string(out) 220 llvm_config.lit_config.note("using SDKROOT: %r" % sdk_path) 221 host_flags += ["-isysroot", sdk_path] 222 elif sys.platform != "win32": 223 host_flags += ["-pthread"] 224 225 if sys.platform.startswith("netbsd"): 226 # needed e.g. to use freshly built libc++ 227 host_flags += [ 228 "-L" + config.llvm_libs_dir, 229 "-Wl,-rpath," + config.llvm_libs_dir, 230 ] 231 232 # The clang module cache is used for building inferiors. 233 host_flags += ["-fmodules-cache-path={}".format(config.clang_module_cache)] 234 235 if config.cmake_sysroot: 236 host_flags += ["--sysroot={}".format(config.cmake_sysroot)] 237 238 if config.enable_remote and config.has_libcxx: 239 host_flags += [ 240 "-L{}".format(config.libcxx_libs_dir), 241 "-lc++", 242 ] 243 244 host_flags = " ".join(host_flags) 245 config.substitutions.append(("%clang_host", "%clang " + host_flags)) 246 config.substitutions.append(("%clangxx_host", "%clangxx " + host_flags)) 247 config.substitutions.append( 248 ("%clang_cl_host", "%clang_cl --target=" + config.host_triple) 249 ) 250 251 additional_tool_dirs = [] 252 if config.lldb_lit_tools_dir: 253 additional_tool_dirs.append(config.lldb_lit_tools_dir) 254 255 llvm_config.use_clang( 256 additional_flags=["--target=specify-a-target-or-use-a-_host-substitution"], 257 additional_tool_dirs=additional_tool_dirs, 258 required=True, 259 use_installed=True, 260 ) 261 262 if sys.platform == "win32": 263 _use_msvc_substitutions(config) 264 265 have_lld = llvm_config.use_lld( 266 additional_tool_dirs=additional_tool_dirs, required=False, use_installed=True 267 ) 268 if have_lld: 269 config.available_features.add("lld") 270 271 support_tools = [ 272 "yaml2obj", 273 "obj2yaml", 274 "llvm-dwp", 275 "llvm-pdbutil", 276 "llvm-mc", 277 "llvm-readobj", 278 "llvm-objdump", 279 "llvm-objcopy", 280 "lli", 281 ] 282 additional_tool_dirs += [config.lldb_tools_dir, config.llvm_tools_dir] 283 llvm_config.add_tool_substitutions(support_tools, additional_tool_dirs) 284 285 _disallow(config, "clang") 286