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 _getDebugInfoArgs(self, debug_info): 131 if debug_info is None: 132 return [] 133 if debug_info == "dwarf": 134 return ["MAKE_DSYM=NO"] 135 if debug_info == "dwo": 136 return ["MAKE_DSYM=NO", "MAKE_DWO=YES"] 137 if debug_info == "gmodules": 138 return ["MAKE_DSYM=NO", "MAKE_GMODULES=YES"] 139 return None 140 141 def build(self, debug_info, sender=None, architecture=None, compiler=None, 142 dictionary=None, testdir=None, testname=None): 143 debug_info_args = self._getDebugInfoArgs(debug_info) 144 if debug_info_args is None: 145 return False 146 147 commands = [] 148 commands.append( 149 self.getMake(testdir, testname) + debug_info_args + [ 150 "all", 151 self.getArchCFlags(architecture), 152 self.getArchSpec(architecture), 153 self.getCCSpec(compiler), 154 self.getExtraMakeArgs(), 155 self.getSDKRootSpec(), 156 self.getModuleCacheSpec(), 157 self.getCmdLine(dictionary) 158 ]) 159 160 self.runBuildCommands(commands, sender=sender) 161 return True 162 163 def cleanup(self, sender=None, dictionary=None): 164 """Perform a platform-specific cleanup after the test.""" 165 return True 166