harness: machines: define custom buildall targets for armv7/armv8 machines
[barrelfish] / tools / harness / builds.py
1 ##########################################################################
2 # Copyright (c) 2009, 2010, 2011, ETH Zurich.
3 # All rights reserved.
4 #
5 # This file is distributed under the terms in the attached LICENSE file.
6 # If you do not find this file, copies can be found by writing to:
7 # ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
8 ##########################################################################
9
10 import os, errno, re
11 import siteconfig
12 import debug
13
14 MPSS_LINUX_PATH=':/opt/mpss/3.7.1/sysroots/x86_64-mpsssdk-linux/usr/bin:/opt/mpss/3.7.1/sysroots/x86_64-mpsssdk-linux/usr/bin/k1om-mpss-linux'
15
16
17 class Build(object):
18     name = None # should be overriden by a subclass
19
20     def __init__(self, options):
21         self.build_dir = None
22         self.options = options
23
24     def _make_build_dir(self, build_dir=None):
25         if build_dir is None:
26             build_dir = os.path.join(self.options.buildbase, self.name.lower())
27         self.build_dir = build_dir
28         debug.verbose('creating build directory %s' % build_dir)
29         try:
30             os.makedirs(build_dir)
31         except OSError, e:
32             if e.errno == errno.EEXIST:
33                 debug.log("reusing existing build in directory %s" % build_dir)
34             else:
35                 raise
36
37     def configure(self, checkout):
38         raise NotImplementedError
39
40     def build(self, targets):
41         raise NotImplementedError
42
43     def install(self, targets, path):
44         """install to the given path"""
45         raise NotImplementedError
46
47
48 class HakeBuildBase(Build):
49     def _run_hake(self, srcdir, archs):
50         # if srcdir is relative, adjust to be wrt build_dir
51         print archs
52         if not os.path.isabs(srcdir):
53             srcdir = os.path.relpath(srcdir, self.build_dir)
54         debug.checkcmd([os.path.join(srcdir, "hake", "hake.sh"), "--source-dir", srcdir],
55                        cwd=self.build_dir)
56
57     def _get_hake_conf(self, srcdir, archs):
58         default_config = {
59             "source_dir": "\"%s\"" % srcdir,
60             "architectures": "[" + ", ".join("\"%s\"" % a for a in archs) + "]",
61             "install_dir": "\".\"",
62             "toolroot": "Nothing",
63             "arm_toolspec": "Nothing",
64             "aarch64_toolspec": "Nothing",
65             "thumb_toolspec": "Nothing",
66             "armeb_toolspec": "Nothing",
67             "x86_toolspec": "Nothing",
68             "k1om_toolspec": "Nothing",
69             "cache_dir": "\"%s\"" % os.path.expanduser("~/.cache/barrelfish/"),
70             "hagfish_location" : "\"%s\"" % siteconfig.get('HAGFISH_LOCATION')
71         }
72         return default_config
73
74     def _write_hake_conf(self, srcdir, archs):
75         # create hake dir
76         hakedir = os.path.join(self.build_dir, 'hake')
77         if not os.path.isdir(hakedir):
78             os.mkdir(hakedir)
79
80         # read default config template
81         with open(os.path.join(srcdir, 'hake', 'Config.hs.template')) as fh:
82             conf_template = fh.readlines()
83
84         # if srcdir is relative, adjust to be wrt build_dir
85         if os.path.isabs(srcdir):
86             rel_srcdir = srcdir
87         else:
88             rel_srcdir = os.path.relpath(srcdir, self.build_dir)
89
90         # get custom configuration options as a dictionary
91         conf = self._get_hake_conf(rel_srcdir, archs)
92
93         # create a new config file: template and then local options
94         newconf = []
95         for line in conf_template:
96             # XXX: exclude options from the defaults that are set locally
97             # where is the haskell parsing library for python? :)
98             if any([line.startswith(k) and re.match(' +=', line[len(k):])
99                         for k in conf.keys()]):
100                 line = '-- ' + line
101             newconf.append(line)
102         newconf.extend(['\n', '\n', '-- Added by test harness:\n'])
103         for item in conf.items():
104             newconf.append("%s = %s\n" % item)
105
106         # write it, only if it's different or the old one doesn't exist
107         try:
108             with open(os.path.join(hakedir, 'Config.hs'), 'r') as fh:
109                 if fh.readlines() == newconf:
110                     return # identical files
111         except IOError:
112             pass
113
114         with open(os.path.join(hakedir, 'Config.hs'), 'w') as fh:
115             fh.writelines(newconf)
116
117     def configure(self, checkout, archs):
118         srcdir = checkout.get_base_dir()
119         environ = dict(os.environ)
120         if "k1om" in archs :
121             environ['PATH'] = environ['PATH'] + MPSS_LINUX_PATH
122         self._make_build_dir()
123         self._write_hake_conf(srcdir, archs)
124         self._run_hake(srcdir, archs)
125
126         # this should be a nop -- building it here causes us to stop early
127         # with any tool or dependency-generation errors before doing test setup
128         self.build(["Makefile"], env=environ)
129
130     @staticmethod
131     def split_env(e):
132         def split_reduce_env(state, c):
133             if not state[0] and c == '\\':
134                 return True, state[1]
135             elif not state[0] and c.isspace():
136                 state[1].append('')
137             elif state[0]:
138                 ec = '\\'+c
139                 s = ec.decode('string_escape')
140                 if s == ec:
141                     # decode had no effect, just drop backslash
142                     s = c
143                 state[1][-1] += s
144             else:
145                 state[1][-1] += c
146             return False, state[1]
147
148         e = e.lstrip()
149         e = reduce(split_reduce_env, e, (False, ['']))[1]
150         e = filter(bool, e)
151         return e
152
153     def build(self, targets, **kwargs):
154         makeopts = self.split_env(os.environ.get('MAKEOPTS', ''))
155         debug.checkcmd(["make"] + makeopts + targets, cwd=self.build_dir, **kwargs)
156
157     def install(self, targets, path):
158         debug.checkcmd(["make", "install",
159                                "INSTALL_PREFIX=%s" % path,
160                                "MODULES=%s" % (" ".join(targets))],
161                        cwd=self.build_dir)
162
163
164 class HakeReleaseBuild(HakeBuildBase):
165     """Release build (optimisations, no debug information)"""
166     name = 'release'
167
168     def _get_hake_conf(self, *args):
169         conf = super(HakeReleaseBuild, self)._get_hake_conf(*args)
170         conf["cOptFlags"] = "[\"-O2\", \"-DNDEBUG\", \"-Wno-unused-variable\"]"
171         return conf
172
173 class HakeTestBuild(HakeBuildBase):
174     """Test build (optimisations, no debug symbols, but assertions enabled)"""
175     name = 'test'
176
177     def _get_hake_conf(self, *args):
178         conf = super(HakeTestBuild, self)._get_hake_conf(*args)
179         conf["cOptFlags"] = "[\"-O2\"]"
180         return conf
181
182 class HakeReleaseTraceBuild(HakeBuildBase):
183     """optimisations, no debug information, and tracing """
184     name = 'release_trace'
185
186     def _get_hake_conf(self, *args):
187         conf = super(HakeReleaseBuild, self)._get_hake_conf(*args)
188         conf["cOptFlags"] = "[\"-O2\", \"-DNDEBUG\"]"
189         conf["trace"] = "True"
190         return conf
191
192 class HakeTestMdbInvariantsBuild(HakeTestBuild):
193     """optimisations, no debug symbols, assertions and MDB invariant checking enabled"""
194     name = 'test_mdbinvariants'
195
196     def _get_hake_conf(self, *args):
197         conf = super(HakeTestMdbInvariantsBuild, self)._get_hake_conf(*args)
198         conf["mdb_check_invariants"] = "True"
199         return conf
200
201 class HakeDebugBuild(HakeBuildBase):
202     """Default Hake build: debug symbols, optimisations, assertions"""
203     name = 'debug'
204
205     def _get_hake_conf(self, *args):
206         conf = super(HakeDebugBuild, self)._get_hake_conf(*args)
207         conf["cOptFlags"] = "[\"-O2\", \"-g\"]"
208         return conf
209
210 class HakeDebugTraceBuild(HakeBuildBase):
211     """debug symbols, optimisations, assertions, and tracing"""
212     name = 'debug_trace'
213
214     def _get_hake_conf(self, *args):
215         conf = super(HakeDebugTraceBuild, self)._get_hake_conf(*args)
216         conf["cOptFlags"] = "[\"-O2\"]"
217         conf["trace"] = "True"
218         return conf
219
220
221 all_builds = [HakeReleaseBuild, HakeTestBuild, HakeDebugBuild, HakeReleaseTraceBuild,
222               HakeTestMdbInvariantsBuild, HakeDebugTraceBuild]
223
224
225 class ExistingBuild(HakeBuildBase):
226     '''Dummy build class for an existing Hake build dir.'''
227     name = 'existing'
228
229     def __init__(self, options, build_dir):
230         super(ExistingBuild, self).__init__(options)
231         debug.verbose('using existing build directory %s' % build_dir)
232         self.build_dir = build_dir
233
234     def configure(self, *args):
235         pass
236
237
238 def existingbuild(*args):
239     """construct the build class for an existing build"""
240     return ExistingBuild(*args)