SConscript (12246:9ffa51416f39) SConscript (12302:5771c4c65b23)
1# -*- mode:python -*-
2
3# Copyright (c) 2004-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

--- 45 unchanged lines hidden (view full) ---

54
55build_env = [(opt, env[opt]) for opt in export_vars]
56
57from m5.util import code_formatter, compareVersions
58
59########################################################################
60# Code for adding source files of various types
61#
1# -*- mode:python -*-
2
3# Copyright (c) 2004-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

--- 45 unchanged lines hidden (view full) ---

54
55build_env = [(opt, env[opt]) for opt in export_vars]
56
57from m5.util import code_formatter, compareVersions
58
59########################################################################
60# Code for adding source files of various types
61#
62# When specifying a source file of some type, a set of guards can be
63# specified for that file. When get() is used to find the files, if
64# get specifies a set of filters, only files that match those filters
65# will be accepted (unspecified filters on files are assumed to be
66# false). Current filters are:
67# main -- specifies the gem5 main() function
68# skip_lib -- do not put this file into the gem5 library
69# skip_no_python -- do not put this file into a no_python library
70# as it embeds compiled Python
71# <unittest> -- unit tests use filters based on the unit test name
72#
73# A parent can now be specified for a source file and default filter
74# values will be retrieved recursively from parents (children override
75# parents).
76#
77def guarded_source_iterator(sources, **guards):
78 '''Iterate over a set of sources, gated by a set of guards.'''
79 for src in sources:
80 for flag,value in guards.iteritems():
81 # if the flag is found and has a different value, skip
82 # this file
83 if src.all_guards.get(flag, False) != value:
84 break
85 else:
86 yield src
62# When specifying a source file of some type, a set of tags can be
63# specified for that file.
87
64
65class SourceList(list):
66 def with_tags_that(self, predicate):
67 '''Return a list of sources with tags that satisfy a predicate.'''
68 def match(source):
69 return predicate(source.tags)
70 return SourceList(filter(match, self))
71
72 def with_any_tags(self, *tags):
73 '''Return a list of sources with any of the supplied tags.'''
74 return self.with_tags_that(lambda stags: len(tags & stags) > 0)
75
76 def with_all_tags(self, *tags):
77 '''Return a list of sources with all of the supplied tags.'''
78 return self.with_tags_that(lambda stags: tags <= stags)
79
80 def with_tag(self, tag):
81 '''Return a list of sources with the supplied tag.'''
82 return self.with_tags_that(lambda stags: tag in stags)
83
84 def without_tags(self, *tags):
85 '''Return a list of sources without any of the supplied tags.'''
86 return self.with_tags_that(lambda stags: len(tags & stags) == 0)
87
88 def without_tag(self, tag):
89 '''Return a list of sources with the supplied tag.'''
90 return self.with_tags_that(lambda stags: tag not in stags)
91
88class SourceMeta(type):
89 '''Meta class for source files that keeps track of all files of a
92class SourceMeta(type):
93 '''Meta class for source files that keeps track of all files of a
90 particular type and has a get function for finding all functions
91 of a certain type that match a set of guards'''
94 particular type.'''
92 def __init__(cls, name, bases, dict):
93 super(SourceMeta, cls).__init__(name, bases, dict)
95 def __init__(cls, name, bases, dict):
96 super(SourceMeta, cls).__init__(name, bases, dict)
94 cls.all = []
97 cls.all = SourceList()
95
98
96 def get(cls, **guards):
97 '''Find all files that match the specified guards. If a source
98 file does not specify a flag, the default is False'''
99 for s in guarded_source_iterator(cls.all, **guards):
100 yield s
101
102class SourceFile(object):
103 '''Base object that encapsulates the notion of a source file.
104 This includes, the source node, target node, various manipulations
99class SourceFile(object):
100 '''Base object that encapsulates the notion of a source file.
101 This includes, the source node, target node, various manipulations
105 of those. A source file also specifies a set of guards which
106 describing which builds the source file applies to. A parent can
107 also be specified to get default guards from'''
102 of those. A source file also specifies a set of tags which
103 describing arbitrary properties of the source file.'''
108 __metaclass__ = SourceMeta
104 __metaclass__ = SourceMeta
109 def __init__(self, source, parent=None, **guards):
110 self.guards = guards
111 self.parent = parent
105 def __init__(self, source, tags=None, add_tags=None):
106 if tags is None:
107 tags='gem5 lib'
108 if isinstance(tags, basestring):
109 tags = set([tags])
110 if isinstance(add_tags, basestring):
111 add_tags = set([add_tags])
112 if add_tags:
113 tags = tags | add_tags
114 self.tags = set(tags)
112
113 tnode = source
114 if not isinstance(source, SCons.Node.FS.File):
115 tnode = File(source)
116
117 self.tnode = tnode
118 self.snode = tnode.srcnode()
119

