da5b040de86cd89b1d40e5257e248e05cbe1cb38
[lldb.git] / lldb / packages / Python / lldbsuite / test / builders / builder.py
1 import os
2 import platform
3 import subprocess
4 import sys
5
6 import lldbsuite.test.lldbtest as lldbtest
7 import lldbsuite.test.lldbutil as lldbutil
8 from lldbsuite.test import configuration
9 from lldbsuite.test_event import build_exception
10
11
12 class 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 buildDTS(self,
242                  sender=None,
243                  architecture=None,
244                  compiler=None,
245                  dictionary=None,
246                  testdir=None,
247                  testname=None):
248         """Build the binaries with DTS - a DWARF optimization tool."""
249         commands = []
250         commands.append(
251             self.getMake(testdir, testname) + [
252                 "MAKE_DSYM=NO", "DTS=YES",
253                 self.getArchCFlags(architecture),
254                 self.getArchSpec(architecture),
255                 self.getCCSpec(compiler),
256                 self.getExtraMakeArgs(),
257                 self.getSDKRootSpec(),
258                 self.getModuleCacheSpec(),
259                 self.getCmdLine(dictionary)
260             ])
261
262         self.runBuildCommands(commands, sender=sender)
263         # True signifies that we can handle building with DTS.
264         return True
265
266     def buildDWZ(self,
267                  sender=None,
268                  architecture=None,
269                  compiler=None,
270                  dictionary=None,
271                  testdir=None,
272                  testname=None):
273         """Build the binaries with DWZ - a DWARF optimization tool."""
274         commands = []
275         commands.append(
276             self.getMake(testdir, testname) + [
277                 "MAKE_DSYM=NO", "DWZ=YES",
278                 self.getArchCFlags(architecture),
279                 self.getArchSpec(architecture),
280                 self.getCCSpec(compiler),
281                 self.getExtraMakeArgs(),
282                 self.getSDKRootSpec(),
283                 self.getModuleCacheSpec(),
284                 self.getCmdLine(dictionary)
285             ])
286
287         self.runBuildCommands(commands, sender=sender)
288         # True signifies that we can handle building with DWZ.
289         return True
290
291     def cleanup(self, sender=None, dictionary=None):
292         """Perform a platform-specific cleanup after the test."""
293         return True