misc: Update #!env calls for python to explicit version
[gem5.git] / util / compile
1 #!/usr/bin/env python2
2 # Copyright (c) 2006 The Regents of The University of Michigan
3 # All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
7 # met: redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer;
9 # redistributions in binary form must reproduce the above copyright
10 # notice, this list of conditions and the following disclaimer in the
11 # documentation and/or other materials provided with the distribution;
12 # neither the name of the copyright holders nor the names of its
13 # contributors may be used to endorse or promote products derived from
14 # this software without specific prior written permission.
15 #
16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #
28 # Authors: Nathan Binkert
29
30 import os, re, sys
31 from os.path import isdir, isfile, join as joinpath
32
33 homedir = os.environ['HOME']
34
35 def do_compile():
36 #
37 # Find SCons
38 #
39 search_dirs = [ joinpath(homedir, 'local/lib'), '/opt/local/lib',
40 '/usr/local/lib', '/usr/lib' ]
41
42 if os.environ.has_key("SCONS_LIB_DIR"):
43 search_dirs.append(os.environ["SCONS_LIB_DIR"])
44
45 local = re.compile(r'^scons-local-([0-9]*)\.([0-9]*)\.([0-9]*)$')
46 standard = re.compile(r'^scons-([0-9]*)\.([0-9]*)\.([0-9]*)$')
47
48 scons_dirs = []
49 for dir in search_dirs:
50 if not isdir(dir):
51 continue
52
53 entries = os.listdir(dir)
54 for entry in entries:
55 if not entry.startswith('scons'):
56 continue
57
58 version = (0,0,0)
59 path = joinpath(dir, entry)
60
61 match = local.search(entry)
62 if not match:
63 match = standard.search(entry)
64
65 if match:
66 version = match.group(1), match.group(2), match.group(3)
67
68 scons_dirs.append((version, path))
69
70 scons_dirs.sort()
71 scons_dirs.reverse()
72
73 if not scons_dirs:
74 print >>sys.stderr, \
75 "could not find scons in the following dirs: %s" % search_dirs
76 sys.exit(1)
77
78 sys.path = [ scons_dirs[0][1] ] + sys.path
79
80 # invoke SCons
81 import SCons.Script
82 SCons.Script.main()
83
84 #
85 # do argument parsing
86 #
87 progname = sys.argv[0]
88
89 import optparse
90
91 usage = '''%prog [compile options] <version> [SCons options]
92
93 %prog assumes that the user has a directory called ~/m5/<version> where
94 the source tree resides, and a directory called ~/build, where %prog
95 will create ~/build/<version> if it does not exist and build the resulting
96 simulators there.
97
98 If ~/build is set up in such a way that it points to a local disk on
99 each host, compiles will be very efficient. For example:
100 ~/build -> /z/<username>/.build (Assuming that /z is a local disk and
101 not NFS mounted, whereas your home directory is NFS mounted).
102 '''
103 version = '%prog 0.1'
104 parser = optparse.OptionParser(usage=usage, version=version,
105 formatter=optparse.TitledHelpFormatter())
106 parser.disable_interspersed_args()
107
108 # current option group
109 group = None
110
111 def set_group(*args, **kwargs):
112 '''set the current option group'''
113 global group
114 if not args and not kwargs:
115 group = None
116 else:
117 group = parser.add_option_group(*args, **kwargs)
118
119 def add_option(*args, **kwargs):
120 if group:
121 return group.add_option(*args, **kwargs)
122 else:
123 return parser.add_option(*args, **kwargs)
124
125 def bool_option(name, default, help):
126 '''add a boolean option called --name and --no-name.
127 Display help depending on which is the default'''
128
129 tname = '--%s' % name
130 fname = '--no-%s' % name
131 dest = name.replace('-', '_')
132 if default:
133 thelp = optparse.SUPPRESS_HELP
134 fhelp = help
135 else:
136 thelp = help
137 fhelp = optparse.SUPPRESS_HELP
138
139 add_option(tname, action="store_true", default=default, help=thelp)
140 add_option(fname, action="store_false", dest=dest, help=fhelp)
141
142 add_option('-n', '--no-compile', default=False, action='store_true',
143 help="don't actually compile, just echo SCons command line")
144 add_option('--everything', default=False, action='store_true',
145 help="compile everything that can be compiled")
146 add_option('-E', "--experimental", action='store_true', default=False,
147 help="enable experimental builds")
148 add_option('-v', "--verbose", default=False, action='store_true',
149 help="be verbose")
150
151 set_group("Output binary types")
152 bool_option("debug", default=False, help="compile debug binaries")
153 bool_option("opt", default=False, help="compile opt binaries")
154 bool_option("fast", default=False, help="compile fast binaries")
155 bool_option("prof", default=False, help="compile profile binaries")
156 add_option('-a', "--all-bin", default=False, action='store_true',
157 help="compile debug, opt, and fast binaries")
158
159 set_group("ISA options")
160 bool_option("alpha", default=False, help="compile Alpha")
161 bool_option("mips", default=False, help="compile MIPS")
162 bool_option("sparc", default=False, help="compile SPARC")
163 add_option('-i', "--all-isa", default=False, action='store_true',
164 help="compile all ISAs")
165
166 set_group("Emulation options")
167 bool_option("syscall", default=True,
168 help="Do not compile System Call Emulation mode")
169 bool_option("fullsys", default=True,
170 help="Do not compile Full System mode")
171
172 def usage(exitcode=None):
173 parser.print_help()
174 if exitcode is not None:
175 sys.exit(exitcode)
176
177 (options, args) = parser.parse_args()
178
179 if options.everything:
180 options.all_bin = True
181 options.prof = True
182 options.all_isa = True
183
184 if options.all_bin:
185 options.debug = True
186 options.opt = True
187 options.fast = True
188
189 binaries = []
190 if options.debug:
191 binaries.append('m5.debug')
192 if options.opt:
193 binaries.append('m5.opt')
194 if options.fast:
195 binaries.append('m5.fast')
196 if options.prof:
197 binaries.append('m5.prof')
198
199 if not binaries:
200 binaries.append('m5.debug')
201
202 if options.all_isa:
203 options.alpha = True
204 options.mips = True
205 options.sparc = True
206
207 isas = []
208 if options.alpha:
209 isas.append('alpha')
210 if options.mips:
211 isas.append('mips')
212 if options.sparc:
213 isas.append('sparc')
214
215 if not isas:
216 isas.append('alpha')
217
218 modes = []
219 if options.syscall:
220 modes.append('syscall')
221 if options.fullsys:
222 modes.append('fullsys')
223
224 if not modes:
225 sys.exit("must specify at least one mode")
226
227 #
228 # Convert options into SCons command line arguments
229 #
230
231 # valid combinations of ISA and emulation mode
232 valid = { ('alpha', 'syscall') : 'ALPHA_SE',
233 ('alpha', 'fullsys') : 'ALPHA_FS',
234 ('mips', 'syscall') : 'MIPS_SE',
235 ('sparc', 'syscall') : 'SPARC_SE' }
236
237 # experimental combinations of ISA and emulation mode
238 experiment = { ('mips', 'fullsys') : 'MIPS_FS',
239 ('sparc', 'fullsys') : 'SPARC_FS' }
240
241 if options.experimental:
242 valid.update(experiment)
243
244 builds = []
245 for isa in isas:
246 for mode in modes:
247 try:
248 build = valid[(isa, mode)]
249 builds.append(build)
250 except KeyError:
251 pass
252
253 if not builds:
254 sys.exit("must specify at least one valid combination of ISA and mode")
255
256 if not args:
257 usage(2)
258
259 version = args[0]
260 del args[0]
261
262 for bin in binaries:
263 for build in builds:
264 args.append('%s/%s' % (build, bin))
265
266 #
267 # set up compile
268 #
269 build_base = joinpath(homedir, 'build')
270 m5_base = joinpath(homedir, 'm5')
271
272 if not isdir(build_base):
273 sys.exit('build directory %s not found' % build_base)
274
275 if not isdir(m5_base):
276 sys.exit('m5 base directory %s not found' % m5_base)
277
278 m5_dir = joinpath(m5_base, version)
279 if not isdir(m5_dir):
280 sys.exit('source directory %s not found' % m5_dir)
281
282 # support M5 1.x
283 oldstyle = isfile(joinpath(m5_dir, 'SConscript'))
284 if oldstyle:
285 ext_dir = joinpath(m5_base, 'ext')
286 test_dir = joinpath(m5_base, 'test.' + version)
287
288 if not isdir(ext_dir):
289 sys.exit('ext directory not found at %s' % ext_dir)
290
291 if not isdir(test_dir):
292 sys.exit('test directory not found at %s' % test_dir)
293
294 build_dir = joinpath(build_base, version)
295 if not isdir(build_dir):
296 os.mkdir(build_dir)
297 # need some symlinks for m5 1.x
298 if oldstyle:
299 os.symlink(m5_dir, joinpath(build_dir, 'm5'))
300 os.symlink(ext_dir, joinpath(build_dir, 'ext'))
301 os.symlink(test_dir, joinpath(build_dir, 'test'))
302 os.symlink(joinpath(m5_dir, 'build', 'SConstruct'),
303 joinpath(build_dir, 'SConstruct'))
304 os.symlink(joinpath(m5_dir, 'build', 'default_options'),
305 joinpath(build_dir, 'default_options'))
306
307 sys.argv = [ progname ]
308 if oldstyle:
309 os.chdir(build_dir)
310 sys.argv.extend(args)
311 else:
312 os.chdir(m5_dir)
313 for arg in args:
314 if not arg.startswith('-') and '=' not in arg:
315 arg = joinpath(build_dir, 'build', arg)
316 sys.argv.append(arg)
317
318 if options.no_compile or options.verbose:
319 for arg in sys.argv[1:]:
320 print arg
321
322 if not options.no_compile:
323 do_compile()