2 # ex:ts=4:sw=4:sts=4:et
3 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
5 class for handling .bb files
7 Reads a .bb file and obtains its metadata
12 # Copyright (C) 2003, 2004 Chris Larson
13 # Copyright (C) 2003, 2004 Phil Blundell
15 # This program is free software; you can redistribute it and/or modify
16 # it under the terms of the GNU General Public License version 2 as
17 # published by the Free Software Foundation.
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
24 # You should have received a copy of the GNU General Public License along
25 # with this program; if not, write to the Free Software Foundation, Inc.,
26 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 import re, bb, os, sys, time
29 import bb.fetch, bb.build, bb.utils
30 from bb import data, fetch, methodpool
32 from ConfHandler import include, localpath, obtain, init
33 from bb.parse import ParseError
35 __func_start_regexp__ = re.compile( r"(((?P<py>python)|(?P<fr>fakeroot))\s*)*(?P<func>[\w\.\-\+\{\}\$]+)?\s*\(\s*\)\s*{$" )
36 __inherit_regexp__ = re.compile( r"inherit\s+(.+)" )
37 __export_func_regexp__ = re.compile( r"EXPORT_FUNCTIONS\s+(.+)" )
38 __addtask_regexp__ = re.compile("addtask\s+(?P<func>\w+)\s*((before\s*(?P<before>((.*(?=after))|(.*))))|(after\s*(?P<after>((.*(?=before))|(.*)))))*")
39 __addhandler_regexp__ = re.compile( r"addhandler\s+(.+)" )
40 __def_regexp__ = re.compile( r"def\s+(\w+).*:" )
41 __python_func_regexp__ = re.compile( r"(\s+.*)|(^$)" )
42 __word__ = re.compile(r"\S+")
50 # We need to indicate EOF to the feeder. This code is so messy that
51 # factoring it out to a close_parse_file method is out of question.
52 # We will use the IN_PYTHON_EOF as an indicator to just close the method
54 # The two parts using it are tightly integrated anyway
55 IN_PYTHON_EOF = -9999999999999
57 __parsed_methods__ = methodpool.get_parsed_dict()
60 localfn = localpath(fn, d)
61 return localfn[-3:] == ".bb" or localfn[-8:] == ".bbclass" or localfn[-4:] == ".inc"
63 def inherit(files, d):
64 __inherit_cache = data.getVar('__inherit_cache', d) or []
67 files = data.expand(files, d)
69 if file[0] != "/" and file[-8:] != ".bbclass":
70 file = os.path.join('classes', '%s.bbclass' % file)
72 if not file in __inherit_cache:
73 bb.msg.debug(2, bb.msg.domain.Parsing, "BB %s:%d: inheriting %s" % (fn, lineno, file))
74 __inherit_cache.append( file )
75 data.setVar('__inherit_cache', __inherit_cache, d)
76 include(fn, file, d, "inherit")
77 __inherit_cache = data.getVar('__inherit_cache', d) or []
79 def handle(fn, d, include = 0):
80 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __infunc__, __body__, __residue__
87 bb.msg.debug(2, bb.msg.domain.Parsing, "BB " + fn + ": handle(data)")
89 bb.msg.debug(2, bb.msg.domain.Parsing, "BB " + fn + ": handle(data, include)")
91 (root, ext) = os.path.splitext(os.path.basename(fn))
92 base_name = "%s%s" % (root,ext)
97 classes.append(__classname__)
100 oldfile = data.getVar('FILE', d)
105 bbpath = (data.getVar('BBPATH', d, 1) or '').split(':')
106 if not os.path.isabs(fn):
109 j = os.path.join(p, fn)
110 if os.access(j, os.R_OK):
115 raise IOError("file not found")
120 if ext != ".bbclass":
121 bbpath.insert(0, os.path.dirname(abs_fn))
122 data.setVar('BBPATH', ":".join(bbpath), d)
125 bb.parse.mark_dependency(d, abs_fn)
127 if ext != ".bbclass":
128 data.setVar('FILE', fn, d)
129 i = (data.getVar("INHERIT", d, 1) or "").split()
130 if not "base" in i and __classname__ != "base":
140 feeder(lineno, s, fn, base_name, d)
142 # add a blank line to close out any python definition
143 feeder(IN_PYTHON_EOF, "", fn, base_name, d)
144 if ext == ".bbclass":
145 classes.remove(__classname__)
150 anonqueue = data.getVar("__anonqueue", d, 1) or []
151 body = [x['content'] for x in anonqueue]
152 flag = { 'python' : 1, 'func' : 1 }
153 data.setVar("__anonfunc", "\n".join(body), d)
154 data.setVarFlags("__anonfunc", flag, d)
157 t = data.getVar('T', d)
158 data.setVar('T', '${TMPDIR}/', d)
159 build.exec_func("__anonfunc", d)
162 data.setVar('T', t, d)
164 bb.msg.debug(1, bb.msg.domain.Parsing, "Exception when executing anonymous function: %s" % e)
166 data.delVar("__anonqueue", d)
167 data.delVar("__anonfunc", d)
168 set_additional_vars(fn, d, include)
172 for var in data.getVar('__BBHANDLERS', d) or []:
173 # try to add the handler
174 # if we added it remember the choiche
175 handler = data.getVar(var,d)
176 if bb.event.register(var,handler) == bb.event.Registered:
177 all_handlers[var] = handler
180 for var in data.getVar('__BBTASKS', d) or []:
181 if var not in tasklist:
183 deps = data.getVarFlag(var, 'deps', d) or []
185 if p not in tasklist[var]:
186 tasklist[var].append(p)
188 postdeps = data.getVarFlag(var, 'postdeps', d) or []
190 if p not in tasklist:
192 if var not in tasklist[p]:
193 tasklist[p].append(var)
195 bb.build.add_tasks(tasklist, d)
197 # now add the handlers
198 if not len(all_handlers) == 0:
199 data.setVar('__all_handlers__', all_handlers, d)
203 bb.data.setVar("FILE", oldfile, d)
205 # we have parsed the bb class now
206 if ext == ".bbclass" or ext == ".inc":
207 __parsed_methods__[base_name] = 1
211 def feeder(lineno, s, fn, root, d):
212 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__,__infunc__, __body__, classes, bb, __residue__
216 data.setVar(__infunc__, '\n'.join(__body__), d)
217 data.setVarFlag(__infunc__, "func", 1, d)
218 if __infunc__ == "__anonymous":
219 anonqueue = bb.data.getVar("__anonqueue", d) or []
221 anonitem["content"] = bb.data.getVar("__anonymous", d)
222 anonitem["flags"] = bb.data.getVarFlags("__anonymous", d)
223 anonqueue.append(anonitem)
224 bb.data.setVar("__anonqueue", anonqueue, d)
225 bb.data.delVarFlags("__anonymous", d)
226 bb.data.delVar("__anonymous", d)
234 m = __python_func_regexp__.match(s)
235 if m and lineno != IN_PYTHON_EOF:
239 # Note we will add root to parsedmethods after having parse
240 # 'this' file. This means we will not parse methods from
242 if not root in __parsed_methods__:
243 text = '\n'.join(__body__)
244 methodpool.insert_method( root, text, fn )
245 funcs = data.getVar('__functions__', d) or {}
246 if not funcs.has_key( root ):
249 funcs[root] = "%s\n%s" % (funcs[root], text)
251 data.setVar('__functions__', funcs, d)
255 if lineno == IN_PYTHON_EOF:
260 if s == '' or s[0] == '#': return # skip comments and empty lines
263 __residue__.append(s[:-1])
266 s = "".join(__residue__) + s
269 m = __func_start_regexp__.match(s)
271 __infunc__ = m.group("func") or "__anonymous"
273 if data.getVar(key, d):
274 # clean up old version of this piece of metadata, as its
275 # flags could cause problems
276 data.setVarFlag(key, 'python', None, d)
277 data.setVarFlag(key, 'fakeroot', None, d)
278 if m.group("py") is not None:
279 data.setVarFlag(key, "python", "1", d)
281 data.delVarFlag(key, "python", d)
282 if m.group("fr") is not None:
283 data.setVarFlag(key, "fakeroot", "1", d)
285 data.delVarFlag(key, "fakeroot", d)
288 m = __def_regexp__.match(s)
294 m = __export_func_regexp__.match(s)
297 n = __word__.findall(fns)
301 allvars.append(classes[-1] + "_" + f)
303 vars = [[ allvars[0], allvars[1] ]]
304 if len(classes) > 1 and classes[-2] is not None:
305 allvars.append(classes[-2] + "_" + f)
307 vars.append([allvars[2], allvars[1]])
308 vars.append([allvars[0], allvars[2]])
310 for (var, calledvar) in vars:
311 if data.getVar(var, d) and not data.getVarFlag(var, 'export_func', d):
314 if data.getVar(var, d):
315 data.setVarFlag(var, 'python', None, d)
316 data.setVarFlag(var, 'func', None, d)
318 for flag in [ "func", "python" ]:
319 if data.getVarFlag(calledvar, flag, d):
320 data.setVarFlag(var, flag, data.getVarFlag(calledvar, flag, d), d)
321 for flag in [ "dirs" ]:
322 if data.getVarFlag(var, flag, d):
323 data.setVarFlag(calledvar, flag, data.getVarFlag(var, flag, d), d)
325 if data.getVarFlag(calledvar, "python", d):
326 data.setVar(var, "\tbb.build.exec_func('" + calledvar + "', d)\n", d)
328 data.setVar(var, "\t" + calledvar + "\n", d)
329 data.setVarFlag(var, 'export_func', '1', d)
333 m = __addtask_regexp__.match(s)
335 func = m.group("func")
336 before = m.group("before")
337 after = m.group("after")
342 data.setVarFlag(var, "task", 1, d)
344 bbtasks = data.getVar('__BBTASKS', d) or []
346 data.setVar('__BBTASKS', bbtasks, d)
348 if after is not None:
349 # set up deps for function
350 data.setVarFlag(var, "deps", after.split(), d)
351 if before is not None:
352 # set up things that depend on this func
353 data.setVarFlag(var, "postdeps", before.split(), d)
356 m = __addhandler_regexp__.match(s)
359 hs = __word__.findall(fns)
360 bbhands = data.getVar('__BBHANDLERS', d) or []
363 data.setVarFlag(h, "handler", 1, d)
364 data.setVar('__BBHANDLERS', bbhands, d)
367 m = __inherit_regexp__.match(s)
371 n = __word__.findall(files)
375 from bb.parse import ConfHandler
376 return ConfHandler.feeder(lineno, s, fn, d)
378 __pkgsplit_cache__={}
379 def vars_from_file(mypkg, d):
381 return (None, None, None)
382 if mypkg in __pkgsplit_cache__:
383 return __pkgsplit_cache__[mypkg]
385 myfile = os.path.splitext(os.path.basename(mypkg))
386 parts = myfile[0].split('_')
387 __pkgsplit_cache__[mypkg] = parts
389 raise ParseError("Unable to generate default variables from the filename: %s (too many underscores)" % mypkg)
395 parts.extend(tmplist)
398 def set_additional_vars(file, d, include):
399 """Deduce rest of variables, e.g. ${A} out of ${SRC_URI}"""
402 # Nothing seems to use this variable
403 #bb.msg.debug(2, bb.msg.domain.Parsing, "BB %s: set_additional_vars" % file)
405 #src_uri = data.getVar('SRC_URI', d, 1)
409 #a = (data.getVar('A', d, 1) or '').split()
411 #from bb import fetch
413 # ud = fetch.init(src_uri.split(), d)
414 # a += fetch.localpaths(d, ud)
415 #except fetch.NoMethodError:
417 #except bb.MalformedUrl,e:
418 # raise ParseError("Unable to generate local paths for SRC_URI due to malformed uri: %s" % e)
421 #data.setVar('A', " ".join(a), d)
424 # Add us to the handlers list
425 from bb.parse import handlers
426 handlers.append({'supports': supports, 'handle': handle, 'init': init})