1import os 2import platform 3import subprocess 4import sys 5 6import lldbsuite.test.lldbtest as lldbtest 7import lldbsuite.test.lldbutil as lldbutil 8from lldbsuite.test import configuration 9from lldbsuite.test_event import build_exception 10 11 12class Builder: 13 def getArchitecture(self): 14 """Returns the architecture in effect the test suite is running with.""" 15 return configuration.arch if configuration.arch else "" 16 17 def getCompiler(self): 18 """Returns the compiler in effect the test suite is running with.""" 19 compiler = configuration.compiler if configuration.compiler else "clang" 20 compiler = lldbutil.which(compiler) 21 return os.path.abspath(compiler) 22 23 def getMake(self, test_subdir, test_name): 24 """Returns the invocation for GNU make. 25 The first argument is a tuple of the relative path to the testcase 26 and its filename stem.""" 27 if platform.system() == "FreeBSD" or platform.system() == "NetBSD": 28 make = "gmake" 29 else: 30 make = "make" 31 32 # Construct the base make invocation. 33 lldb_test = os.environ["LLDB_TEST"] 34 if not (lldb_test and configuration.test_build_dir and test_subdir 35 and test_name and (not os.path.isabs(test_subdir))): 36 raise Exception("Could not derive test directories") 37 build_dir = os.path.join(configuration.test_build_dir, test_subdir, 38 test_name) 39 src_dir = os.path.join(configuration.test_src_root, test_subdir) 40 # This is a bit of a hack to make inline testcases work. 41 makefile = os.path.join(src_dir, "Makefile") 42 if not os.path.isfile(makefile): 43 makefile = os.path.join(build_dir, "Makefile") 44 return [ 45 make, "VPATH=" + src_dir, "-C", build_dir, "-I", src_dir, "-I", 46 os.path.join(lldb_test, "make"), "-f", makefile 47 ] 48 49 def getCmdLine(self, d): 50 """ 51 Helper function to return a properly formatted command line argument(s) 52 string used for the make system. 53 """ 54 55 # If d is None or an empty mapping, just return an empty string. 56 if not d: 57 return "" 58 pattern = '%s="%s"' if "win32" in sys.platform else "%s='%s'" 59 60 def setOrAppendVariable(k, v): 61 append_vars = ["CFLAGS", "CFLAGS_EXTRAS", "LD_EXTRAS"] 62 if k in append_vars and k in os.environ: 63 v = os.environ[k] + " " + v 64 return pattern % (k, v) 65 66 cmdline = " ".join( 67 [setOrAppendVariable(k, v) for k, v in list(d.items())]) 68 69 return cmdline 70 71 def runBuildCommands(self, commands, sender): 72 try: 73 lldbtest.system(commands, sender=sender) 74 except subprocess.CalledProcessError as called_process_error: 75 # Convert to a build-specific error. 76 # We don't do that in lldbtest.system() since that 77 # is more general purpose. 78 raise build_exception.BuildError(called_process_error) 79 80 def getArchSpec(self, architecture): 81 """ 82 Helper function to return the key-value string to specify the architecture 83 used for the make system. 84 """ 85 arch = architecture if architecture else None 86 if not arch and configuration.arch: 87 arch = configuration.arch 88 89 return ("ARCH=" + arch) if arch else "" 90 91 def getCCSpec(self, compiler): 92 """ 93 Helper function to return the key-value string to specify the compiler 94 used for the make system. 95 """ 96 cc = compiler if compiler else None 97 if not cc and configuration.compiler: 98 cc = configuration.compiler 99 if cc: 100 return "CC=\"%s\"" % cc 101 else: 102 return "" 103 104 def getDsymutilSpec(self): 105 """ 106 Helper function to return the key-value string to specify the dsymutil 107 used for the make system. 108 """ 109 if configuration.dsymutil: 110 return "DSYMUTIL={}".format(configuration.dsymutil) 111 return "" 112 113 def getSDKRootSpec(self): 114 """ 115 Helper function to return the key-value string to specify the SDK root 116 used for the make system. 117 """ 118 if configuration.sdkroot: 119 return "SDKROOT={}".format(configuration.sdkroot) 120 return "" 121 122 def getModuleCacheSpec(self): 123 """ 124 Helper function to return the key-value string to specify the clang 125 module cache used for the make system. 126 """ 127 if configuration.clang_module_cache_dir: 128 return "CLANG_MODULE_CACHE_DIR={}".format( 129 configuration.clang_module_cache_dir) 130 return "" 131 132 def buildDefault(self, 133 sender=None, 134 architecture=None, 135 compiler=None, 136 dictionary=None, 137 testdir=None, 138 testname=None): 139 """Build the binaries the default way.""" 140 commands = [] 141 commands.append( 142 self.getMake(testdir, testname) + [ 143 "all", 144 self.getArchSpec(architecture), 145 self.getCCSpec(compiler), 146 self.getDsymutilSpec(), 147 self.getSDKRootSpec(), 148 self.getModuleCacheSpec(), 149 self.getCmdLine(dictionary) 150 ]) 151 152 self.runBuildCommands(commands, sender=sender) 153 154 # True signifies that we can handle building default. 155 return True 156 157 def buildDwarf(self, 158 sender=None, 159 architecture=None, 160 compiler=None, 161 dictionary=None, 162 testdir=None, 163 testname=None): 164 """Build the binaries with dwarf debug info.""" 165 commands = [] 166 commands.append( 167 self.getMake(testdir, testname) + [ 168 "MAKE_DSYM=NO", 169 self.getArchSpec(architecture), 170 self.getCCSpec(compiler), 171 self.getDsymutilSpec(), 172 self.getSDKRootSpec(), 173 self.getModuleCacheSpec(), 174 self.getCmdLine(dictionary) 175 ]) 176 177 self.runBuildCommands(commands, sender=sender) 178 # True signifies that we can handle building dwarf. 179 return True 180 181 def buildDwo(self, 182 sender=None, 183 architecture=None, 184 compiler=None, 185 dictionary=None, 186 testdir=None, 187 testname=None): 188 """Build the binaries with dwarf debug info.""" 189 commands = [] 190 commands.append( 191 self.getMake(testdir, testname) + [ 192 "MAKE_DSYM=NO", "MAKE_DWO=YES", 193 self.getArchSpec(architecture), 194 self.getCCSpec(compiler), 195 self.getDsymutilSpec(), 196 self.getSDKRootSpec(), 197 self.getModuleCacheSpec(), 198 self.getCmdLine(dictionary) 199 ]) 200 201 self.runBuildCommands(commands, sender=sender) 202 # True signifies that we can handle building dwo. 203 return True 204 205 def buildGModules(self, 206 sender=None, 207 architecture=None, 208 compiler=None, 209 dictionary=None, 210 testdir=None, 211 testname=None): 212 """Build the binaries with dwarf debug info.""" 213 commands = [] 214 commands.append( 215 self.getMake(testdir, testname) + [ 216 "MAKE_DSYM=NO", "MAKE_GMODULES=YES", 217 self.getArchSpec(architecture), 218 self.getCCSpec(compiler), 219 self.getDsymutilSpec(), 220 self.getSDKRootSpec(), 221 self.getModuleCacheSpec(), 222 self.getCmdLine(dictionary) 223 ]) 224 225 self.runBuildCommands(commands, sender=sender) 226 # True signifies that we can handle building with gmodules. 227 return True 228 229 def buildDsym(self, 230 sender=None, 231 architecture=None, 232 compiler=None, 233 dictionary=None, 234 testdir=None): 235 # False signifies that we cannot handle building with dSYM. 236 return False 237 238 def cleanup(self, sender=None, dictionary=None): 239 """Perform a platform-specific cleanup after the test.""" 240 return True 241