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 10import os, errno, re 11import siteconfig 12import debug 13 14MPSS_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 17class 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 48class 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 164class 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 173class 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 182class 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 192class 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 201class 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 210class 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 221all_builds = [HakeReleaseBuild, HakeTestBuild, HakeDebugBuild, HakeReleaseTraceBuild, 222 HakeTestMdbInvariantsBuild, HakeDebugTraceBuild] 223 224 225class 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 238def existingbuild(*args): 239 """construct the build class for an existing build""" 240 return ExistingBuild(*args) 241