From 0337db3388db335ea23f02f3aa00bca9d483ef1c Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Tue, 30 May 2006 13:11:34 -0400 Subject: Link in Python interpreter. Use embedded zip archive to carry Python code instead of homegrown embedded string/file mechanism. Do argument parsing in Python instead of C++. SConstruct: Add Python interpreter include path & library. Define two new simple builders which copy & concatenate files, respectively, for use by the Python embedded zipfile code. src/SConscript: Encapsulate environment creation in a function. Add code to append Python zip archive to final executable. Eliminate references to obsolete files. src/python/SConscript: Rewrite to generate embedded zip archive of Python code (replacing old "embedded string" mechanism). src/python/m5/__init__.py: Move main arg-parsing loop here (out of C++ main()). src/python/m5/config.py: Minor fix (version incompatibility?). src/sim/main.cc: Invoke embedded Python interpreter to parse args and generate config.ini, replacing C++ arg parsing code. --HG-- extra : convert_revision : 72d21236b2bee139ff39ba4cf031a4a1f8560029 --- src/python/SConscript | 226 +++++++++++++--------------------------------- src/python/m5/__init__.py | 108 +++++++++++++++++++++- src/python/m5/config.py | 2 +- 3 files changed, 169 insertions(+), 167 deletions(-) (limited to 'src/python') diff --git a/src/python/SConscript b/src/python/SConscript index 4407e403d..1f2d7fe0e 100644 --- a/src/python/SConscript +++ b/src/python/SConscript @@ -27,126 +27,55 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import os, os.path, re, sys +from zipfile import PyZipFile -Import('env') +# handy function for path joins +def join(*args): + return os.path.normpath(os.path.join(*args)) -import scons_helper - -def WriteEmbeddedPyFile(target, source, path, name, ext, filename): - if isinstance(source, str): - source = file(source, 'r') - - if isinstance(target, str): - target = file(target, 'w') - - print >>target, "AddModule(%s, %s, %s, %s, '''\\" % \ - (`path`, `name`, `ext`, `filename`) - - for line in source: - line = line - # escape existing backslashes - line = line.replace('\\', '\\\\') - # escape existing triple quotes - line = line.replace("'''", r"\'\'\'") - - print >>target, line, - - print >>target, "''')" - print >>target - -def WriteCFile(target, source, name): - if isinstance(source, str): - source = file(source, 'r') - - if isinstance(target, str): - target = file(target, 'w') - - print >>target, 'const char %s_string[] = {' % name - - count = 0 - from array import array - try: - while True: - foo = array('B') - foo.fromfile(source, 10000) - l = [ str(i) for i in foo.tolist() ] - count += len(l) - for i in xrange(0,9999,20): - print >>target, ','.join(l[i:i+20]) + ',' - except EOFError: - l = [ str(i) for i in foo.tolist() ] - count += len(l) - for i in xrange(0,len(l),20): - print >>target, ','.join(l[i:i+20]) + ',' - print >>target, ','.join(l[i:]) + ',' - - print >>target, '};' - print >>target, 'const int %s_length = %d;' % (name, count) - print >>target - -def splitpath(path): - dir,file = os.path.split(path) - path = [] - assert(file) - while dir: - dir,base = os.path.split(dir) - path.insert(0, base) - return path, file - -def MakeEmbeddedPyFile(target, source, env): - target = file(str(target[0]), 'w') - - tree = {} - for src in source: - src = str(src) - path,pyfile = splitpath(src) - node = tree - for dir in path: - if not node.has_key(dir): - node[dir] = { } - node = node[dir] - - name,ext = pyfile.split('.') - if name == '__init__': - node['.hasinit'] = True - node[pyfile] = (src,name,ext,src) - - done = False - while not done: - done = True - for name,entry in tree.items(): - if not isinstance(entry, dict): continue - if entry.has_key('.hasinit'): continue - - done = False - del tree[name] - for key,val in entry.iteritems(): - if tree.has_key(key): - raise NameError, \ - "dir already has %s can't add it again" % key - tree[key] = val - - files = [] - def populate(node, path = []): - names = node.keys() - names.sort() - for name in names: - if name == '.hasinit': - continue - - entry = node[name] - if isinstance(entry, dict): - if not entry.has_key('.hasinit'): - raise NameError, 'package directory missing __init__.py' - populate(entry, path + [ name ]) - else: - pyfile,name,ext,filename = entry - files.append((pyfile, path, name, ext, filename)) - populate(tree) - - for pyfile, path, name, ext, filename in files: - WriteEmbeddedPyFile(target, pyfile, path, name, ext, filename) +Import('env') +# This SConscript is in charge of collecting .py files and generating a zip archive that is appended to the m5 binary. + +# Copy .py source files here (relative to src/python in the build +# directory). +pyzip_root = 'zip' + +# List of files & directories to include in the zip file. To include +# a package, list only the root directory of the package, not any +# internal .py files (else they will get the path stripped off when +# they are imported into the zip file). +pyzip_files = [] + +# List of additional files on which the zip archive depends, but which +# are not included in pyzip_files... i.e. individual .py files within +# a package. +pyzip_dep_files = [] + +# Add the specified package to the zip archive. Adds the directory to +# pyzip_files and all included .py files to pyzip_dep_files. +def addPkg(pkgdir): + pyzip_files.append(join(pyzip_root, pkgdir)) + origdir = os.getcwd() + srcdir = join(Dir('.').srcnode().abspath, pkgdir) + os.chdir(srcdir) + for path, dirs, files in os.walk('.'): + for i,dir in enumerate(dirs): + if dir == 'SCCS': + del dirs[i] + break + + for f in files: + if f.endswith('.py'): + source = join(pkgdir, path, f) + target = join(pyzip_root, source) + pyzip_dep_files.append(target) + env.CopyFile(target, source) + + os.chdir(origdir) + +# Generate Python file that contains a dict specifying the current +# build_env flags. def MakeDefinesPyFile(target, source, env): f = file(str(target[0]), 'w') print >>f, "import __main__" @@ -154,54 +83,21 @@ def MakeDefinesPyFile(target, source, env): print >>f, source[0] f.close() -CFileCounter = 0 -def MakePythonCFile(target, source, env): - global CFileCounter - target = file(str(target[0]), 'w') - - print >>target, '''\ -#include "base/embedfile.hh" - -namespace { -''' - for src in source: - src = str(src) - fname = os.path.basename(src) - name = 'embedded_file%d' % CFileCounter - CFileCounter += 1 - WriteCFile(target, src, name) - print >>target, '''\ -EmbedMap %(name)s("%(fname)s", - %(name)s_string, %(name)s_length); - -''' % locals() - print >>target, '''\ - -/* namespace */ } -''' - -# base list of .py files to embed -embedded_py_files = [ os.path.join(env['ROOT'], 'util/pbs/jobfile.py') ] -# add all .py files in python/m5 -objpath = os.path.join(env['SRCDIR'], 'python', 'm5') -for root, dirs, files in os.walk(objpath, topdown=True): - for i,dir in enumerate(dirs): - if dir == 'SCCS': - del dirs[i] - break - - assert(root.startswith(objpath)) - for f in files: - if f.endswith('.py'): - embedded_py_files.append(os.path.join(root, f)) - -embedfile_hh = os.path.join(env['SRCDIR'], 'base/embedfile.hh') - optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions]) env.Command('defines.py', Value(optionDict), MakeDefinesPyFile) -env.Command('embedded_py.py', embedded_py_files, MakeEmbeddedPyFile) -env.Depends('embedded_py.cc', embedfile_hh) -env.Command('embedded_py.cc', - ['string_importer.py', 'defines.py', 'embedded_py.py'], - MakePythonCFile) +# Now specify the packages & files for the zip archive. +addPkg('m5') +pyzip_files.append('defines.py') +pyzip_files.append(join(env['ROOT'], 'util/pbs/jobfile.py')) + +# Action function to build the zip archive. Uses the PyZipFile module +# included in the standard Python library. +def buildPyZip(target, source, env): + pzf = PyZipFile(str(target[0]), 'w') + for s in source: + pzf.writepy(str(s)) + +# Add the zip file target to the environment. +env.Command('m5py.zip', pyzip_files, buildPyZip) +env.Depends('m5py.zip', pyzip_dep_files) diff --git a/src/python/m5/__init__.py b/src/python/m5/__init__.py index 9bb68a090..06875d1f0 100644 --- a/src/python/m5/__init__.py +++ b/src/python/m5/__init__.py @@ -24,7 +24,53 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import sys, os +import sys, os, time + +import __main__ + +briefCopyright = ''' +Copyright (c) 2001-2006 +The Regents of The University of Michigan +All Rights Reserved +''' + +fullCopyright = ''' +Copyright (c) 2001-2006 +The Regents of The University of Michigan +All Rights Reserved + +Permission is granted to use, copy, create derivative works and +redistribute this software and such derivative works for any purpose, +so long as the copyright notice above, this grant of permission, and +the disclaimer below appear in all copies made; and so long as the +name of The University of Michigan is not used in any advertising or +publicity pertaining to the use or distribution of this software +without specific, written prior authorization. + +THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE +UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND WITHOUT +WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER EXPRESS OR +IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE REGENTS OF +THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE FOR ANY DAMAGES, +INCLUDING DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OF OR IN CONNECTION +WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS HEREAFTER +ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +''' + +def sayHello(f): + print >> f, "M5 Simulator System" + print >> f, briefCopyright + print >> f, "M5 compiled on", __main__.compileDate + hostname = os.environ.get('HOSTNAME') + if not hostname: + hostname = os.environ.get('HOST') + if hostname: + print >> f, "M5 executing on", hostname + print >> f, "M5 simulation started", time.ctime() + +sayHello(sys.stderr) # define this here so we can use it right away if necessary def panic(string): @@ -72,3 +118,63 @@ from config import * # import the built-in object definitions from objects import * + +args_left = sys.argv[1:] +configfile_found = False + +while args_left: + arg = args_left.pop(0) + if arg.startswith('--'): + # if arg starts with '--', parse as a special python option + # of the format --= + try: + (var, val) = arg.split('=', 1) + except ValueError: + panic("Could not parse configuration argument '%s'\n" + "Expecting --=\n" % arg); + eval("%s = %s" % (var, repr(val))) + elif arg.startswith('-'): + # if the arg starts with '-', it should be a simulator option + # with a format similar to getopt. + optchar = arg[1] + if len(arg) > 2: + args_left.insert(0, arg[2:]) + if optchar == 'd': + outdir = args_left.pop(0) + elif optchar == 'h': + showBriefHelp(sys.stderr) + sys.exit(1) + elif optchar == 'E': + env_str = args_left.pop(0) + split_result = env_str.split('=', 1) + var = split_result[0] + if len(split_result == 2): + val = split_result[1] + else: + val = True + env[var] = val + elif optchar == 'I': + AddToPath(args_left.pop(0)) + elif optchar == 'P': + eval(args_left.pop(0)) + else: + showBriefHelp(sys.stderr) + panic("invalid argument '%s'\n" % arg_str) + else: + # In any other case, treat the option as a configuration file + # name and load it. + if not arg.endswith('.py'): + panic("Config file '%s' must end in '.py'\n" % arg) + configfile_found = True + m5execfile(arg, globals()) + + +if not configfile_found: + panic("no configuration file specified!") + +if globals().has_key('root') and isinstance(root, Root): + sys.stdout = file('config.ini', 'w') + instantiate(root) +else: + print 'Instantiation skipped: no root object found.' + diff --git a/src/python/m5/config.py b/src/python/m5/config.py index 1e25e0d09..ce7e5a964 100644 --- a/src/python/m5/config.py +++ b/src/python/m5/config.py @@ -794,7 +794,7 @@ class ParamFactory(object): # E.g., Param.Int(5, "number of widgets") def __call__(self, *args, **kwargs): - caller_frame = inspect.stack()[1][0] + caller_frame = inspect.currentframe().f_back ptype = None try: ptype = eval(self.ptype_str, -- cgit v1.2.3