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 --- |