compile revision 3855
1247Sstever@eecs.umich.edu#!/usr/bin/env python
22783Sktlim@umich.edu# Copyright (c) 2006 The Regents of The University of Michigan
3247Sstever@eecs.umich.edu# All rights reserved.
4247Sstever@eecs.umich.edu#
5247Sstever@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
6247Sstever@eecs.umich.edu# modification, are permitted provided that the following conditions are
7247Sstever@eecs.umich.edu# met: redistributions of source code must retain the above copyright
8247Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
9247Sstever@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
10247Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
11247Sstever@eecs.umich.edu# documentation and/or other materials provided with the distribution;
12247Sstever@eecs.umich.edu# neither the name of the copyright holders nor the names of its
13247Sstever@eecs.umich.edu# contributors may be used to endorse or promote products derived from
14247Sstever@eecs.umich.edu# this software without specific prior written permission.
15247Sstever@eecs.umich.edu#
16247Sstever@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17247Sstever@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18247Sstever@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19247Sstever@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20247Sstever@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21247Sstever@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22247Sstever@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23247Sstever@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24247Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25247Sstever@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26247Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27247Sstever@eecs.umich.edu#
28247Sstever@eecs.umich.edu# Authors: Nathan Binkert
29247Sstever@eecs.umich.edu
301123Sstever@eecs.umich.eduimport os, re, sys
311123Sstever@eecs.umich.edufrom os.path import isdir, isfile, join as joinpath
321123Sstever@eecs.umich.edu
331746Shsul@eecs.umich.eduhomedir = os.environ['HOME']
341746Shsul@eecs.umich.edu
351123Sstever@eecs.umich.edudef do_compile():
363362Sstever@eecs.umich.edu    #
373362Sstever@eecs.umich.edu    # Find SCons
383362Sstever@eecs.umich.edu    #
393362Sstever@eecs.umich.edu    search_dirs = [ joinpath(homedir, 'local/lib'), '/opt/local/lib',
403362Sstever@eecs.umich.edu                    '/usr/local/lib', '/usr/lib' ]
413362Sstever@eecs.umich.edu
423362Sstever@eecs.umich.edu    if os.environ.has_key("SCONS_LIB_DIR"):
431123Sstever@eecs.umich.edu        search_dirs.append(os.environ["SCONS_LIB_DIR"])
443370Sstever@eecs.umich.edu
453370Sstever@eecs.umich.edu    local = re.compile(r'^scons-local-([0-9]*)\.([0-9]*)\.([0-9]*)$')
463370Sstever@eecs.umich.edu    standard = re.compile(r'^scons-([0-9]*)\.([0-9]*)\.([0-9]*)$')
473370Sstever@eecs.umich.edu
483362Sstever@eecs.umich.edu    scons_dirs = []
493362Sstever@eecs.umich.edu    for dir in search_dirs:
503362Sstever@eecs.umich.edu        if not isdir(dir):
513362Sstever@eecs.umich.edu            continue
523362Sstever@eecs.umich.edu
533362Sstever@eecs.umich.edu        entries = os.listdir(dir)
543362Sstever@eecs.umich.edu        for entry in entries:
553362Sstever@eecs.umich.edu            if not entry.startswith('scons'):
563362Sstever@eecs.umich.edu                continue
573362Sstever@eecs.umich.edu
583362Sstever@eecs.umich.edu            version = (0,0,0)
593362Sstever@eecs.umich.edu            path = joinpath(dir, entry)
603362Sstever@eecs.umich.edu
611123Sstever@eecs.umich.edu            match = local.search(entry)
62247Sstever@eecs.umich.edu            if not match:
63247Sstever@eecs.umich.edu                match = standard.search(entry)
643362Sstever@eecs.umich.edu
653362Sstever@eecs.umich.edu            if match:
663362Sstever@eecs.umich.edu                version = match.group(1), match.group(2), match.group(3)
673362Sstever@eecs.umich.edu
683362Sstever@eecs.umich.edu            scons_dirs.append((version, path))
693362Sstever@eecs.umich.edu
703362Sstever@eecs.umich.edu    scons_dirs.sort()
713362Sstever@eecs.umich.edu    scons_dirs.reverse()
723362Sstever@eecs.umich.edu
733362Sstever@eecs.umich.edu    if not scons_dirs:
743362Sstever@eecs.umich.edu        print >>sys.stderr, \
753362Sstever@eecs.umich.edu              "could not find scons in the following dirs: %s" % search_dirs
76247Sstever@eecs.umich.edu        sys.exit(1)
77247Sstever@eecs.umich.edu
78247Sstever@eecs.umich.edu    sys.path = [ scons_dirs[0][1] ] + sys.path
793362Sstever@eecs.umich.edu
803362Sstever@eecs.umich.edu    # invoke SCons
81247Sstever@eecs.umich.edu    import SCons.Script
823362Sstever@eecs.umich.edu    SCons.Script.main()
833362Sstever@eecs.umich.edu
843362Sstever@eecs.umich.edu#
85247Sstever@eecs.umich.edu# do argument parsing
863370Sstever@eecs.umich.edu#
873370Sstever@eecs.umich.eduprogname = sys.argv[0]
883370Sstever@eecs.umich.edu
893370Sstever@eecs.umich.eduimport optparse
903370Sstever@eecs.umich.edu
913370Sstever@eecs.umich.eduusage = '''%prog [compile options] <version> [SCons options]
923370Sstever@eecs.umich.edu
933370Sstever@eecs.umich.edu%prog assumes that the user has a directory called ~/m5/<version> where
941442Sstever@eecs.umich.eduthe source tree resides, and a directory called ~/build, where %prog
951442Sstever@eecs.umich.eduwill create ~/build/<version> if it does not exist and build the resulting
961442Sstever@eecs.umich.edusimulators there.
971442Sstever@eecs.umich.edu
981442Sstever@eecs.umich.eduIf ~/build is set up in such a way that it points to a local disk on
991442Sstever@eecs.umich.edueach host, compiles will be very efficient.  For example:
1001123Sstever@eecs.umich.edu~/build -> /z/<username>/.build  (Assuming that /z is a local disk and
1013362Sstever@eecs.umich.edunot NFS mounted, whereas your home directory is NFS mounted).
1023362Sstever@eecs.umich.edu'''
103247Sstever@eecs.umich.eduversion = '%prog 0.1'
104247Sstever@eecs.umich.eduparser = optparse.OptionParser(usage=usage, version=version,
105247Sstever@eecs.umich.edu                               formatter=optparse.TitledHelpFormatter())
106247Sstever@eecs.umich.eduparser.disable_interspersed_args()
107247Sstever@eecs.umich.edu
108247Sstever@eecs.umich.edu# current option group
109247Sstever@eecs.umich.edugroup = None
110247Sstever@eecs.umich.edu
111247Sstever@eecs.umich.edudef set_group(*args, **kwargs):
112247Sstever@eecs.umich.edu    '''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
119def add_option(*args, **kwargs):
120    if group:
121        return group.add_option(*args, **kwargs)
122    else:
123        return parser.add_option(*args, **kwargs)
124
125def 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
142add_option('-n', '--no-compile', default=False, action='store_true',
143           help="don't actually compile, just echo SCons command line")
144add_option('--everything', default=False, action='store_true',
145           help="compile everything that can be compiled")
146add_option('-E', "--experimental", action='store_true', default=False,
147           help="enable experimental builds")
148add_option('-v', "--verbose", default=False, action='store_true',
149           help="be verbose")
150          
151set_group("Output binary types")
152bool_option("debug", default=False, help="compile debug binaries")
153bool_option("opt", default=False, help="compile opt binaries")
154bool_option("fast", default=False, help="compile fast binaries")
155bool_option("prof", default=False, help="compile profile binaries")
156add_option('-a', "--all-bin", default=False, action='store_true',
157           help="compile debug, opt, and fast binaries")
158
159set_group("ISA options")
160bool_option("alpha", default=False, help="compile Alpha")
161bool_option("mips", default=False, help="compile MIPS")
162bool_option("sparc", default=False, help="compile SPARC")
163add_option('-i', "--all-isa", default=False, action='store_true',
164           help="compile all ISAs")
165
166set_group("Emulation options")
167bool_option("syscall", default=True,
168            help="Do not compile System Call Emulation mode")
169bool_option("fullsys", default=True,
170            help="Do not compile Full System mode")
171
172def 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
179if options.everything:
180    options.all_bin = True
181    options.prof = True
182    options.all_isa = True
183
184if options.all_bin:
185    options.debug = True
186    options.opt = True
187    options.fast = True
188
189binaries = []
190if options.debug:
191    binaries.append('m5.debug')
192if options.opt:
193    binaries.append('m5.opt')
194if options.fast:
195    binaries.append('m5.fast')
196if options.prof:
197    binaries.append('m5.prof')
198
199if not binaries:
200    binaries.append('m5.debug')
201
202if options.all_isa:
203    options.alpha = True
204    options.mips = True
205    options.sparc = True
206
207isas = []
208if options.alpha:
209    isas.append('alpha')
210if options.mips:
211    isas.append('mips')
212if options.sparc:
213    isas.append('sparc')
214
215if not isas:
216    isas.append('alpha')
217
218modes = []
219if options.syscall:
220    modes.append('syscall')
221if options.fullsys:
222    modes.append('fullsys')
223
224if 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
232valid = { ('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
238experiment = { ('mips', 'fullsys') : 'MIPS_FS',
239               ('sparc', 'fullsys') : 'SPARC_FS' }
240
241if options.experimental:
242    valid.update(experiment)
243
244builds = []
245for 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
253if not builds:
254    sys.exit("must specify at least one valid combination of ISA and mode")
255
256if not args:
257    usage(2)
258
259version = args[0]
260del args[0]
261
262for bin in binaries:
263    for build in builds:
264        args.append('%s/%s' % (build, bin))
265
266#
267# set up compile
268#
269build_base = joinpath(homedir, 'build')
270m5_base = joinpath(homedir, 'm5')
271
272if not isdir(build_base):
273    sys.exit('build directory %s not found' % build_base)
274
275if not isdir(m5_base):
276    sys.exit('m5 base directory %s not found' % m5_base)
277
278m5_dir = joinpath(m5_base, version)
279if not isdir(m5_dir):
280    sys.exit('source directory %s not found' % m5_dir)
281
282# support M5 1.x
283oldstyle = isfile(joinpath(m5_dir, 'SConscript'))
284if 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
294build_dir = joinpath(build_base, version)
295if 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
307sys.argv = [ progname ]
308if oldstyle:
309    os.chdir(build_dir)
310    sys.argv.extend(args)
311else:
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
318if options.no_compile or options.verbose:
319    for arg in sys.argv[1:]:
320        print arg
321
322if not options.no_compile:
323    do_compile()
324