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__)
98 __inherit_cache = data.getVar('__inherit_cache', d) or []
99 if not fn in __inherit_cache:
100 __inherit_cache.append(fn)
101 data.setVar('__inherit_cache', __inherit_cache, d)
104 oldfile = data.getVar('FILE', d)
109 bbpath = (data.getVar('BBPATH', d, 1) or '').split(':')
110 if not os.path.isabs(fn):
113 j = os.path.join(p, fn)
114 if os.access(j, os.R_OK):
119 raise IOError("file not found")
124 if ext != ".bbclass":
125 bbpath.insert(0, os.path.dirname(abs_fn))
126 data.setVar('BBPATH', ":".join(bbpath), d)
129 bb.parse.mark_dependency(d, abs_fn)
131 if ext != ".bbclass":
132 data.setVar('FILE', fn, d)
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 handler = data.getVar(var,d)
175 bb.event.register(var, handler)
177 tasklist = data.getVar('__BBTASKS', d) or []
178 bb.build.add_tasks(tasklist, d)
182 bb.data.setVar("FILE", oldfile, d)
184 # we have parsed the bb class now
185 if ext == ".bbclass" or ext == ".inc":
186 __parsed_methods__[base_name] = 1
190 def feeder(lineno, s, fn, root, d):
191 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__,__infunc__, __body__, classes, bb, __residue__
195 data.setVar(__infunc__, '\n'.join(__body__), d)
196 data.setVarFlag(__infunc__, "func", 1, d)
197 if __infunc__ == "__anonymous":
198 anonqueue = bb.data.getVar("__anonqueue", d) or []
200 anonitem["content"] = bb.data.getVar("__anonymous", d)
201 anonitem["flags"] = bb.data.getVarFlags("__anonymous", d)
202 anonqueue.append(anonitem)
203 bb.data.setVar("__anonqueue", anonqueue, d)
204 bb.data.delVarFlags("__anonymous", d)
205 bb.data.delVar("__anonymous", d)
213 m = __python_func_regexp__.match(s)
214 if m and lineno != IN_PYTHON_EOF:
218 # Note we will add root to parsedmethods after having parse
219 # 'this' file. This means we will not parse methods from
221 if not root in __parsed_methods__:
222 text = '\n'.join(__body__)
223 methodpool.insert_method( root, text, fn )
224 funcs = data.getVar('__functions__', d) or {}
225 if not funcs.has_key( root ):
228 funcs[root] = "%s\n%s" % (funcs[root], text)
230 data.setVar('__functions__', funcs, d)
234 if lineno == IN_PYTHON_EOF:
239 if s == '' or s[0] == '#': return # skip comments and empty lines
242 __residue__.append(s[:-1])
245 s = "".join(__residue__) + s
248 m = __func_start_regexp__.match(s)
250 __infunc__ = m.group("func") or "__anonymous"
252 if data.getVar(key, d):
253 # clean up old version of this piece of metadata, as its
254 # flags could cause problems
255 data.setVarFlag(key, 'python', None, d)
256 data.setVarFlag(key, 'fakeroot', None, d)
257 if m.group("py") is not None:
258 data.setVarFlag(key, "python", "1", d)
260 data.delVarFlag(key, "python", d)
261 if m.group("fr") is not None:
262 data.setVarFlag(key, "fakeroot", "1", d)
264 data.delVarFlag(key, "fakeroot", d)
267 m = __def_regexp__.match(s)
273 m = __export_func_regexp__.match(s)
276 n = __word__.findall(fns)
280 allvars.append(classes[-1] + "_" + f)
282 vars = [[ allvars[0], allvars[1] ]]
283 if len(classes) > 1 and classes[-2] is not None:
284 allvars.append(classes[-2] + "_" + f)
286 vars.append([allvars[2], allvars[1]])
287 vars.append([allvars[0], allvars[2]])
289 for (var, calledvar) in vars:
290 if data.getVar(var, d) and not data.getVarFlag(var, 'export_func', d):
293 if data.getVar(var, d):
294 data.setVarFlag(var, 'python', None, d)
295 data.setVarFlag(var, 'func', None, d)
297 for flag in [ "func", "python" ]:
298 if data.getVarFlag(calledvar, flag, d):
299 data.setVarFlag(var, flag, data.getVarFlag(calledvar, flag, d), d)
300 for flag in [ "dirs" ]:
301 if data.getVarFlag(var, flag, d):
302 data.setVarFlag(calledvar, flag, data.getVarFlag(var, flag, d), d)
304 if data.getVarFlag(calledvar, "python", d):
305 data.setVar(var, "\tbb.build.exec_func('" + calledvar + "', d)\n", d)
307 data.setVar(var, "\t" + calledvar + "\n", d)
308 data.setVarFlag(var, 'export_func', '1', d)
312 m = __addtask_regexp__.match(s)
314 func = m.group("func")
315 before = m.group("before")
316 after = m.group("after")
321 data.setVarFlag(var, "task", 1, d)
323 bbtasks = data.getVar('__BBTASKS', d) or []
324 if not var in bbtasks:
326 data.setVar('__BBTASKS', bbtasks, d)
328 existing = data.getVarFlag(var, "deps", d) or []
329 if after is not None:
330 # set up deps for function
331 for entry in after.split():
332 if entry not in existing:
333 existing.append(entry)
334 data.setVarFlag(var, "deps", existing, d)
335 if before is not None:
336 # set up things that depend on this func
337 for entry in before.split():
338 existing = data.getVarFlag(entry, "deps", d) or []
339 if var not in existing:
340 data.setVarFlag(entry, "deps", [var] + existing, d)
343 m = __addhandler_regexp__.match(s)
346 hs = __word__.findall(fns)
347 bbhands = data.getVar('__BBHANDLERS', d) or []
350 data.setVarFlag(h, "handler", 1, d)
351 data.setVar('__BBHANDLERS', bbhands, d)
354 m = __inherit_regexp__.match(s)
358 n = __word__.findall(files)
362 from bb.parse import ConfHandler
363 return ConfHandler.feeder(lineno, s, fn, d)
365 __pkgsplit_cache__={}
366 def vars_from_file(mypkg, d):
368 return (None, None, None)
369 if mypkg in __pkgsplit_cache__:
370 return __pkgsplit_cache__[mypkg]
372 myfile = os.path.splitext(os.path.basename(mypkg))
373 parts = myfile[0].split('_')
374 __pkgsplit_cache__[mypkg] = parts
376 raise ParseError("Unable to generate default variables from the filename: %s (too many underscores)" % mypkg)
382 parts.extend(tmplist)
385 def set_additional_vars(file, d, include):
386 """Deduce rest of variables, e.g. ${A} out of ${SRC_URI}"""
389 # Nothing seems to use this variable
390 #bb.msg.debug(2, bb.msg.domain.Parsing, "BB %s: set_additional_vars" % file)
392 #src_uri = data.getVar('SRC_URI', d, 1)
396 #a = (data.getVar('A', d, 1) or '').split()
398 #from bb import fetch
400 # ud = fetch.init(src_uri.split(), d)
401 # a += fetch.localpaths(d, ud)
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)
408 #data.setVar('A', " ".join(a), d)
411 # Add us to the handlers list
412 from bb.parse import handlers
413 handlers.append({'supports': supports, 'handle': handle, 'init': init})