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 return ("ARCH=" + architecture) if architecture else "" 97 98 def getCCSpec(self, compiler): 99 """ 100 Helper function to return the key-value string to specify the compiler 101 used for the make system. 102 """ 103 cc = compiler if compiler else None 104 if not cc and configuration.compiler: 105 cc = configuration.compiler 106 if cc: 107 return "CC=\"%s\"" % cc 108 else: 109 return "" 110 111 def getSDKRootSpec(self): 112 """ 113 Helper function to return the key-value string to specify the SDK root 114 used for the make system. 115 """ 116 if configuration.sdkroot: 117 return "SDKROOT={}".format(configuration.sdkroot) 118 return "" 119 120 def getModuleCacheSpec(self): 121 """ 122 Helper function to return the key-value string to specify the clang 123 module cache used for the make system. 124 """ 125 if configuration.clang_module_cache_dir: 126 return "CLANG_MODULE_CACHE_DIR={}".format( 127 configuration.clang_module_cache_dir) 128 return "" 129 130 def buildDefault(self, 131 sender=None, 132 architecture=None, 133 compiler=None, 134 dictionary=None, 135 testdir=None, 136 testname=None): 137 """Build the binaries the default way.""" 138 commands = [] 139 commands.append( 140 self.getMake(testdir, testname) + [ 141 "all", 142 self.getArchCFlags(architecture), 143 self.getArchSpec(architecture), 144 self.getCCSpec(compiler), 145 self.getExtraMakeArgs(), 146 self.getSDKRootSpec(), 147 self.getModuleCacheSpec(), 148 self.getCmdLine(dictionary) 149 ]) 150 151 self.runBuildCommands(commands, sender=sender) 152 153 # True signifies that we can handle building default. 154 return True 155 156 def buildDwarf(self, 157 sender=None, 158 architecture=None, 159 compiler=None, 160 dictionary=None, 161 testdir=None, 162 testname=None): 163 """Build the binaries with dwarf debug info.""" 164 commands = [] 165 commands.append( 166 self.getMake(testdir, testname) + [ 167 "MAKE_DSYM=NO", 168 self.getArchCFlags(architecture), 169 self.getArchSpec(architecture), 170 self.getCCSpec(compiler), 171 self.getExtraMakeArgs(), 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.getArchCFlags(architecture), 194 self.getArchSpec(architecture), 195 self.getCCSpec(compiler), 196 self.getExtraMakeArgs(), 197 self.getSDKRootSpec(), 198 self.getModuleCacheSpec(), 199 self.getCmdLine(dictionary) 200 ]) 201 202 self.runBuildCommands(commands, sender=sender) 203 # True signifies that we can handle building dwo. 204 return True 205 206 def buildGModules(self, 207 sender=None, 208 architecture=None, 209 compiler=None, 210 dictionary=None, 211 testdir=None, 212 testname=None): 213 """Build the binaries with dwarf debug info.""" 214 commands = [] 215 commands.append( 216 self.getMake(testdir, testname) + [ 217 "MAKE_DSYM=NO", "MAKE_GMODULES=YES", 218 self.getArchCFlags(architecture), 219 self.getArchSpec(architecture), 220 self.getCCSpec(compiler), 221 self.getExtraMakeArgs(), 222 self.getSDKRootSpec(), 223 self.getModuleCacheSpec(), 224 self.getCmdLine(dictionary) 225 ]) 226 227 self.runBuildCommands(commands, sender=sender) 228 # True signifies that we can handle building with gmodules. 229 return True 230 231 def buildDsym(self, 232 sender=None, 233 architecture=None, 234 compiler=None, 235 dictionary=None, 236 testdir=None, 237 testname=None): 238 # False signifies that we cannot handle building with dSYM. 239 return False 240 241 def cleanup(self, sender=None, dictionary=None): 242 """Perform a platform-specific cleanup after the test.""" 243 return True 244