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 dname = os.path.dirname(abs_fn)
126 if bbpath[0] != dname:
127 bbpath.insert(0, dname)
128 data.setVar('BBPATH', ":".join(bbpath), d)
131 bb.parse.mark_dependency(d, abs_fn)
133 if ext != ".bbclass":
134 data.setVar('FILE', fn, d)
142 feeder(lineno, s, fn, base_name, d)
144 # add a blank line to close out any python definition
145 feeder(IN_PYTHON_EOF, "", fn, base_name, d)
146 if ext == ".bbclass":
147 classes.remove(__classname__)
152 anonqueue = data.getVar("__anonqueue", d, 1) or []
153 body = [x['content'] for x in anonqueue]
154 flag = { 'python' : 1, 'func' : 1 }
155 data.setVar("__anonfunc", "\n".join(body), d)
156 data.setVarFlags("__anonfunc", flag, d)
159 t = data.getVar('T', d)
160 data.setVar('T', '${TMPDIR}/', d)
161 build.exec_func("__anonfunc", d)
164 data.setVar('T', t, d)
166 bb.msg.debug(1, bb.msg.domain.Parsing, "Exception when executing anonymous function: %s" % e)
168 data.delVar("__anonqueue", d)
169 data.delVar("__anonfunc", d)
170 set_additional_vars(fn, d, include)
174 for var in data.getVar('__BBHANDLERS', d) or []:
175 # try to add the handler
176 handler = data.getVar(var,d)
177 bb.event.register(var, handler)
179 tasklist = data.getVar('__BBTASKS', d) or []
180 bb.build.add_tasks(tasklist, d)
184 bb.data.setVar("FILE", oldfile, d)
186 # we have parsed the bb class now
187 if ext == ".bbclass" or ext == ".inc":
188 __parsed_methods__[base_name] = 1
192 def feeder(lineno, s, fn, root, d):
193 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__,__infunc__, __body__, classes, bb, __residue__
197 data.setVar(__infunc__, '\n'.join(__body__), d)
198 data.setVarFlag(__infunc__, "func", 1, d)
199 if __infunc__ == "__anonymous":
200 anonqueue = bb.data.getVar("__anonqueue", d) or []
202 anonitem["content"] = bb.data.getVar("__anonymous", d)
203 anonitem["flags"] = bb.data.getVarFlags("__anonymous", d)
204 anonqueue.append(anonitem)
205 bb.data.setVar("__anonqueue", anonqueue, d)
206 bb.data.delVarFlags("__anonymous", d)
207 bb.data.delVar("__anonymous", d)
215 m = __python_func_regexp__.match(s)
216 if m and lineno != IN_PYTHON_EOF:
220 # Note we will add root to parsedmethods after having parse
221 # 'this' file. This means we will not parse methods from
223 if not root in __parsed_methods__:
224 text = '\n'.join(__body__)
225 methodpool.insert_method( root, text, fn )
226 funcs = data.getVar('__functions__', d) or {}
227 if not funcs.has_key( root ):
230 funcs[root] = "%s\n%s" % (funcs[root], text)
232 data.setVar('__functions__', funcs, d)
236 if lineno == IN_PYTHON_EOF:
241 if s == '' or s[0] == '#': return # skip comments and empty lines
244 __residue__.append(s[:-1])
247 s = "".join(__residue__) + s
250 m = __func_start_regexp__.match(s)
252 __infunc__ = m.group("func") or "__anonymous"
254 if data.getVar(key, d):
255 # clean up old version of this piece of metadata, as its
256 # flags could cause problems
257 data.setVarFlag(key, 'python', None, d)
258 data.setVarFlag(key, 'fakeroot', None, d)
259 if m.group("py") is not None:
260 data.setVarFlag(key, "python", "1", d)
262 data.delVarFlag(key, "python", d)
263 if m.group("fr") is not None:
264 data.setVarFlag(key, "fakeroot", "1", d)
266 data.delVarFlag(key, "fakeroot", d)
269 m = __def_regexp__.match(s)
275 m = __export_func_regexp__.match(s)
278 n = __word__.findall(fns)
282 allvars.append(classes[-1] + "_" + f)
284 vars = [[ allvars[0], allvars[1] ]]
285 if len(classes) > 1 and classes[-2] is not None:
286 allvars.append(classes[-2] + "_" + f)
288 vars.append([allvars[2], allvars[1]])
289 vars.append([allvars[0], allvars[2]])
291 for (var, calledvar) in vars:
292 if data.getVar(var, d) and not data.getVarFlag(var, 'export_func', d):
295 if data.getVar(var, d):
296 data.setVarFlag(var, 'python', None, d)
297 data.setVarFlag(var, 'func', None, d)
299 for flag in [ "func", "python" ]:
300 if data.getVarFlag(calledvar, flag, d):
301 data.setVarFlag(var, flag, data.getVarFlag(calledvar, flag, d), d)
302 for flag in [ "dirs" ]:
303 if data.getVarFlag(var, flag, d):
304 data.setVarFlag(calledvar, flag, data.getVarFlag(var, flag, d), d)
306 if data.getVarFlag(calledvar, "python", d):
307 data.setVar(var, "\tbb.build.exec_func('" + calledvar + "', d)\n", d)
309 data.setVar(var, "\t" + calledvar + "\n", d)
310 data.setVarFlag(var, 'export_func', '1', d)
314 m = __addtask_regexp__.match(s)
316 func = m.group("func")
317 before = m.group("before")
318 after = m.group("after")
323 data.setVarFlag(var, "task", 1, d)
325 bbtasks = data.getVar('__BBTASKS', d) or []
326 if not var in bbtasks:
328 data.setVar('__BBTASKS', bbtasks, d)
330 existing = data.getVarFlag(var, "deps", d) or []
331 if after is not None:
332 # set up deps for function
333 for entry in after.split():
334 if entry not in existing:
335 existing.append(entry)
336 data.setVarFlag(var, "deps", existing, d)
337 if before is not None:
338 # set up things that depend on this func
339 for entry in before.split():
340 existing = data.getVarFlag(entry, "deps", d) or []
341 if var not in existing:
342 data.setVarFlag(entry, "deps", [var] + existing, d)
345 m = __addhandler_regexp__.match(s)
348 hs = __word__.findall(fns)
349 bbhands = data.getVar('__BBHANDLERS', d) or []
352 data.setVarFlag(h, "handler", 1, d)
353 data.setVar('__BBHANDLERS', bbhands, d)
356 m = __inherit_regexp__.match(s)
360 n = __word__.findall(files)
364 from bb.parse import ConfHandler
365 return ConfHandler.feeder(lineno, s, fn, d)
367 __pkgsplit_cache__={}
368 def vars_from_file(mypkg, d):
370 return (None, None, None)
371 if mypkg in __pkgsplit_cache__:
372 return __pkgsplit_cache__[mypkg]
374 myfile = os.path.splitext(os.path.basename(mypkg))
375 parts = myfile[0].split('_')
376 __pkgsplit_cache__[mypkg] = parts
378 raise ParseError("Unable to generate default variables from the filename: %s (too many underscores)" % mypkg)
384 parts.extend(tmplist)
387 def set_additional_vars(file, d, include):
388 """Deduce rest of variables, e.g. ${A} out of ${SRC_URI}"""
391 # Nothing seems to use this variable
392 #bb.msg.debug(2, bb.msg.domain.Parsing, "BB %s: set_additional_vars" % file)
394 #src_uri = data.getVar('SRC_URI', d, 1)
398 #a = (data.getVar('A', d, 1) or '').split()
400 #from bb import fetch
402 # ud = fetch.init(src_uri.split(), d)
403 # a += fetch.localpaths(d, ud)
404 #except fetch.NoMethodError:
406 #except bb.MalformedUrl,e:
407 # raise ParseError("Unable to generate local paths for SRC_URI due to malformed uri: %s" % e)
410 #data.setVar('A', " ".join(a), d)
413 # Add us to the handlers list
414 from bb.parse import handlers
415 handlers.append({'supports': supports, 'handle': handle, 'init': init})