--- 17 unchanged lines hidden (view full) ---

137 def extname(self):
138 index = self.basename.rfind('.')
139 if index <= 0:
140 # dot files aren't extensions
141 return self.basename, None
142
143 return self.basename[:index], self.basename[index+1:]
144
115
116 tnode = source
117 if not isinstance(source, SCons.Node.FS.File):
118 tnode = File(source)
119
120 self.tnode = tnode
121 self.snode = tnode.srcnode()
122

--- 17 unchanged lines hidden (view full) ---

140 def extname(self):
141 index = self.basename.rfind('.')
142 if index <= 0:
143 # dot files aren't extensions
144 return self.basename, None
145
146 return self.basename[:index], self.basename[index+1:]
147
145 @property
146 def all_guards(self):
147 '''find all guards for this object getting default values
148 recursively from its parents'''
149 guards = {}
150 if self.parent:
151 guards.update(self.parent.guards)
152 guards.update(self.guards)
153 return guards
154
155 def __lt__(self, other): return self.filename < other.filename
156 def __le__(self, other): return self.filename <= other.filename
157 def __gt__(self, other): return self.filename > other.filename
158 def __ge__(self, other): return self.filename >= other.filename
159 def __eq__(self, other): return self.filename == other.filename
160 def __ne__(self, other): return self.filename != other.filename
161
162 @staticmethod
163 def done():
164 def disabled(cls, name, *ignored):
165 raise RuntimeError("Additional SourceFile '%s'" % name,\
166 "declared, but targets deps are already fixed.")
167 SourceFile.__init__ = disabled
168
169
170class Source(SourceFile):
148 def __lt__(self, other): return self.filename < other.filename
149 def __le__(self, other): return self.filename <= other.filename
150 def __gt__(self, other): return self.filename > other.filename
151 def __ge__(self, other): return self.filename >= other.filename
152 def __eq__(self, other): return self.filename == other.filename
153 def __ne__(self, other): return self.filename != other.filename
154
155 @staticmethod
156 def done():
157 def disabled(cls, name, *ignored):
158 raise RuntimeError("Additional SourceFile '%s'" % name,\
159 "declared, but targets deps are already fixed.")
160 SourceFile.__init__ = disabled
161
162
163class Source(SourceFile):
171 current_group = None
172 source_groups = { None : [] }
164 ungrouped_tag = 'No link group'
165 source_groups = set()
173
166
167 _current_group_tag = ungrouped_tag
168
169 @staticmethod
170 def link_group_tag(group):
171 return 'link group: %s' % group
172
174 @classmethod
175 def set_group(cls, group):
173 @classmethod
174 def set_group(cls, group):
176 if not group in Source.source_groups:
177 Source.source_groups[group] = []
178 Source.current_group = group
175 new_tag = Source.link_group_tag(group)
176 Source._current_group_tag = new_tag
177 Source.source_groups.add(group)
179
178
180 '''Add a c/c++ source file to the build'''
181 def __init__(self, source, Werror=True, **guards):
182 '''specify the source file, and any guards'''
183 super(Source, self).__init__(source, **guards)
179 def _add_link_group_tag(self):
180 self.tags.add(Source._current_group_tag)
184
181
182 '''Add a c/c++ source file to the build'''
183 def __init__(self, source, tags=None, add_tags=None, Werror=True):
184 '''specify the source file, and any tags'''
185 super(Source, self).__init__(source, tags, add_tags)
186 self._add_link_group_tag()
185 self.Werror = Werror
186
187 self.Werror = Werror
188
187 Source.source_groups[Source.current_group].append(self)
188
189class PySource(SourceFile):
190 '''Add a python source file to the named package'''
191 invalid_sym_char = re.compile('[^A-z0-9_]')
192 modules = {}
193 tnodes = {}
194 symnames = {}
195
189class PySource(SourceFile):
190 '''Add a python source file to the named package'''
191 invalid_sym_char = re.compile('[^A-z0-9_]')
192 modules = {}
193 tnodes = {}
194 symnames = {}
195
196 def __init__(self, package, source, **guards):
197 '''specify the python package, the source file, and any guards'''
198 super(PySource, self).__init__(source, **guards)
196 def __init__(self, package, source, tags=None, add_tags=None):
197 '''specify the python package, the source file, and any tags'''
198 super(PySource, self).__init__(source, tags, add_tags)
199
200 modname,ext = self.extname
201 assert ext == 'py'
202
203 if package:
204 path = package.split('.')
205 else:
206 path = []

