1import os 2import platform 3import subprocess 4import sys 5import itertools 6 7import lldbsuite.test.lldbtest as lldbtest 8import lldbsuite.test.lldbutil as lldbutil 9from lldbsuite.test import configuration 10from lldbsuite.test_event import build_exception 11 12 13class Builder: 14 def getArchitecture(self): 15 """Returns the architecture in effect the test suite is running with.""" 16 return configuration.arch if configuration.arch else "" 17 18 def getCompiler(self): 19 """Returns the compiler in effect the test suite is running with.""" 20 compiler = configuration.compiler if configuration.compiler else "clang" 21 compiler = lldbutil.which(compiler) 22 return os.path.abspath(compiler) 23 24 def getTriple(self, arch): 25 """Returns the triple for the given architecture or None.""" 26 return None 27 28 def getExtraMakeArgs(self): 29 """ 30 Helper function to return extra argumentsfor the make system. This 31 method is meant to be overridden by platform specific builders. 32 """ 33 return [] 34 35 def getArchCFlags(self, architecture): 36 """Returns the ARCH_CFLAGS for the make system.""" 37 return [] 38 39 def getMake(self, test_subdir, test_name): 40 """Returns the invocation for GNU make. 41 The first argument is a tuple of the relative path to the testcase 42 and its filename stem.""" 43 if platform.system() == "FreeBSD" or platform.system() == "NetBSD": 44 make = "gmake" 45 else: 46 make = "make" 47 48 # Construct the base make invocation. 49 lldb_test = os.environ["LLDB_TEST"] 50 if not (lldb_test and configuration.test_build_dir and test_subdir 51 and test_name and (not os.path.isabs(test_subdir))): 52 raise Exception("Could not derive test directories") 53 build_dir = os.path.join(configuration.test_build_dir, test_subdir, 54 test_name) 55 src_dir = os.path.join(configuration.test_src_root, test_subdir) 56 # This is a bit of a hack to make inline testcases work. 57 makefile = os.path.join(src_dir, "Makefile") 58 if not os.path.isfile(makefile): 59 makefile = os.path.join(build_dir, "Makefile") 60 return [ 61 make, "VPATH=" + src_dir, "-C", build_dir, "-I", src_dir, "-I", 62 os.path.join(lldb_test, "make"), "-f", makefile 63 ] 64 65 def getCmdLine(self, d): 66 """ 67 Helper function to return a command line argument string used for the 68 make system. 69 """ 70 71 # If d is None or an empty mapping, just return an empty list. 72 if not d: 73 return [] 74 75 def setOrAppendVariable(k, v): 76 append_vars = ["CFLAGS", "CFLAGS_EXTRAS", "LD_EXTRAS"] 77 if k in append_vars and k in os.environ: 78 v = os.environ[k] + " " + v 79 return '%s=%s' % (k, v) 80 81 cmdline = [setOrAppendVariable(k, v) for k, v in list(d.items())] 82 83 return cmdline 84 85 def getArchSpec(self, architecture): 86 """ 87 Helper function to return the key-value string to specify the architecture 88 used for the make system. 89 """ 90 return ["ARCH=" + architecture] if architecture else [] 91 92 def getCCSpec(self, compiler): 93 """ 94 Helper function to return the key-value string to specify the compiler 95 used for the make system. 96 """ 97 cc = compiler if compiler else None 98 if not cc and configuration.compiler: 99 cc = configuration.compiler 100 if cc: 101 return ["CC=\"%s\"" % cc] 102 return [] 103 104 def getSDKRootSpec(self): 105 """ 106 Helper function to return the key-value string to specify the SDK root 107 used for the make system. 108 """ 109 if configuration.sdkroot: 110 return ["SDKROOT={}".format(configuration.sdkroot)] 111 return [] 112 113 def getModuleCacheSpec(self): 114 """ 115 Helper function to return the key-value string to specify the clang 116 module cache used for the make system. 117 """ 118 if configuration.clang_module_cache_dir: 119 return ["CLANG_MODULE_CACHE_DIR={}".format( 120 configuration.clang_module_cache_dir)] 121 return [] 122 123 def getLibCxxArgs(self): 124 if configuration.libcxx_include_dir and configuration.libcxx_library_dir: 125 libcpp_args = ["LIBCPP_INCLUDE_DIR={}".format(configuration.libcxx_include_dir), 126 "LIBCPP_LIBRARY_DIR={}".format(configuration.libcxx_library_dir)] 127 if configuration.libcxx_include_target_dir: 128 libcpp_args.append("LIBCPP_INCLUDE_TARGET_DIR={}".format( 129 configuration.libcxx_include_target_dir)) 130 return libcpp_args 131 return [] 132 133 def _getDebugInfoArgs(self, debug_info): 134 if debug_info is None: 135 return [] 136 if debug_info == "dwarf": 137 return ["MAKE_DSYM=NO"] 138 if debug_info == "dwo": 139 return ["MAKE_DSYM=NO", "MAKE_DWO=YES"] 140 if debug_info == "gmodules": 141 return ["MAKE_DSYM=NO", "MAKE_GMODULES=YES"] 142 return None 143 144 def getBuildCommand(self, debug_info, architecture=None, compiler=None, 145 dictionary=None, testdir=None, testname=None, make_targets=None): 146 debug_info_args = self._getDebugInfoArgs(debug_info) 147 if debug_info_args is None: 148 return None 149 if make_targets is None: 150 make_targets = ["all"] 151 command_parts = [ 152 self.getMake(testdir, testname), debug_info_args, make_targets, 153 self.getArchCFlags(architecture), self.getArchSpec(architecture), 154 self.getCCSpec(compiler), self.getExtraMakeArgs(), 155 self.getSDKRootSpec(), self.getModuleCacheSpec(), 156 self.getLibCxxArgs(), self.getCmdLine(dictionary)] 157 command = list(itertools.chain(*command_parts)) 158 159 return command 160 161 def cleanup(self, dictionary=None): 162 """Perform a platform-specific cleanup after the test.""" 163 return True 164