add ext4,vfat and tar.bz2
[u-tools.git] / tools / scons.py
blobc8cc5f79b9702f108f5260b302319c8346f0e233
1 import sys
2 sys.path.append("tools") # Allow us to import bootimg.py
3 #sys.path.append("tools/pyelf")
4 #sys.path = ["tools/pexpect"] + sys.path # Allow us to import pexpect.py
6 import os.path
7 import SCons.Defaults
8 import SCons.Scanner
9 import os, glob
11 import traceback
12 from types import TupleType
13 from util import contains_any, identity_mapping
14 from xml.dom import minidom
15 from optparse import OptionParser
17 # Make it easier to raise UserErrors
18 from SCons.Errors import UserError
20 # We want the SConsign file (where it stores
21 # information on hashs and times
22 SConsignFile(".sconsign")
24 def get_version():
25 # Work make the scons version easy to test
26 scons_version = tuple([int(x) for x in SCons.__version__.split(".")])
28 # Make sure that we have a decent version of SCons
29 if scons_version <= (0, 95):
30 raise UserError, "Support for SCons 0.95 has been dropped. " + \
31 "Please upgrade to at least 0.96"
33 # We check we have at least version 2.3, If we don't we are in trouble!
34 if sys.version_info < (2, 3):
35 raise UserError, "To use the Kenge build system you need Python2.3 " + \
36 "including the python devel packages."
37 return scons_version
39 def src_glob(search, replacement = {}):
40 """Src glob is used to find source files easily e.g: src_glob("src/*.c"),
41 the reason we can't just use glob is due to the way SCons handles out
42 of directory builds."""
43 if search.startswith('#'):
44 # what does '#' signify?
45 search = search[1:]
46 dir = os.path.dirname(search)
47 if dir != "":
48 dir = '#' + dir + os.sep
49 #is the below any different from Dir('.').srcnode.abspath ??
50 src_path = Dir('#').srcnode().abspath
51 elif search.startswith(os.sep):
52 # we have been given an absolute path
53 dir = os.path.dirname(search)
54 if dir != "":
55 dir += os.sep
56 src_path = os.sep
57 else:
58 dir = os.path.dirname(search)
59 if dir != "":
60 dir += os.sep
61 src_path = Dir('.').srcnode().abspath
63 src_path = src_path % replacement
64 search = search % replacement
65 files = glob.glob(os.path.join(src_path, search))
66 files = map(os.path.basename, files)
67 ret_files = []
68 for file in files:
69 ret_files.append(dir + file)
70 # Sort the files so the linkers get the same list of objects
71 # and hence deterministic builds
72 ret_files.sort()
73 return ret_files
75 ################################################################################
76 # Read configuration files
77 ################################################################################
79 class Options:
80 """Class to hold a set of configuration options. This works as a
81 recursive dictionary, with access through the "." method. This allows
82 settings things such as:
84 conf = Options()
85 conf.FOO.BAR.BAZ = 1
87 And all intermediate level will be created automagically."""
89 def __init__(self):
90 """Create a new instance."""
91 self.__dict__["dict"] = {}
93 def __getattr__(self, attr):
94 """Magic getattr method to implement accessing dictionary
95 members through the . syntax. Will create a new Options dictionary
96 when accessing new names. This method is only called in cases
97 when the attribute doesn't already exist."""
98 if attr.startswith("__"): # Disallow access to "__" names
99 raise AttributeError
100 self.__dict__[attr] = Options()
101 return self.__dict__[attr]
103 def __setattr__(self, attr, value):
104 """Sets a new value in the dictionary"""
105 self.dict[attr.upper()] = value
107 def get_conf(args):
108 conf = Options()
109 # First read options from the .conf file
110 if os.path.exists(".conf"):
111 execfile(".conf", locals())
113 # Then take values from the commands line options
114 for (key, value) in args.items():
115 parts = key.split(".")
116 c = conf
117 while len(parts) > 1:
118 c = getattr(c, parts[0])
119 parts = parts[1:]
120 setattr(c, parts[0], value)
121 return conf
123 def load_cross(conf):
124 import cross
125 cross.conf = conf
126 cross.Dir = Dir
127 cross.SConsignFile = SConsignFile
128 cross.Environment = Environment
129 cross.Scanner = Scanner
130 cross.SCons = SCons
131 cross.Builder = Builder
132 cross.Action = Action
133 cross.SConscript = SConscript
134 cross.Flatten = Flatten
135 cross.src_glob = src_glob
136 cross.Value = Value
137 cross.Command = Command
138 cross.Touch = Touch
139 cross.File = File
140 cross.Depends = Depends
141 cross.CScan = CScan
142 cross.AlwaysBuild = AlwaysBuild
145 ############################################################################
146 # Cleaning stuff
147 ############################################################################
149 def clean():
150 # Determine if the user is trying to clean
151 cleaning = contains_any(["--clean", "--remove", "-c"], sys.argv)
153 # Clean out any .pyc from tool
154 if cleaning:
155 pyc_clean("tools")
157 # Option processing functions.
159 def get_bool_arg(build, name, default):
160 """Get the boolean value of an option."""
161 if type(build) == dict:
162 args = build
163 else:
164 args = build.args
165 x = args.get(name, default)
166 if type(x) is type(""):
167 x.lower()
168 if x in [1, True, "1", "true", "yes", "True"]:
169 x = True
170 elif x in [0, False, "0", "false", "no", "False"]:
171 x = False
172 else:
173 raise UserError, "%s is not a valid argument for option %s. It should be True or False" % (x, name)
175 return x
177 def get_arg(build, name, default):
178 if type(build) == dict:
179 args = build
180 else:
181 args = build.args
182 return args.get(name, default)
184 def get_int_arg(build, name, default):
185 val = get_arg(build, name, default)
187 if val is not None:
188 return int(val)
189 else:
190 return None
192 def get_option_arg(build, name, default, options, as_list = False):
193 """Get the value of an option, which must be one of the supplied set"""
194 if type(build) == dict:
195 args = build
196 else:
197 args = build.args
198 def_val = default
199 arg = args.get(name, def_val)
201 if options and type(options[0]) == TupleType:
202 # This means a user has specified a list like:
203 # [("foo", foo_object), ("bar", bar_object)]
204 mapping = dict(options)
205 options = [x[0] for x in options]
206 else:
207 mapping = dict([(str(x), x) for x in options])
209 if arg == None:
210 if str(arg) not in mapping:
211 raise UserError, "need argument for option %s. Valid options are: %s" % (name, options)
212 return mapping[str(arg)]
214 if not isinstance(arg, str): #Assuming integer
215 if arg not in options:
216 raise UserError, "%s is not a valid argument for option %s. Valid options are: %s" % (x, name, options)
217 return arg
218 arg = arg.split(",")
219 for x in arg:
220 if x not in mapping:
221 raise UserError, "%s is not a valid argument for option %s. Valid options are: %s" % (x, name, options)
223 if as_list:
224 return arg
225 else:
226 return mapping[arg[0]]
229 def get_rtos_example_args(xml_file, example_cmd_line):
230 """Read the given rtos tests configuration xml file and return a dictionary
231 containing the values read"""
232 rtos_args = {}
233 for example in example_cmd_line:
234 if not example == "all":
235 rtos_args[example] = {}
236 rtos_args[example]["nb_copies"] = 1
237 rtos_args[example]["extra_arg"] = 1
238 xmltree = minidom.parse("tools/unittest/" + xml_file).documentElement
239 rtos_args["server"] = xmltree.getAttribute("server")
240 example_nodes = xmltree.getElementsByTagName("example")
241 for example_node in example_nodes:
242 example_name = example_node.getAttribute("name")
243 if example_name in example_cmd_line or example_cmd_line == ["all"]:
244 if example_cmd_line == ["all"]:
245 rtos_args[example_name] = {}
246 rtos_args[example_name]["nb_copies"] = example_node.getAttribute("nb_copies")
247 rtos_args[example_name]["extra_arg"] = example_node.getAttribute("extra_arg")
248 return rtos_args
250 ################################################################################
251 # Now find the project SConstruct file to use.
252 ################################################################################
254 def get_sconstruct_path(conf):
255 # Find the project from the arguments.
256 project = conf.dict.get("PROJECT", None)
257 if "PROJECT" in conf.dict: del conf.dict["PROJECT"]
259 # Provide useful message if it doesn't exist
260 if project is None:
261 raise UserError, "You must specify the PROJECT you want to build."
263 cust = conf.dict.get('CUST', None)
264 sconstruct_path = "cust/%s/projects/%s/SConstruct" % (cust, project)
265 if not os.path.exists(sconstruct_path):
266 sconstruct_path = "projects/%s/SConstruct" % project
267 if not os.path.exists(sconstruct_path):
268 raise UserError, "%s is not a valid project" % project
269 else:
270 # liunote add for project import
271 project_path = "projects/%s/" % project
272 # print project_path
273 sys.path.append(project_path)
275 return sconstruct_path
278 scons_version = get_version()
279 conf = get_conf(ARGUMENTS)
280 load_cross(conf)
281 clean()
282 sconstruct_path = get_sconstruct_path(conf)
284 Export("conf")
285 Export("scons_version")
286 Export("UserError")
287 Export("src_glob")
288 Export("get_bool_arg")
289 Export("get_int_arg")
290 Export("get_arg")
291 # Execute the SConstruct
292 execfile(sconstruct_path)