--- 23 unchanged lines hidden (view full) ---

230
231class SimObject(PySource):
232 '''Add a SimObject python file as a python source object and add
233 it to a list of sim object modules'''
234
235 fixed = False
236 modnames = []
237
199
200 modname,ext = self.extname
201 assert ext == 'py'
202
203 if package:
204 path = package.split('.')
205 else:
206 path = []

--- 23 unchanged lines hidden (view full) ---

230
231class SimObject(PySource):
232 '''Add a SimObject python file as a python source object and add
233 it to a list of sim object modules'''
234
235 fixed = False
236 modnames = []
237
238 def __init__(self, source, **guards):
239 '''Specify the source file and any guards (automatically in
238 def __init__(self, source, tags=None, add_tags=None):
239 '''Specify the source file and any tags (automatically in
240 the m5.objects package)'''
240 the m5.objects package)'''
241 super(SimObject, self).__init__('m5.objects', source, **guards)
241 super(SimObject, self).__init__('m5.objects', source, tags, add_tags)
242 if self.fixed:
243 raise AttributeError, "Too late to call SimObject now."
244
245 bisect.insort_right(SimObject.modnames, self.modname)
246
247class ProtoBuf(SourceFile):
248 '''Add a Protocol Buffer to build'''
249
242 if self.fixed:
243 raise AttributeError, "Too late to call SimObject now."
244
245 bisect.insort_right(SimObject.modnames, self.modname)
246
247class ProtoBuf(SourceFile):
248 '''Add a Protocol Buffer to build'''
249
250 def __init__(self, source, **guards):
251 '''Specify the source file, and any guards'''
252 super(ProtoBuf, self).__init__(source, **guards)
250 def __init__(self, source, tags=None, add_tags=None):
251 '''Specify the source file, and any tags'''
252 super(ProtoBuf, self).__init__(source, tags, add_tags)
253
254 # Get the file name and the extension
255 modname,ext = self.extname
256 assert ext == 'proto'
257
258 # Currently, we stick to generating the C++ headers, so we
259 # only need to track the source and header.
260 self.cc_file = File(modname + '.pb.cc')
261 self.hh_file = File(modname + '.pb.h')
262
263class UnitTest(object):
264 '''Create a UnitTest'''
265
266 all = []
267 def __init__(self, target, *sources, **kwargs):
268 '''Specify the target name and any sources. Sources that are
269 not SourceFiles are evalued with Source(). All files are
253
254 # Get the file name and the extension
255 modname,ext = self.extname
256 assert ext == 'proto'
257
258 # Currently, we stick to generating the C++ headers, so we
259 # only need to track the source and header.
260 self.cc_file = File(modname + '.pb.cc')
261 self.hh_file = File(modname + '.pb.h')
262
263class UnitTest(object):
264 '''Create a UnitTest'''
265
266 all = []
267 def __init__(self, target, *sources, **kwargs):
268 '''Specify the target name and any sources. Sources that are
269 not SourceFiles are evalued with Source(). All files are
270 guarded with a guard of the same name as the UnitTest
271 target.'''
270 tagged with the name of the UnitTest target.'''
272
271
273 srcs = []
272 srcs = SourceList()
274 for src in sources:
275 if not isinstance(src, SourceFile):
273 for src in sources:
274 if not isinstance(src, SourceFile):
276 src = Source(src, skip_lib=True)
277 src.guards[target] = True
275 src = Source(src, tags=str(target))
278 srcs.append(src)
279
280 self.sources = srcs
281 self.target = target
282 self.main = kwargs.get('main', False)
283 UnitTest.all.append(self)
284
285# Children should have access

