xref: /llvm-project/lldb/test/Shell/helper/toolchain.py (revision 88591aa0ca7e4d99da353d49f91ea63e43fb55e0)
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