summaryrefslogtreecommitdiff
path: root/src/SConscript
diff options
context:
space:
mode:
Diffstat (limited to 'src/SConscript')
-rw-r--r--src/SConscript185
1 files changed, 133 insertions, 52 deletions
diff --git a/src/SConscript b/src/SConscript
index ad1fe76a9..36cbbfa78 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -28,11 +28,13 @@
#
# Authors: Nathan Binkert
+import array
import imp
+import marshal
import os
-import py_compile
+import re
import sys
-import zipfile
+import zlib
from os.path import basename, exists, isdir, isfile, join as joinpath
@@ -58,39 +60,54 @@ def sort_list(_list):
return _list
class PySourceFile(object):
+ invalid_sym_char = re.compile('[^A-z0-9_]')
def __init__(self, package, source):
filename = str(source)
pyname = basename(filename)
assert pyname.endswith('.py')
name = pyname[:-3]
- path = package.split('.')
+ if package:
+ path = package.split('.')
+ else:
+ path = []
modpath = path
if name != '__init__':
modpath += [name]
modpath = '.'.join(modpath)
- arcpath = package.split('.') + [ pyname + 'c' ]
+ arcpath = path + [ pyname ]
arcname = joinpath(*arcpath)
- self.source = source
+ self.tnode = source
+ self.snode = source.srcnode()
self.pyname = pyname
- self.srcpath = source.srcnode().abspath
self.package = package
self.modpath = modpath
self.arcname = arcname
self.filename = filename
self.compiled = File(filename + 'c')
+ self.assembly = File(filename + '.s')
+ self.symname = "PyEMB_" + self.invalid_sym_char.sub('_', modpath)
+
########################################################################
# Code for adding source files of various types
#
-cc_sources = []
+cc_lib_sources = []
def Source(source):
- '''Add a C/C++ source file to the build'''
+ '''Add a source file to the libm5 build'''
+ if not isinstance(source, SCons.Node.FS.File):
+ source = File(source)
+
+ cc_lib_sources.append(source)
+
+cc_bin_sources = []
+def BinSource(source):
+ '''Add a source file to the m5 binary build'''
if not isinstance(source, SCons.Node.FS.File):
source = File(source)
- cc_sources.append(source)
+ cc_bin_sources.append(source)
py_sources = []
def PySource(package, source):
@@ -129,6 +146,7 @@ def SwigSource(package, source):
# Children should have access
Export('Source')
+Export('BinSource')
Export('PySource')
Export('SimObject')
Export('SwigSource')
@@ -259,7 +277,7 @@ class DictImporter(object):
py_modules = {}
for source in py_sources:
- py_modules[source.modpath] = source.srcpath
+ py_modules[source.modpath] = source.snode.abspath
# install the python importer so we can grab stuff from the source
# tree itself. We can't have SimObjects added after this point or
@@ -551,14 +569,14 @@ def makeSwigInit(target, source, env):
for module in source:
print >>f, ' void init_%s();' % module.get_contents()
print >>f, '}'
- print >>f, 'void init_swig() {'
+ print >>f, 'void initSwig() {'
for module in source:
print >>f, ' init_%s();' % module.get_contents()
print >>f, '}'
f.close()
-env.Command('swig/init.cc', swig_modules, makeSwigInit)
-Source('swig/init.cc')
+env.Command('python/swig/init.cc', swig_modules, makeSwigInit)
+Source('python/swig/init.cc')
# Generate traceflags.py
def traceFlagsPy(target, source, env):
@@ -797,42 +815,95 @@ env.Command('base/program_info.cc',
Value(str(SCons.Node.FS.default_fs.SConstruct_dir)),
programInfo)
-# Build the zip file
-def compilePyFile(target, source, env):
- '''Action function to compile a .py into a .pyc'''
- py_compile.compile(str(source[0]), str(target[0]))
-
-def buildPyZip(target, source, env):
- '''Action function to build the zip archive. Uses the
- PyZipFile module included in the standard Python library.'''
-
- py_compiled = {}
- for s in py_sources:
- compname = str(s.compiled)
- assert compname not in py_compiled
- py_compiled[compname] = s
-
- zf = zipfile.ZipFile(str(target[0]), 'w')
- for s in source:
- zipname = str(s)
- arcname = py_compiled[zipname].arcname
- zf.write(zipname, arcname)
- zf.close()
+# embed python files. All .py files that have been indicated by a
+# PySource() call in a SConscript need to be embedded into the M5
+# library. To do that, we compile the file to byte code, marshal the
+# byte code, compress it, and then generate an assembly file that
+# inserts the result into the data section with symbols indicating the
+# beginning, and end (and with the size at the end)
+py_sources_tnodes = {}
+for pysource in py_sources:
+ py_sources_tnodes[pysource.tnode] = pysource
+
+def objectifyPyFile(target, source, env):
+ '''Action function to compile a .py into a code object, marshal
+ it, compress it, and stick it into an asm file so the code appears
+ as just bytes with a label in the data section'''
+
+ src = file(str(source[0]), 'r').read()
+ dst = file(str(target[0]), 'w')
+
+ pysource = py_sources_tnodes[source[0]]
+ compiled = compile(src, pysource.snode.path, 'exec')
+ marshalled = marshal.dumps(compiled)
+ compressed = zlib.compress(marshalled)
+ data = compressed
+
+ # Some C/C++ compilers prepend an underscore to global symbol
+ # names, so if they're going to do that, we need to prepend that
+ # leading underscore to globals in the assembly file.
+ if env['LEADING_UNDERSCORE']:
+ sym = '_' + pysource.symname
+ else:
+ sym = pysource.symname
+
+ step = 16
+ print >>dst, ".data"
+ print >>dst, ".globl %s_beg" % sym
+ print >>dst, ".globl %s_end" % sym
+ print >>dst, "%s_beg:" % sym
+ for i in xrange(0, len(data), step):
+ x = array.array('B', data[i:i+step])
+ print >>dst, ".byte", ','.join([str(d) for d in x])
+ print >>dst, "%s_end:" % sym
+ print >>dst, ".long %d" % len(marshalled)
-py_compiled = []
-py_zip_depends = []
for source in py_sources:
- env.Command(source.compiled, source.source, compilePyFile)
- py_compiled.append(source.compiled)
-
- # make the zipfile depend on the archive name so that the archive
- # is rebuilt if the name changes
- py_zip_depends.append(Value(source.arcname))
+ env.Command(source.assembly, source.tnode, objectifyPyFile)
+ Source(source.assembly)
+
+# Generate init_python.cc which creates a bunch of EmbeddedPyModule
+# structs that describe the embedded python code. One such struct
+# contains information about the importer that python uses to get at
+# the embedded files, and then there's a list of all of the rest that
+# the importer uses to load the rest on demand.
+py_sources_symbols = {}
+for pysource in py_sources:
+ py_sources_symbols[pysource.symname] = pysource
+def pythonInit(target, source, env):
+ dst = file(str(target[0]), 'w')
+
+ def dump_mod(sym, endchar=','):
+ pysource = py_sources_symbols[sym]
+ print >>dst, ' { "%s",' % pysource.arcname
+ print >>dst, ' "%s",' % pysource.modpath
+ print >>dst, ' %s_beg, %s_end,' % (sym, sym)
+ print >>dst, ' %s_end - %s_beg,' % (sym, sym)
+ print >>dst, ' *(int *)%s_end }%s' % (sym, endchar)
+
+ print >>dst, '#include "sim/init.hh"'
+
+ for sym in source:
+ sym = sym.get_contents()
+ print >>dst, "extern const char %s_beg[], %s_end[];" % (sym, sym)
+
+ print >>dst, "const EmbeddedPyModule embeddedPyImporter = "
+ dump_mod("PyEMB_importer", endchar=';');
+ print >>dst
+
+ print >>dst, "const EmbeddedPyModule embeddedPyModules[] = {"
+ for i,sym in enumerate(source):
+ sym = sym.get_contents()
+ if sym == "PyEMB_importer":
+ # Skip the importer since we've already exported it
+ continue
+ dump_mod(sym)
+ print >>dst, " { 0, 0, 0, 0, 0, 0 }"
+ print >>dst, "};"
-# Add the zip file target to the environment.
-m5zip = File('m5py.zip')
-env.Command(m5zip, py_compiled, buildPyZip)
-env.Depends(m5zip, py_zip_depends)
+symbols = [Value(s.symname) for s in py_sources]
+env.Command('sim/init_python.cc', symbols, pythonInit)
+Source('sim/init_python.cc')
########################################################################
#
@@ -873,18 +944,28 @@ def makeEnv(label, objsfx, strip = False, **kwargs):
newEnv = env.Copy(OBJSUFFIX=objsfx)
newEnv.Label = label
newEnv.Append(**kwargs)
+
+ # First make a library of everything but main() so other programs can
+ # link against m5.
+ #
+ # SCons doesn't know to append a library suffix when there is a '.' in the
+ # name. Use '_' instead.
+ m5lib = newEnv.Library('m5_' + label, make_objs(cc_lib_sources, newEnv))
+
+ # Now link a stub with main() and the library.
exe = 'm5.' + label # final executable
- bin = exe + '.bin' # executable w/o appended Python zip archive
- newEnv.Program(bin, make_objs(cc_sources, newEnv))
+ objects = [newEnv.Object(s) for s in cc_bin_sources] + m5lib
if strip:
- stripped_bin = bin + '.stripped'
+ unstripped_exe = exe + '.unstripped'
+ newEnv.Program(unstripped_exe, objects)
if sys.platform == 'sunos5':
cmd = 'cp $SOURCE $TARGET; strip $TARGET'
else:
cmd = 'strip $SOURCE -o $TARGET'
- newEnv.Command(stripped_bin, bin, cmd)
- bin = stripped_bin
- targets = newEnv.Concat(exe, [bin, 'm5py.zip'])
+ targets = newEnv.Command(exe, unstripped_exe, cmd)
+ else:
+ targets = newEnv.Program(exe, objects)
+
newEnv.M5Binary = targets[0]
envList.append(newEnv)