--- 479 unchanged lines hidden (view full) ---

765 # specify the proto_path to avoid having the generated files
766 # include the path.
767 env.Command([proto.cc_file, proto.hh_file], proto.tnode,
768 MakeAction('$PROTOC --cpp_out ${TARGET.dir} '
769 '--proto_path ${SOURCE.dir} $SOURCE',
770 Transform("PROTOC")))
771
772 # Add the C++ source file
276 srcs.append(src)
277
278 self.sources = srcs
279 self.target = target
280 self.main = kwargs.get('main', False)
281 UnitTest.all.append(self)
282
283# Children should have access

--- 479 unchanged lines hidden (view full) ---

763 # specify the proto_path to avoid having the generated files
764 # include the path.
765 env.Command([proto.cc_file, proto.hh_file], proto.tnode,
766 MakeAction('$PROTOC --cpp_out ${TARGET.dir} '
767 '--proto_path ${SOURCE.dir} $SOURCE',
768 Transform("PROTOC")))
769
770 # Add the C++ source file
773 Source(proto.cc_file, **proto.guards)
771 Source(proto.cc_file, tags=proto.tags)
774elif ProtoBuf.all:
775 print 'Got protobuf to build, but lacks support!'
776 Exit(1)
777
778#
779# Handle debug flags
780#
781def makeDebugFlagCC(target, source, env):

--- 149 unchanged lines hidden (view full) ---

931
932} // anonymous namespace
933''')
934 code.write(str(target[0]))
935
936for source in PySource.all:
937 env.Command(source.cpp, source.tnode,
938 MakeAction(embedPyFile, Transform("EMBED PY")))
772elif ProtoBuf.all:
773 print 'Got protobuf to build, but lacks support!'
774 Exit(1)
775
776#
777# Handle debug flags
778#
779def makeDebugFlagCC(target, source, env):

--- 149 unchanged lines hidden (view full) ---

929
930} // anonymous namespace
931''')
932 code.write(str(target[0]))
933
934for source in PySource.all:
935 env.Command(source.cpp, source.tnode,
936 MakeAction(embedPyFile, Transform("EMBED PY")))
939 Source(source.cpp, skip_no_python=True)
937 Source(source.cpp, tags=source.tags, add_tags='python')
940
941########################################################################
942#
943# Define binaries. Each different build type (debug, opt, etc.) gets
944# a slightly different build environment.
945#
946
947# List of constructed environments to pass back to SConstruct
938
939########################################################################
940#
941# Define binaries. Each different build type (debug, opt, etc.) gets
942# a slightly different build environment.
943#
944
945# List of constructed environments to pass back to SConstruct
948date_source = Source('base/date.cc', skip_lib=True)
946date_source = Source('base/date.cc', tags=[])
949
950# Function to create a new build environment as clone of current
951# environment 'env' with modified object suffix and optional stripped
952# binary. Additional keyword arguments are appended to corresponding
953# build environment vars.
954def makeEnv(env, label, objsfx, strip=False, disable_partial=False, **kwargs):
955 # SCons doesn't know to append a library suffix when there is a '.' in the
956 # name. Use '_' instead.

--- 66 unchanged lines hidden (view full) ---

1023 else:
1024 obj = env.SharedObject(source.tnode)
1025
1026 if extra_deps:
1027 env.Depends(obj, extra_deps)
1028
1029 return obj
1030
947
948# Function to create a new build environment as clone of current
949# environment 'env' with modified object suffix and optional stripped
950# binary. Additional keyword arguments are appended to corresponding
951# build environment vars.
952def makeEnv(env, label, objsfx, strip=False, disable_partial=False, **kwargs):
953 # SCons doesn't know to append a library suffix when there is a '.' in the
954 # name. Use '_' instead.

--- 66 unchanged lines hidden (view full) ---

