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