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 runBuildCommands(self, commands): 86 try: 87 lldbtest.system(commands) 88 except subprocess.CalledProcessError as called_process_error: 89 # Convert to a build-specific error. 90 # We don't do that in lldbtest.system() since that 91 # is more general purpose. 92 raise build_exception.BuildError(called_process_error) 93 94 def getArchSpec(self, architecture): 95 """ 96 Helper function to return the key-value string to specify the architecture 97 used for the make system. 98 """ 99 return ["ARCH=" + architecture] if architecture 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 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 _getDebugInfoArgs(self, debug_info): 133 if debug_info is None: 134 return [] 135 if debug_info == "dwarf": 136 return ["MAKE_DSYM=NO"] 137 if debug_info == "dwo": 138 return ["MAKE_DSYM=NO", "MAKE_DWO=YES"] 139 if debug_info == "gmodules": 140 return ["MAKE_DSYM=NO", "MAKE_GMODULES=YES"] 141 return None 142 143 def build(self, debug_info, architecture=None, compiler=None, 144 dictionary=None, testdir=None, testname=None): 145 debug_info_args = self._getDebugInfoArgs(debug_info) 146 if debug_info_args is None: 147 return False 148 149 command_parts = [ 150 self.getMake(testdir, testname), debug_info_args, ["all"], 151 self.getArchCFlags(architecture), self.getArchSpec(architecture), 152 self.getCCSpec(compiler), self.getExtraMakeArgs(), 153 self.getSDKRootSpec(), self.getModuleCacheSpec(), 154 self.getCmdLine(dictionary)] 155 command = list(itertools.chain(*command_parts)) 156 157 self.runBuildCommands([command]) 158 return True 159 160 def cleanup(self, dictionary=None): 161 """Perform a platform-specific cleanup after the test.""" 162 return True 163