2 # ex:ts=4:sw=4:sts=4:et
3 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4 """class for handling .bb files
6 Reads a .bb file and obtains its metadata
8 Copyright (C) 2003, 2004 Chris Larson
9 Copyright (C) 2003, 2004 Phil Blundell
11 This program is free software; you can redistribute it and/or modify it under
12 the terms of the GNU General Public License as published by the Free Software
13 Foundation; either version 2 of the License, or (at your option) any later
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22 Place, Suite 330, Boston, MA 02111-1307 USA."""
24 import re, bb, os, sys, time
25 import bb.fetch, bb.build, bb.utils
26 from bb import debug, data, fetch, fatal, methodpool
28 from ConfHandler import include, localpath, obtain, init
29 from bb.parse import ParseError
31 __func_start_regexp__ = re.compile( r"(((?P<py>python)|(?P<fr>fakeroot))\s*)*(?P<func>[\w\.\-\+\{\}\$]+)?\s*\(\s*\)\s*{$" )
32 __inherit_regexp__ = re.compile( r"inherit\s+(.+)" )
33 __export_func_regexp__ = re.compile( r"EXPORT_FUNCTIONS\s+(.+)" )
34 __addtask_regexp__ = re.compile("addtask\s+(?P<func>\w+)\s*((before\s*(?P<before>((.*(?=after))|(.*))))|(after\s*(?P<after>((.*(?=before))|(.*)))))*")
35 __addhandler_regexp__ = re.compile( r"addhandler\s+(.+)" )
36 __def_regexp__ = re.compile( r"def\s+(\w+).*:" )
37 __python_func_regexp__ = re.compile( r"(\s+.*)|(^$)" )
38 __word__ = re.compile(r"\S+")
47 __parsed_methods__ = methodpool.get_parsed_dict()
50 localfn = localpath(fn, d)
51 return localfn[-3:] == ".bb" or localfn[-8:] == ".bbclass" or localfn[-4:] == ".inc"
53 def inherit(files, d):
54 __inherit_cache = data.getVar('__inherit_cache', d) or ""
58 file = data.expand(f, d)
59 if file[0] != "/" and file[-8:] != ".bbclass":
60 file = os.path.join('classes', '%s.bbclass' % file)
62 if not file in __inherit_cache.split():
63 debug(2, "BB %s:%d: inheriting %s" % (fn, lineno, file))
64 __inherit_cache += " %s" % file
66 data.setVar('__inherit_cache', __inherit_cache, d)
69 def handle(fn, d, include = 0):
70 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __infunc__, __body__, __bbpath_found__, __residue__
78 debug(2, "BB " + fn + ": handle(data)")
80 debug(2, "BB " + fn + ": handle(data, include)")
82 (root, ext) = os.path.splitext(os.path.basename(fn))
83 base_name = "%s%s" % (root,ext)
88 classes.append(__classname__)
91 oldfile = data.getVar('FILE', d)
96 bbpath = (data.getVar('BBPATH', d, 1) or '').split(':')
97 if not os.path.isabs(fn):
100 p = data.expand(p, d)
101 j = os.path.join(p, fn)
102 if os.access(j, os.R_OK):
107 raise IOError("file not found")
112 if ext != ".bbclass":
113 bbpath.insert(0, os.path.dirname(abs_fn))
114 data.setVar('BBPATH', ":".join(bbpath), d)
117 bb.parse.mark_dependency(d, abs_fn)
119 if ext != ".bbclass":
120 data.setVar('FILE', fn, d)
121 i = (data.getVar("INHERIT", d, 1) or "").split()
122 if not "base" in i and __classname__ != "base":
132 feeder(lineno, s, fn, base_name, d)
134 # add a blank line to close out any python definition
135 feeder(lineno + 1, "", fn, base_name, d)
136 if ext == ".bbclass":
137 classes.remove(__classname__)
142 anonqueue = data.getVar("__anonqueue", d, 1) or []
143 for anon in anonqueue:
144 data.setVar("__anonfunc", anon["content"], d)
145 data.setVarFlags("__anonfunc", anon["flags"], d)
148 t = data.getVar('T', d)
149 data.setVar('T', '${TMPDIR}/', d)
150 build.exec_func("__anonfunc", d)
153 data.setVar('T', t, d)
155 bb.debug(1, "executing anonymous function: %s" % e)
157 data.delVar("__anonqueue", d)
158 data.delVar("__anonfunc", d)
159 set_additional_vars(fn, d, include)
163 for var in data.keys(d):
164 # try to add the handler
165 # if we added it remember the choiche
166 if data.getVarFlag(var, 'handler', d):
167 handler = data.getVar(var,d)
168 if bb.event.register(var,handler) == bb.event.Registered:
169 all_handlers[var] = handler
173 if not data.getVarFlag(var, 'task', d):
176 deps = data.getVarFlag(var, 'deps', d) or []
177 postdeps = data.getVarFlag(var, 'postdeps', d) or []
178 bb.build.add_task(var, deps, d)
180 pdeps = data.getVarFlag(p, 'deps', d) or []
182 data.setVarFlag(p, 'deps', pdeps, d)
183 bb.build.add_task(p, pdeps, d)
185 # now add the handlers
186 if not len(all_handlers) == 0:
187 data.setVar('__all_handlers__', all_handlers, d)
191 bb.data.setVar("FILE", oldfile, d)
193 # we have parsed the bb class now
194 if ext == ".bbclass" or ext == ".inc":
195 __parsed_methods__[base_name] = 1
199 def feeder(lineno, s, fn, root, d):
200 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__,__infunc__, __body__, __bbpath_found__, classes, bb, __residue__
204 data.setVar(__infunc__, '\n'.join(__body__), d)
205 data.setVarFlag(__infunc__, "func", 1, d)
206 if __infunc__ == "__anonymous":
207 anonqueue = bb.data.getVar("__anonqueue", d) or []
209 anonitem["content"] = bb.data.getVar("__anonymous", d)
210 anonitem["flags"] = bb.data.getVarFlags("__anonymous", d)
211 anonqueue.append(anonitem)
212 bb.data.setVar("__anonqueue", anonqueue, d)
213 bb.data.delVarFlags("__anonymous", d)
214 bb.data.delVar("__anonymous", d)
222 m = __python_func_regexp__.match(s)
227 # Note we will add root to parsedmethods after having parse
228 # 'this' file. This means we will not parse methods from
230 if not root in __parsed_methods__:
231 text = '\n'.join(__body__)
232 methodpool.insert_method( root, text, fn )
233 funcs = data.getVar('__functions__', d) or {}
234 if not funcs.has_key( root ):
237 funcs[root] = "%s\n%s" % (funcs[root], text)
239 data.setVar('__functions__', funcs, d)
245 if s == '' or s[0] == '#': return # skip comments and empty lines
248 __residue__.append(s[:-1])
251 s = "".join(__residue__) + s
254 m = __func_start_regexp__.match(s)
256 __infunc__ = m.group("func") or "__anonymous"
258 if data.getVar(key, d):
259 # clean up old version of this piece of metadata, as its
260 # flags could cause problems
261 data.setVarFlag(key, 'python', None, d)
262 data.setVarFlag(key, 'fakeroot', None, d)
263 if m.group("py") is not None:
264 data.setVarFlag(key, "python", "1", d)
266 data.delVarFlag(key, "python", d)
267 if m.group("fr") is not None:
268 data.setVarFlag(key, "fakeroot", "1", d)
270 data.delVarFlag(key, "fakeroot", d)
273 m = __def_regexp__.match(s)
279 m = __export_func_regexp__.match(s)
282 n = __word__.findall(fns)
286 allvars.append(classes[-1] + "_" + f)
288 vars = [[ allvars[0], allvars[1] ]]
289 if len(classes) > 1 and classes[-2] is not None:
290 allvars.append(classes[-2] + "_" + f)
292 vars.append([allvars[2], allvars[1]])
293 vars.append([allvars[0], allvars[2]])
295 for (var, calledvar) in vars:
296 if data.getVar(var, d) and not data.getVarFlag(var, 'export_func', d):
299 if data.getVar(var, d):
300 data.setVarFlag(var, 'python', None, d)
301 data.setVarFlag(var, 'func', None, d)
303 for flag in [ "func", "python" ]:
304 if data.getVarFlag(calledvar, flag, d):
305 data.setVarFlag(var, flag, data.getVarFlag(calledvar, flag, d), d)
306 for flag in [ "dirs" ]:
307 if data.getVarFlag(var, flag, d):
308 data.setVarFlag(calledvar, flag, data.getVarFlag(var, flag, d), d)
310 if data.getVarFlag(calledvar, "python", d):
311 data.setVar(var, "\tbb.build.exec_func('" + calledvar + "', d)\n", d)
313 data.setVar(var, "\t" + calledvar + "\n", d)
314 data.setVarFlag(var, 'export_func', '1', d)
318 m = __addtask_regexp__.match(s)
320 func = m.group("func")
321 before = m.group("before")
322 after = m.group("after")
327 data.setVarFlag(var, "task", 1, d)
329 if after is not None:
330 # set up deps for function
331 data.setVarFlag(var, "deps", after.split(), d)
332 if before is not None:
333 # set up things that depend on this func
334 data.setVarFlag(var, "postdeps", before.split(), d)
337 m = __addhandler_regexp__.match(s)
340 hs = __word__.findall(fns)
342 data.setVarFlag(h, "handler", 1, d)
345 m = __inherit_regexp__.match(s)
349 n = __word__.findall(files)
353 from bb.parse import ConfHandler
354 return ConfHandler.feeder(lineno, s, fn, d)
356 __pkgsplit_cache__={}
357 def vars_from_file(mypkg, d):
359 return (None, None, None)
360 if mypkg in __pkgsplit_cache__:
361 return __pkgsplit_cache__[mypkg]
363 myfile = os.path.splitext(os.path.basename(mypkg))
364 parts = myfile[0].split('_')
365 __pkgsplit_cache__[mypkg] = parts
371 parts.extend(tmplist)
374 def set_additional_vars(file, d, include):
375 """Deduce rest of variables, e.g. ${A} out of ${SRC_URI}"""
377 debug(2,"BB %s: set_additional_vars" % file)
379 src_uri = data.getVar('SRC_URI', d)
382 src_uri = data.expand(src_uri, d)
384 a = data.getVar('A', d)
386 a = data.expand(a, d).split()
392 fetch.init(src_uri.split(), d)
393 except fetch.NoMethodError:
395 except bb.MalformedUrl,e:
396 raise ParseError("Unable to generate local paths for SRC_URI due to malformed uri: %s" % e)
398 a += fetch.localpaths(d)
400 data.setVar('A', " ".join(a), d)
403 # Add us to the handlers list
404 from bb.parse import handlers
405 handlers.append({'supports': supports, 'handle': handle, 'init': init})