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, "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
179 for var in data.getVar('__BBTASKS', d) or []:
180 deps = data.getVarFlag(var, 'deps', d) or []
181 postdeps = data.getVarFlag(var, 'postdeps', d) or []
182 bb.build.add_task(var, deps, d)
184 pdeps = data.getVarFlag(p, 'deps', d) or []
186 data.setVarFlag(p, 'deps', pdeps, d)
187 bb.build.add_task(p, pdeps, d)
189 # now add the handlers
190 if not len(all_handlers) == 0:
191 data.setVar('__all_handlers__', all_handlers, d)
195 bb.data.setVar("FILE", oldfile, d)
197 # we have parsed the bb class now
198 if ext == ".bbclass" or ext == ".inc":
199 __parsed_methods__[base_name] = 1
203 def feeder(lineno, s, fn, root, d):
204 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__,__infunc__, __body__, classes, bb, __residue__
208 data.setVar(__infunc__, '\n'.join(__body__), d)
209 data.setVarFlag(__infunc__, "func", 1, d)
210 if __infunc__ == "__anonymous":
211 anonqueue = bb.data.getVar("__anonqueue", d) or []
213 anonitem["content"] = bb.data.getVar("__anonymous", d)
214 anonitem["flags"] = bb.data.getVarFlags("__anonymous", d)
215 anonqueue.append(anonitem)
216 bb.data.setVar("__anonqueue", anonqueue, d)
217 bb.data.delVarFlags("__anonymous", d)
218 bb.data.delVar("__anonymous", d)
226 m = __python_func_regexp__.match(s)
227 if m and lineno != IN_PYTHON_EOF:
231 # Note we will add root to parsedmethods after having parse
232 # 'this' file. This means we will not parse methods from
234 if not root in __parsed_methods__:
235 text = '\n'.join(__body__)
236 methodpool.insert_method( root, text, fn )
237 funcs = data.getVar('__functions__', d) or {}
238 if not funcs.has_key( root ):
241 funcs[root] = "%s\n%s" % (funcs[root], text)
243 data.setVar('__functions__', funcs, d)
247 if lineno == IN_PYTHON_EOF:
252 if s == '' or s[0] == '#': return # skip comments and empty lines
255 __residue__.append(s[:-1])
258 s = "".join(__residue__) + s
261 m = __func_start_regexp__.match(s)
263 __infunc__ = m.group("func") or "__anonymous"
265 if data.getVar(key, d):
266 # clean up old version of this piece of metadata, as its
267 # flags could cause problems
268 data.setVarFlag(key, 'python', None, d)
269 data.setVarFlag(key, 'fakeroot', None, d)
270 if m.group("py") is not None:
271 data.setVarFlag(key, "python", "1", d)
273 data.delVarFlag(key, "python", d)
274 if m.group("fr") is not None:
275 data.setVarFlag(key, "fakeroot", "1", d)
277 data.delVarFlag(key, "fakeroot", d)
280 m = __def_regexp__.match(s)
286 m = __export_func_regexp__.match(s)
289 n = __word__.findall(fns)
293 allvars.append(classes[-1] + "_" + f)
295 vars = [[ allvars[0], allvars[1] ]]
296 if len(classes) > 1 and classes[-2] is not None:
297 allvars.append(classes[-2] + "_" + f)
299 vars.append([allvars[2], allvars[1]])
300 vars.append([allvars[0], allvars[2]])
302 for (var, calledvar) in vars:
303 if data.getVar(var, d) and not data.getVarFlag(var, 'export_func', d):
306 if data.getVar(var, d):
307 data.setVarFlag(var, 'python', None, d)
308 data.setVarFlag(var, 'func', None, d)
310 for flag in [ "func", "python" ]:
311 if data.getVarFlag(calledvar, flag, d):
312 data.setVarFlag(var, flag, data.getVarFlag(calledvar, flag, d), d)
313 for flag in [ "dirs" ]:
314 if data.getVarFlag(var, flag, d):
315 data.setVarFlag(calledvar, flag, data.getVarFlag(var, flag, d), d)
317 if data.getVarFlag(calledvar, "python", d):
318 data.setVar(var, "\tbb.build.exec_func('" + calledvar + "', d)\n", d)
320 data.setVar(var, "\t" + calledvar + "\n", d)
321 data.setVarFlag(var, 'export_func', '1', d)
325 m = __addtask_regexp__.match(s)
327 func = m.group("func")
328 before = m.group("before")
329 after = m.group("after")
334 data.setVarFlag(var, "task", 1, d)
336 bbtasks = data.getVar('__BBTASKS', d) or []
338 data.setVar('__BBTASKS', bbtasks, d)
340 if after is not None:
341 # set up deps for function
342 data.setVarFlag(var, "deps", after.split(), d)
343 if before is not None:
344 # set up things that depend on this func
345 data.setVarFlag(var, "postdeps", before.split(), d)
348 m = __addhandler_regexp__.match(s)
351 hs = __word__.findall(fns)
352 bbhands = data.getVar('__BBHANDLERS', d) or []
355 data.setVarFlag(h, "handler", 1, d)
356 data.setVar('__BBHANDLERS', bbhands, d)
359 m = __inherit_regexp__.match(s)
363 n = __word__.findall(files)
367 from bb.parse import ConfHandler
368 return ConfHandler.feeder(lineno, s, fn, d)
370 __pkgsplit_cache__={}
371 def vars_from_file(mypkg, d):
373 return (None, None, None)
374 if mypkg in __pkgsplit_cache__:
375 return __pkgsplit_cache__[mypkg]
377 myfile = os.path.splitext(os.path.basename(mypkg))
378 parts = myfile[0].split('_')
379 __pkgsplit_cache__[mypkg] = parts
385 parts.extend(tmplist)
388 def set_additional_vars(file, d, include):
389 """Deduce rest of variables, e.g. ${A} out of ${SRC_URI}"""
391 bb.msg.debug(2, bb.msg.domain.Parsing, "BB %s: set_additional_vars" % file)
393 src_uri = data.getVar('SRC_URI', d, 1)
397 a = (data.getVar('A', d, 1) or '').split()
401 fetch.init(src_uri.split(), d)
402 except fetch.NoMethodError:
404 except bb.MalformedUrl,e:
405 raise ParseError("Unable to generate local paths for SRC_URI due to malformed uri: %s" % e)
407 a += fetch.localpaths(d)
409 data.setVar('A', " ".join(a), d)
412 # Add us to the handlers list
413 from bb.parse import handlers
414 handlers.append({'supports': supports, 'handle': handle, 'init': init})