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 getExtraMakeArgs(self): 25 """ 26 Helper function to return extra argumentsfor the make system. This 27 method is meant to be overridden by platform specific builders. 28 """ 29 return [] 30 31 def getArchCFlags(self, architecture): 32 """Returns the ARCH_CFLAGS for the make system.""" 33 return [] 34 35 def getMake(self, test_subdir, test_name): 36 """Returns the invocation for GNU make. 37 The first argument is a tuple of the relative path to the testcase 38 and its filename stem.""" 39 if platform.system() == "FreeBSD" or platform.system() == "NetBSD": 40 make = "gmake" 41 else: 42 make = "make" 43 44 # Construct the base make invocation. 45 lldb_test = os.environ["LLDB_TEST"] 46 if not (lldb_test and configuration.test_build_dir and test_subdir 47 and test_name and (not os.path.isabs(test_subdir))): 48 raise Exception("Could not derive test directories") 49 build_dir = os.path.join(configuration.test_build_dir, test_subdir, 50 test_name) 51 src_dir = os.path.join(configuration.test_src_root, test_subdir) 52 # This is a bit of a hack to make inline testcases work. 53 makefile = os.path.join(src_dir, "Makefile") 54 if not os.path.isfile(makefile): 55 makefile = os.path.join(build_dir, "Makefile") 56 return [ 57 make, "VPATH=" + src_dir, "-C", build_dir, "-I", src_dir, "-I", 58 os.path.join(lldb_test, "make"), "-f", makefile 59 ] 60 61 def getCmdLine(self, d): 62 """ 63 Helper function to return a command line argument string used for the 64 make system. 65 """ 66 67 # If d is None or an empty mapping, just return an empty list. 68 if not d: 69 return [] 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 '%s=%s' % (k, v) 76 77 cmdline = [setOrAppendVariable(k, v) for k, v in list(d.items())] 78 79 return cmdline 80 81 def runBuildCommands(self, commands): 82 try: 83 lldbtest.system(commands) 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 return ["ARCH=" + architecture] if architecture else [] 96 97 def getCCSpec(self, compiler): 98 """ 99 Helper function to return the key-value string to specify the compiler 100 used for the make system. 101 """ 102 cc = compiler if compiler else None 103 if not cc and configuration.compiler: 104 cc = configuration.compiler 105 if cc: 106 return ["CC=\"%s\"" % cc] 107 return [] 108 109 def getSDKRootSpec(self): 110 """ 111 Helper function to return the key-value string to specify the SDK root 112 used for the make system. 113 """ 114 if configuration.sdkroot: 115 return ["SDKROOT={}".format(configuration.sdkroot)] 116 return [] 117 118 def getModuleCacheSpec(self): 119 """ 120 Helper function to return the key-value string to specify the clang 121 module cache used for the make system. 122 """ 123 if configuration.clang_module_cache_dir: 124 return ["CLANG_MODULE_CACHE_DIR={}".format( 125 configuration.clang_module_cache_dir)] 126 return [] 127 128 def _getDebugInfoArgs(self, debug_info): 129 if debug_info is None: 130 return [] 131 if debug_info == "dwarf": 132 return ["MAKE_DSYM=NO"] 133 if debug_info == "dwo": 134 return ["MAKE_DSYM=NO", "MAKE_DWO=YES"] 135 if debug_info == "gmodules": 136 return ["MAKE_DSYM=NO", "MAKE_GMODULES=YES"] 137 return None 138 139 def build(self, debug_info, architecture=None, compiler=None, 140 dictionary=None, testdir=None, testname=None): 141 debug_info_args = self._getDebugInfoArgs(debug_info) 142 if debug_info_args is None: 143 return False 144 145 command_parts = [ 146 self.getMake(testdir, testname), debug_info_args, ["all"], 147 self.getArchCFlags(architecture), self.getArchSpec(architecture), 148 self.getCCSpec(compiler), self.getExtraMakeArgs(), 149 self.getSDKRootSpec(), self.getModuleCacheSpec(), 150 self.getCmdLine(dictionary)] 151 command = list(itertools.chain(*command_parts)) 152 153 self.runBuildCommands([command]) 154 return True 155 156 def cleanup(self, dictionary=None): 157 """Perform a platform-specific cleanup after the test.""" 158 return True 159