1021 else:
1022 obj = env.SharedObject(source.tnode)
1023
1024 if extra_deps:
1025 env.Depends(obj, extra_deps)
1026
1027 return obj
1028
1031 lib_guards = {'main': False, 'skip_lib': False}
1029 lib_sources = Source.all.with_tag('gem5 lib')
1032
1033 # Without Python, leave out all Python content from the library
1034 # builds. The option doesn't affect gem5 built as a program
1035 if GetOption('without_python'):
1030
1031 # Without Python, leave out all Python content from the library
1032 # builds. The option doesn't affect gem5 built as a program
1033 if GetOption('without_python'):
1036 lib_guards['skip_no_python'] = False
1034 lib_sources = lib_sources.without_tag('python')
1037
1038 static_objs = []
1039 shared_objs = []
1035
1036 static_objs = []
1037 shared_objs = []
1040 for s in guarded_source_iterator(Source.source_groups[None], **lib_guards):
1038
1039 for s in lib_sources.with_tag(Source.ungrouped_tag):
1041 static_objs.append(make_obj(s, True))
1042 shared_objs.append(make_obj(s, False))
1043
1044 partial_objs = []
1040 static_objs.append(make_obj(s, True))
1041 shared_objs.append(make_obj(s, False))
1042
1043 partial_objs = []
1045 for group, all_srcs in Source.source_groups.iteritems():
1046 # If these are the ungrouped source files, skip them.
1047 if not group:
1048 continue
1049
1044
1050 # Get a list of the source files compatible with the current guards.
1051 srcs = [ s for s in guarded_source_iterator(all_srcs, **lib_guards) ]
1052 # If there aren't any left, skip this group.
1045 for group in Source.source_groups:
1046 srcs = lib_sources.with_tag(Source.link_group_tag(group))
1053 if not srcs:
1054 continue
1055
1056 # If partial linking is disabled, add these sources to the build
1057 # directly, and short circuit this loop.
1058 if disable_partial:
1059 for s in srcs:
1060 static_objs.append(make_obj(s, True))

--- 21 unchanged lines hidden (view full) ---

1082 shared_objs.append(shared_date)
1083
1084 # First make a library of everything but main() so other programs can
1085 # link against m5.
1086 static_lib = new_env.StaticLibrary(libname, static_objs)
1087 shared_lib = new_env.SharedLibrary(libname, shared_objs)
1088
1089 # Now link a stub with main() and the static library.
1047 if not srcs:
1048 continue
1049
1050 # If partial linking is disabled, add these sources to the build
1051 # directly, and short circuit this loop.
1052 if disable_partial:
1053 for s in srcs:
1054 static_objs.append(make_obj(s, True))

--- 21 unchanged lines hidden (view full) ---

1076 shared_objs.append(shared_date)
1077
1078 # First make a library of everything but main() so other programs can
1079 # link against m5.
1080 static_lib = new_env.StaticLibrary(libname, static_objs)
1081 shared_lib = new_env.SharedLibrary(libname, shared_objs)
1082
1083 # Now link a stub with main() and the static library.
1090 main_objs = [ make_obj(s, True) for s in Source.get(main=True) ]
1084 main_objs = [ make_obj(s, True) for s in Source.all.with_tag('main') ]
1091
1092 for test in UnitTest.all:
1085
1086 for test in UnitTest.all:
1093 flags = { test.target : True }
1094 test_sources = Source.get(**flags)
1087 test_sources = Source.all.with_tag(str(test.target))
1095 test_objs = [ make_obj(s, static=True) for s in test_sources ]
1096 if test.main:
1097 test_objs += main_objs
1098 path = 'unittest/%s.%s' % (test.target, label)
1099 new_env.Program(path, test_objs + static_objs)
1100
1101 progname = exename
1102 if strip:

--- 124 unchanged lines hidden ---
1088 test_objs = [ make_obj(s, static=True) for s in test_sources ]
1089 if test.main:
1090 test_objs += main_objs
1091 path = 'unittest/%s.%s' % (test.target, label)
1092 new_env.Program(path, test_objs + static_objs)
1093
1094 progname = exename
1095 if strip:

--- 124 unchanged lines hidden ---