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 ( 51 lldb_test 52 and configuration.test_build_dir 53 and test_subdir 54 and test_name 55 and (not os.path.isabs(test_subdir)) 56 ): 57 raise Exception("Could not derive test directories") 58 build_dir = os.path.join(configuration.test_build_dir, test_subdir, test_name) 59 src_dir = os.path.join(configuration.test_src_root, test_subdir) 60 # This is a bit of a hack to make inline testcases work. 61 makefile = os.path.join(src_dir, "Makefile") 62 if not os.path.isfile(makefile): 63 makefile = os.path.join(build_dir, "Makefile") 64 return [ 65 make, 66 "VPATH=" + src_dir, 67 "-C", 68 build_dir, 69 "-I", 70 src_dir, 71 "-I", 72 os.path.join(lldb_test, "make"), 73 "-f", 74 makefile, 75 ] 76 77 def getCmdLine(self, d): 78 """ 79 Helper function to return a command line argument string used for the 80 make system. 81 """ 82 83 # If d is None or an empty mapping, just return an empty list. 84 if not d: 85 return [] 86 87 def setOrAppendVariable(k, v): 88 append_vars = ["CFLAGS", "CFLAGS_EXTRAS", "LD_EXTRAS"] 89 if k in append_vars and k in os.environ: 90 v = os.environ[k] + " " + v 91 return "%s=%s" % (k, v) 92 93 cmdline = [setOrAppendVariable(k, v) for k, v in list(d.items())] 94 95 return cmdline 96 97 def getArchSpec(self, architecture): 98 """ 99 Helper function to return the key-value string to specify the architecture 100 used for the make system. 101 """ 102 return ["ARCH=" + architecture] if architecture else [] 103 104 def getCCSpec(self, compiler): 105 """ 106 Helper function to return the key-value string to specify the compiler 107 used for the make system. 108 """ 109 cc = compiler if compiler else None 110 if not cc and configuration.compiler: 111 cc = configuration.compiler 112 if cc: 113 return ['CC="%s"' % cc] 114 return [] 115 116 def getSDKRootSpec(self): 117 """ 118 Helper function to return the key-value string to specify the SDK root 119 used for the make system. 120 """ 121 if configuration.sdkroot: 122 return ["SDKROOT={}".format(configuration.sdkroot)] 123 return [] 124 125 def getModuleCacheSpec(self): 126 """ 127 Helper function to return the key-value string to specify the clang 128 module cache used for the make system. 129 """ 130 if configuration.clang_module_cache_dir: 131 return [ 132 "CLANG_MODULE_CACHE_DIR={}".format(configuration.clang_module_cache_dir) 133 ] 134 return [] 135 136 def getLibCxxArgs(self): 137 if configuration.libcxx_include_dir and configuration.libcxx_library_dir: 138 libcpp_args = [ 139 "LIBCPP_INCLUDE_DIR={}".format(configuration.libcxx_include_dir), 140 "LIBCPP_LIBRARY_DIR={}".format(configuration.libcxx_library_dir), 141 ] 142 if configuration.libcxx_include_target_dir: 143 libcpp_args.append( 144 "LIBCPP_INCLUDE_TARGET_DIR={}".format( 145 configuration.libcxx_include_target_dir 146 ) 147 ) 148 return libcpp_args 149 return [] 150 151 def _getDebugInfoArgs(self, debug_info): 152 if debug_info is None: 153 return [] 154 if debug_info == "dwarf": 155 return ["MAKE_DSYM=NO"] 156 if debug_info == "dwo": 157 return ["MAKE_DSYM=NO", "MAKE_DWO=YES"] 158 if debug_info == "gmodules": 159 return ["MAKE_DSYM=NO", "MAKE_GMODULES=YES"] 160 return None 161 162 def getBuildCommand( 163 self, 164 debug_info, 165 architecture=None, 166 compiler=None, 167 dictionary=None, 168 testdir=None, 169 testname=None, 170 make_targets=None, 171 ): 172 debug_info_args = self._getDebugInfoArgs(debug_info) 173 if debug_info_args is None: 174 return None 175 if make_targets is None: 176 make_targets = ["all"] 177 command_parts = [ 178 self.getMake(testdir, testname), 179 debug_info_args, 180 make_targets, 181 self.getArchCFlags(architecture), 182 self.getArchSpec(architecture), 183 self.getCCSpec(compiler), 184 self.getExtraMakeArgs(), 185 self.getSDKRootSpec(), 186 self.getModuleCacheSpec(), 187 self.getLibCxxArgs(), 188 self.getCmdLine(dictionary), 189 ] 190 command = list(itertools.chain(*command_parts)) 191 192 return command 193 194 def cleanup(self, dictionary=None): 195 """Perform a platform-specific cleanup after the test.""" 196 return True 197