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