SConscript revision 1439
1# -*- mode:python -*-
2
3# Copyright (c) 2005 The Regents of The University of Michigan
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are
8# met: redistributions of source code must retain the above copyright
9# notice, this list of conditions and the following disclaimer;
10# redistributions in binary form must reproduce the above copyright
11# notice, this list of conditions and the following disclaimer in the
12# documentation and/or other materials provided with the distribution;
13# neither the name of the copyright holders nor the names of its
14# contributors may be used to endorse or promote products derived from
15# this software without specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29import os, os.path, re
30
31def WriteEmbeddedPyFile(target, source, path, name, ext, filename):
32    if isinstance(source, str):
33        source = file(source, 'r')
34
35    if isinstance(target, str):
36        target = file(target, 'w')
37
38    print >>target, "AddModule(%s, %s, %s, %s, '''\\" % \
39          (`path`, `name`, `ext`, `filename`)
40
41    for line in source:
42        line = line
43        # escape existing backslashes
44        line = line.replace('\\', '\\\\')
45        # escape existing triple quotes
46        line = line.replace("'''", r"\'\'\'")
47
48        print >>target, line,
49
50    print >>target, "''')"
51    print >>target
52
53def WriteCFile(target, source, name):
54    if isinstance(source, str):
55        source = file(source, 'r')
56
57    if isinstance(target, str):
58        target = file(target, 'w')
59
60    print >>target, 'const char %s_string[] = {' % name
61
62    count = 0
63    from array import array
64    try:
65        while True:
66            foo = array('B')
67            foo.fromfile(source, 10000)
68            l = [ str(i) for i in foo.tolist() ]
69            count += len(l)
70            for i in xrange(0,9999,20):
71                print >>target, ','.join(l[i:i+20]) + ','
72    except EOFError:
73        l = [ str(i) for i in foo.tolist() ]
74        count += len(l)
75        for i in xrange(0,len(l),20):
76            print >>target, ','.join(l[i:i+20]) + ','
77        print >>target, ','.join(l[i:]) + ','
78
79    print >>target, '};'
80    print >>target, 'const int %s_length = %d;' % (name, count)
81    print >>target
82
83def splitpath(path):
84    dir,file = os.path.split(path)
85    path = []
86    assert(file)
87    while dir:
88        dir,base = os.path.split(dir)
89        path.insert(0, base)
90    return path, file
91
92Import('env')
93def MakeEmbeddedPyFile(target, source, env):
94    target = file(str(target[0]), 'w')
95   
96    tree = {}
97    for src in source:
98        src = str(src)
99        path,pyfile = splitpath(src)
100        node = tree
101        for dir in path:
102            if not node.has_key(dir):
103                node[dir] = { }
104            node = node[dir]
105
106        name,ext = pyfile.split('.')
107        if name == '__init__':
108            node['.hasinit'] = True
109        node[pyfile] = (src,name,ext,src)
110
111    done = False
112    while not done:
113        done = True
114        for name,entry in tree.items():
115            if not isinstance(entry, dict): continue
116            if entry.has_key('.hasinit'): continue
117
118            done = False
119            del tree[name]
120            for key,val in entry.iteritems():
121                if tree.has_key(key):
122                    raise NameError, \
123                          "dir already has %s can't add it again" % key
124                tree[key] = val
125
126    files = []
127    def populate(node, path = []):
128        names = node.keys()
129        names.sort()
130        for name in names:
131            if name == '.hasinit':
132                continue
133            
134            entry = node[name]
135            if isinstance(entry, dict):
136                if not entry.has_key('.hasinit'):
137                    raise NameError, 'package directory missing __init__.py'
138                populate(entry, path + [ name ])
139            else:
140                pyfile,name,ext,filename = entry
141                files.append((pyfile, path, name, ext, filename))
142    populate(tree)
143
144    for pyfile, path, name, ext, filename in files:
145        WriteEmbeddedPyFile(target, pyfile, path, name, ext, filename)
146
147def MakeDefinesPyFile(target, source, env):
148    target = file(str(target[0]), 'w')
149
150    defines = env['CPPDEFINES']
151    if isinstance(defines, list):
152        for var in defines:
153            if isinstance(var, tuple):
154                key,val = var
155            else:
156                key,val = var,'True'
157
158            if not isinstance(key, basestring):
159                panic("invalid type for define: %s" % type(key))
160                
161            print >>target, "env['%s'] = '%s'" % (key, val)
162
163    elif isinstance(defines, dict):
164        for key,val in defines.iteritems():
165            print >>target, "env['%s'] = '%s'" % (key, val)
166    else:
167        panic("invalid type for defines: %s" % type(defines))
168
169CFileCounter = 0
170def MakePythonCFile(target, source, env):
171    global CFileCounter
172    target = file(str(target[0]), 'w')
173
174    print >>target, '''\
175#include "base/embedfile.hh"
176
177namespace {
178'''
179    for src in source:
180        src = str(src)
181        fname = os.path.basename(src)
182        name = 'embedded_file%d' % CFileCounter
183        CFileCounter += 1
184        WriteCFile(target, src, name)
185        print >>target, '''\
186EmbedMap %(name)s("%(fname)s",
187    %(name)s_string, %(name)s_length);
188
189''' % locals()
190    print >>target, '''\
191
192/* namespace */ }
193'''
194
195embedded_py_files = ['m5config.py', 'importer.py', '../../util/pbs/jobfile.py']
196objpath = os.path.join(env['SRCDIR'], 'objects')
197for root, dirs, files in os.walk(objpath, topdown=True):
198    for i,dir in enumerate(dirs):
199        if dir == 'SCCS':
200            del dirs[i]
201            break
202
203    assert(root.startswith(objpath))
204    for f in files:
205        if f.endswith('.mpy') or f.endswith('.py'):
206            embedded_py_files.append(os.path.join(root, f))
207
208embedfile_hh = os.path.join(env['SRCDIR'], 'base/embedfile.hh')
209env.Command('defines.py', None, MakeDefinesPyFile)
210env.Command('embedded_py.py', embedded_py_files, MakeEmbeddedPyFile)
211env.Depends('embedded_py.cc', embedfile_hh)
212env.Command('embedded_py.cc',
213            ['string_importer.py', 'defines.py', 'embedded_py.py'],
214            MakePythonCFile)
215