xref: /llvm-project/lldb/packages/Python/lldbsuite/test/builders/builder.py (revision 058ede06c4ffd4e3c9f54d947e3bfb027c2d0557)
1b623f3c0SJonas Devlieghereimport os
244fc987eSVladislav Dzhidzhoevimport pathlib
3b623f3c0SJonas Devlieghereimport platform
4b623f3c0SJonas Devlieghereimport subprocess
5b623f3c0SJonas Devlieghereimport sys
6551d1188SPavel Labathimport itertools
7b623f3c0SJonas Devlieghere
8b623f3c0SJonas Devlieghereimport lldbsuite.test.lldbtest as lldbtest
944fc987eSVladislav Dzhidzhoevimport lldbsuite.test.lldbplatformutil as lldbplatformutil
10b623f3c0SJonas Devlieghereimport lldbsuite.test.lldbutil as lldbutil
11b623f3c0SJonas Devliegherefrom lldbsuite.test import configuration
12b623f3c0SJonas Devliegherefrom lldbsuite.test_event import build_exception
13*058ede06SVladislav Dzhidzhoevfrom lldbsuite.support import seven
14b623f3c0SJonas Devlieghere
15b623f3c0SJonas Devlieghere
16b623f3c0SJonas Devlieghereclass Builder:
17b623f3c0SJonas Devlieghere    def getArchitecture(self):
18b623f3c0SJonas Devlieghere        """Returns the architecture in effect the test suite is running with."""
19b623f3c0SJonas Devlieghere        return configuration.arch if configuration.arch else ""
20b623f3c0SJonas Devlieghere
21b623f3c0SJonas Devlieghere    def getCompiler(self):
22b623f3c0SJonas Devlieghere        """Returns the compiler in effect the test suite is running with."""
23b623f3c0SJonas Devlieghere        compiler = configuration.compiler if configuration.compiler else "clang"
24b623f3c0SJonas Devlieghere        compiler = lldbutil.which(compiler)
25b623f3c0SJonas Devlieghere        return os.path.abspath(compiler)
26b623f3c0SJonas Devlieghere
270f12cf7eSJonas Devlieghere    def getTriple(self, arch):
280f12cf7eSJonas Devlieghere        """Returns the triple for the given architecture or None."""
290f12cf7eSJonas Devlieghere        return None
300f12cf7eSJonas Devlieghere
31074c591aSJonas Devlieghere    def getExtraMakeArgs(self):
32074c591aSJonas Devlieghere        """
33074c591aSJonas Devlieghere        Helper function to return extra argumentsfor the make system. This
34074c591aSJonas Devlieghere        method is meant to be overridden by platform specific builders.
35074c591aSJonas Devlieghere        """
36551d1188SPavel Labath        return []
37e5d08fcbSJonas Devlieghere
38e5d08fcbSJonas Devlieghere    def getArchCFlags(self, architecture):
39e5d08fcbSJonas Devlieghere        """Returns the ARCH_CFLAGS for the make system."""
40551d1188SPavel Labath        return []
41074c591aSJonas Devlieghere
42b623f3c0SJonas Devlieghere    def getMake(self, test_subdir, test_name):
43b623f3c0SJonas Devlieghere        """Returns the invocation for GNU make.
44b623f3c0SJonas Devlieghere        The first argument is a tuple of the relative path to the testcase
45b623f3c0SJonas Devlieghere        and its filename stem."""
46b623f3c0SJonas Devlieghere        # Construct the base make invocation.
47b623f3c0SJonas Devlieghere        lldb_test = os.environ["LLDB_TEST"]
482238dcc3SJonas Devlieghere        if not (
492238dcc3SJonas Devlieghere            lldb_test
502238dcc3SJonas Devlieghere            and configuration.test_build_dir
512238dcc3SJonas Devlieghere            and test_subdir
522238dcc3SJonas Devlieghere            and test_name
532238dcc3SJonas Devlieghere            and (not os.path.isabs(test_subdir))
542238dcc3SJonas Devlieghere        ):
55b623f3c0SJonas Devlieghere            raise Exception("Could not derive test directories")
562238dcc3SJonas Devlieghere        build_dir = os.path.join(configuration.test_build_dir, test_subdir, test_name)
57b623f3c0SJonas Devlieghere        src_dir = os.path.join(configuration.test_src_root, test_subdir)
58b623f3c0SJonas Devlieghere        # This is a bit of a hack to make inline testcases work.
59b623f3c0SJonas Devlieghere        makefile = os.path.join(src_dir, "Makefile")
60b623f3c0SJonas Devlieghere        if not os.path.isfile(makefile):
61b623f3c0SJonas Devlieghere            makefile = os.path.join(build_dir, "Makefile")
62b623f3c0SJonas Devlieghere        return [
636b7b05b5SVladislav Dzhidzhoev            configuration.make_path,
642238dcc3SJonas Devlieghere            "VPATH=" + src_dir,
652238dcc3SJonas Devlieghere            "-C",
662238dcc3SJonas Devlieghere            build_dir,
672238dcc3SJonas Devlieghere            "-I",
682238dcc3SJonas Devlieghere            src_dir,
692238dcc3SJonas Devlieghere            "-I",
702238dcc3SJonas Devlieghere            os.path.join(lldb_test, "make"),
712238dcc3SJonas Devlieghere            "-f",
722238dcc3SJonas Devlieghere            makefile,
73b623f3c0SJonas Devlieghere        ]
74b623f3c0SJonas Devlieghere
75b623f3c0SJonas Devlieghere    def getCmdLine(self, d):
76b623f3c0SJonas Devlieghere        """
77551d1188SPavel Labath        Helper function to return a command line argument string used for the
78551d1188SPavel Labath        make system.
79b623f3c0SJonas Devlieghere        """
80b623f3c0SJonas Devlieghere
81551d1188SPavel Labath        # If d is None or an empty mapping, just return an empty list.
82b623f3c0SJonas Devlieghere        if not d:
83551d1188SPavel Labath            return []
84b623f3c0SJonas Devlieghere
85b623f3c0SJonas Devlieghere        def setOrAppendVariable(k, v):
86b623f3c0SJonas Devlieghere            append_vars = ["CFLAGS", "CFLAGS_EXTRAS", "LD_EXTRAS"]
87b623f3c0SJonas Devlieghere            if k in append_vars and k in os.environ:
88b623f3c0SJonas Devlieghere                v = os.environ[k] + " " + v
892238dcc3SJonas Devlieghere            return "%s=%s" % (k, v)
90b623f3c0SJonas Devlieghere
91551d1188SPavel Labath        cmdline = [setOrAppendVariable(k, v) for k, v in list(d.items())]
92b623f3c0SJonas Devlieghere
93b623f3c0SJonas Devlieghere        return cmdline
94b623f3c0SJonas Devlieghere
95b623f3c0SJonas Devlieghere    def getArchSpec(self, architecture):
96b623f3c0SJonas Devlieghere        """
97b623f3c0SJonas Devlieghere        Helper function to return the key-value string to specify the architecture
98b623f3c0SJonas Devlieghere        used for the make system.
99b623f3c0SJonas Devlieghere        """
100551d1188SPavel Labath        return ["ARCH=" + architecture] if architecture else []
101b623f3c0SJonas Devlieghere
10244fc987eSVladislav Dzhidzhoev    def getToolchainSpec(self, compiler):
103b623f3c0SJonas Devlieghere        """
10444fc987eSVladislav Dzhidzhoev        Helper function to return the key-value strings to specify the toolchain
105b623f3c0SJonas Devlieghere        used for the make system.
106b623f3c0SJonas Devlieghere        """
107b623f3c0SJonas Devlieghere        cc = compiler if compiler else None
108b623f3c0SJonas Devlieghere        if not cc and configuration.compiler:
109b623f3c0SJonas Devlieghere            cc = configuration.compiler
11044fc987eSVladislav Dzhidzhoev
11144fc987eSVladislav Dzhidzhoev        if not cc:
112551d1188SPavel Labath            return []
113b623f3c0SJonas Devlieghere
114aea06684SVladislav Dzhidzhoev        exe_ext = ""
115aea06684SVladislav Dzhidzhoev        if lldbplatformutil.getHostPlatform() == "windows":
116aea06684SVladislav Dzhidzhoev            exe_ext = ".exe"
117aea06684SVladislav Dzhidzhoev
11844fc987eSVladislav Dzhidzhoev        cc = cc.strip()
11944fc987eSVladislav Dzhidzhoev        cc_path = pathlib.Path(cc)
12044fc987eSVladislav Dzhidzhoev
12144fc987eSVladislav Dzhidzhoev        # We can get CC compiler string in the following formats:
12244fc987eSVladislav Dzhidzhoev        #  [<tool>] <compiler>    - such as 'xrun clang', 'xrun /usr/bin/clang' & etc
12344fc987eSVladislav Dzhidzhoev        #
12444fc987eSVladislav Dzhidzhoev        # Where <compiler> could contain the following parts:
12544fc987eSVladislav Dzhidzhoev        #   <simple-name>[.<exe-ext>]                           - sucn as 'clang', 'clang.exe' ('clang-cl.exe'?)
12644fc987eSVladislav Dzhidzhoev        #   <target-triple>-<simple-name>[.<exe-ext>]           - such as 'armv7-linux-gnueabi-gcc'
12744fc987eSVladislav Dzhidzhoev        #   <path>/<simple-name>[.<exe-ext>]                    - such as '/usr/bin/clang', 'c:\path\to\compiler\clang,exe'
12844fc987eSVladislav Dzhidzhoev        #   <path>/<target-triple>-<simple-name>[.<exe-ext>]    - such as '/usr/bin/clang', 'c:\path\to\compiler\clang,exe'
12944fc987eSVladislav Dzhidzhoev
13044fc987eSVladislav Dzhidzhoev        cc_ext = cc_path.suffix
13144fc987eSVladislav Dzhidzhoev        # Compiler name without extension
13244fc987eSVladislav Dzhidzhoev        cc_name = cc_path.stem.split(" ")[-1]
13344fc987eSVladislav Dzhidzhoev
13444fc987eSVladislav Dzhidzhoev        # A kind of compiler (canonical name): clang, gcc, cc & etc.
13544fc987eSVladislav Dzhidzhoev        cc_type = cc_name
13644fc987eSVladislav Dzhidzhoev        # A triple prefix of compiler name: <armv7-none-linux-gnu->gcc
13744fc987eSVladislav Dzhidzhoev        cc_prefix = ""
13844fc987eSVladislav Dzhidzhoev        if not "clang-cl" in cc_name and not "llvm-gcc" in cc_name:
13944fc987eSVladislav Dzhidzhoev            cc_name_parts = cc_name.split("-")
14044fc987eSVladislav Dzhidzhoev            cc_type = cc_name_parts[-1]
14144fc987eSVladislav Dzhidzhoev            if len(cc_name_parts) > 1:
14244fc987eSVladislav Dzhidzhoev                cc_prefix = "-".join(cc_name_parts[:-1]) + "-"
14344fc987eSVladislav Dzhidzhoev
14444fc987eSVladislav Dzhidzhoev        # A kind of C++ compiler.
14544fc987eSVladislav Dzhidzhoev        cxx_types = {
14644fc987eSVladislav Dzhidzhoev            "icc": "icpc",
14744fc987eSVladislav Dzhidzhoev            "llvm-gcc": "llvm-g++",
14844fc987eSVladislav Dzhidzhoev            "gcc": "g++",
14944fc987eSVladislav Dzhidzhoev            "cc": "c++",
15044fc987eSVladislav Dzhidzhoev            "clang": "clang++",
15144fc987eSVladislav Dzhidzhoev        }
15244fc987eSVladislav Dzhidzhoev        cxx_type = cxx_types.get(cc_type, cc_type)
15344fc987eSVladislav Dzhidzhoev
15444fc987eSVladislav Dzhidzhoev        cc_dir = cc_path.parent
15544fc987eSVladislav Dzhidzhoev
15644fc987eSVladislav Dzhidzhoev        def getToolchainUtil(util_name):
157aea06684SVladislav Dzhidzhoev            return os.path.join(configuration.llvm_tools_dir, util_name + exe_ext)
15844fc987eSVladislav Dzhidzhoev
159aea06684SVladislav Dzhidzhoev        cxx = cc_dir / (cc_prefix + cxx_type + cc_ext)
16044fc987eSVladislav Dzhidzhoev
16144fc987eSVladislav Dzhidzhoev        util_names = {
16244fc987eSVladislav Dzhidzhoev            "OBJCOPY": "objcopy",
16344fc987eSVladislav Dzhidzhoev            "STRIP": "strip",
16444fc987eSVladislav Dzhidzhoev            "ARCHIVER": "ar",
16544fc987eSVladislav Dzhidzhoev            "DWP": "dwp",
16644fc987eSVladislav Dzhidzhoev        }
16744fc987eSVladislav Dzhidzhoev        utils = []
16844fc987eSVladislav Dzhidzhoev
169aea06684SVladislav Dzhidzhoev        # Required by API TestBSDArchives.py tests.
170aea06684SVladislav Dzhidzhoev        if not os.getenv("LLVM_AR"):
171aea06684SVladislav Dzhidzhoev            utils.extend(["LLVM_AR=%s" % getToolchainUtil("llvm-ar")])
172aea06684SVladislav Dzhidzhoev
17344fc987eSVladislav Dzhidzhoev        if cc_type in ["clang", "cc", "gcc"]:
17444fc987eSVladislav Dzhidzhoev            util_paths = {}
17544fc987eSVladislav Dzhidzhoev            # Assembly a toolchain side tool cmd based on passed CC.
17644fc987eSVladislav Dzhidzhoev            for var, name in util_names.items():
17744fc987eSVladislav Dzhidzhoev                # Do not override explicity specified tool from the cmd line.
17844fc987eSVladislav Dzhidzhoev                if not os.getenv(var):
179e7174a83SVladislav Dzhidzhoev                    util_paths[var] = getToolchainUtil("llvm-" + name)
18044fc987eSVladislav Dzhidzhoev                else:
18144fc987eSVladislav Dzhidzhoev                    util_paths[var] = os.getenv(var)
18244fc987eSVladislav Dzhidzhoev            utils.extend(["AR=%s" % util_paths["ARCHIVER"]])
18344fc987eSVladislav Dzhidzhoev
18444fc987eSVladislav Dzhidzhoev            # Look for llvm-dwp or gnu dwp
18544fc987eSVladislav Dzhidzhoev            if not lldbutil.which(util_paths["DWP"]):
18644fc987eSVladislav Dzhidzhoev                util_paths["DWP"] = getToolchainUtil("llvm-dwp")
18744fc987eSVladislav Dzhidzhoev            if not lldbutil.which(util_paths["DWP"]):
18844fc987eSVladislav Dzhidzhoev                util_paths["DWP"] = lldbutil.which("llvm-dwp")
18944fc987eSVladislav Dzhidzhoev            if not util_paths["DWP"]:
19044fc987eSVladislav Dzhidzhoev                util_paths["DWP"] = lldbutil.which("dwp")
19144fc987eSVladislav Dzhidzhoev                if not util_paths["DWP"]:
19244fc987eSVladislav Dzhidzhoev                    del util_paths["DWP"]
19344fc987eSVladislav Dzhidzhoev
194*058ede06SVladislav Dzhidzhoev            if lldbplatformutil.platformIsDarwin():
195*058ede06SVladislav Dzhidzhoev                util_paths["STRIP"] = seven.get_command_output("xcrun -f strip")
196*058ede06SVladislav Dzhidzhoev
19744fc987eSVladislav Dzhidzhoev            for var, path in util_paths.items():
19844fc987eSVladislav Dzhidzhoev                utils.append("%s=%s" % (var, path))
199b773da0cSVladislav Dzhidzhoev
200b773da0cSVladislav Dzhidzhoev        if lldbplatformutil.platformIsDarwin():
20144fc987eSVladislav Dzhidzhoev            utils.extend(["AR=%slibtool" % os.getenv("CROSS_COMPILE", "")])
20244fc987eSVladislav Dzhidzhoev
20344fc987eSVladislav Dzhidzhoev        return [
20444fc987eSVladislav Dzhidzhoev            "CC=%s" % cc,
20544fc987eSVladislav Dzhidzhoev            "CC_TYPE=%s" % cc_type,
20644fc987eSVladislav Dzhidzhoev            "CXX=%s" % cxx,
20744fc987eSVladislav Dzhidzhoev        ] + utils
20844fc987eSVladislav Dzhidzhoev
209b623f3c0SJonas Devlieghere    def getSDKRootSpec(self):
210b623f3c0SJonas Devlieghere        """
211b623f3c0SJonas Devlieghere        Helper function to return the key-value string to specify the SDK root
212b623f3c0SJonas Devlieghere        used for the make system.
213b623f3c0SJonas Devlieghere        """
214b623f3c0SJonas Devlieghere        if configuration.sdkroot:
215551d1188SPavel Labath            return ["SDKROOT={}".format(configuration.sdkroot)]
216551d1188SPavel Labath        return []
217b623f3c0SJonas Devlieghere
218b623f3c0SJonas Devlieghere    def getModuleCacheSpec(self):
219b623f3c0SJonas Devlieghere        """
220b623f3c0SJonas Devlieghere        Helper function to return the key-value string to specify the clang
221b623f3c0SJonas Devlieghere        module cache used for the make system.
222b623f3c0SJonas Devlieghere        """
223b623f3c0SJonas Devlieghere        if configuration.clang_module_cache_dir:
2242238dcc3SJonas Devlieghere            return [
2252238dcc3SJonas Devlieghere                "CLANG_MODULE_CACHE_DIR={}".format(configuration.clang_module_cache_dir)
2262238dcc3SJonas Devlieghere            ]
227551d1188SPavel Labath        return []
228b623f3c0SJonas Devlieghere
229ce233e71SJonas Devlieghere    def getLibCxxArgs(self):
230cc0b5ebfSJonas Devlieghere        if configuration.libcxx_include_dir and configuration.libcxx_library_dir:
2312238dcc3SJonas Devlieghere            libcpp_args = [
2322238dcc3SJonas Devlieghere                "LIBCPP_INCLUDE_DIR={}".format(configuration.libcxx_include_dir),
2332238dcc3SJonas Devlieghere                "LIBCPP_LIBRARY_DIR={}".format(configuration.libcxx_library_dir),
2342238dcc3SJonas Devlieghere            ]
235cb0eb9d8SJordan Rupprecht            if configuration.libcxx_include_target_dir:
2362238dcc3SJonas Devlieghere                libcpp_args.append(
2372238dcc3SJonas Devlieghere                    "LIBCPP_INCLUDE_TARGET_DIR={}".format(
2382238dcc3SJonas Devlieghere                        configuration.libcxx_include_target_dir
2392238dcc3SJonas Devlieghere                    )
2402238dcc3SJonas Devlieghere                )
241cb0eb9d8SJordan Rupprecht            return libcpp_args
242ce233e71SJonas Devlieghere        return []
243ce233e71SJonas Devlieghere
244b88d2112SAdrian Prantl    def getLLDBObjRoot(self):
245b88d2112SAdrian Prantl        return ["LLDB_OBJ_ROOT={}".format(configuration.lldb_obj_root)]
246b88d2112SAdrian Prantl
2478bac18beSPavel Labath    def _getDebugInfoArgs(self, debug_info):
2488bac18beSPavel Labath        if debug_info is None:
2498bac18beSPavel Labath            return []
2508bac18beSPavel Labath        if debug_info == "dwarf":
2518bac18beSPavel Labath            return ["MAKE_DSYM=NO"]
2528bac18beSPavel Labath        if debug_info == "dwo":
2538bac18beSPavel Labath            return ["MAKE_DSYM=NO", "MAKE_DWO=YES"]
2548bac18beSPavel Labath        if debug_info == "gmodules":
2558bac18beSPavel Labath            return ["MAKE_DSYM=NO", "MAKE_GMODULES=YES"]
2568bac18beSPavel Labath        return None
2578bac18beSPavel Labath
2582238dcc3SJonas Devlieghere    def getBuildCommand(
2592238dcc3SJonas Devlieghere        self,
2602238dcc3SJonas Devlieghere        debug_info,
2612238dcc3SJonas Devlieghere        architecture=None,
2622238dcc3SJonas Devlieghere        compiler=None,
2632238dcc3SJonas Devlieghere        dictionary=None,
2642238dcc3SJonas Devlieghere        testdir=None,
2652238dcc3SJonas Devlieghere        testname=None,
2662238dcc3SJonas Devlieghere        make_targets=None,
2672238dcc3SJonas Devlieghere    ):
2688bac18beSPavel Labath        debug_info_args = self._getDebugInfoArgs(debug_info)
2698bac18beSPavel Labath        if debug_info_args is None:
270eee887e0SPavel Labath            return None
2714763200eSGreg Clayton        if make_targets is None:
2724763200eSGreg Clayton            make_targets = ["all"]
273551d1188SPavel Labath        command_parts = [
2742238dcc3SJonas Devlieghere            self.getMake(testdir, testname),
2752238dcc3SJonas Devlieghere            debug_info_args,
2762238dcc3SJonas Devlieghere            make_targets,
2772238dcc3SJonas Devlieghere            self.getArchCFlags(architecture),
2782238dcc3SJonas Devlieghere            self.getArchSpec(architecture),
27944fc987eSVladislav Dzhidzhoev            self.getToolchainSpec(compiler),
2802238dcc3SJonas Devlieghere            self.getExtraMakeArgs(),
2812238dcc3SJonas Devlieghere            self.getSDKRootSpec(),
2822238dcc3SJonas Devlieghere            self.getModuleCacheSpec(),
2832238dcc3SJonas Devlieghere            self.getLibCxxArgs(),
284b88d2112SAdrian Prantl            self.getLLDBObjRoot(),
2852238dcc3SJonas Devlieghere            self.getCmdLine(dictionary),
2862238dcc3SJonas Devlieghere        ]
287551d1188SPavel Labath        command = list(itertools.chain(*command_parts))
288b623f3c0SJonas Devlieghere
289eee887e0SPavel Labath        return command
290b623f3c0SJonas Devlieghere
291551d1188SPavel Labath    def cleanup(self, dictionary=None):
292b623f3c0SJonas Devlieghere        """Perform a platform-specific cleanup after the test."""
293b623f3c0SJonas Devlieghere        return True
294