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
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+")
48 # A cache of parsed bbclasses. We will use this cache to make a
49 # decision if we should compile and execute a method.
50 # This dict contains a list of classes which might have methods
51 # we have already added.
53 __parsed_methods__ = {}
56 localfn = localpath(fn, d)
57 return localfn[-3:] == ".bb" or localfn[-8:] == ".bbclass" or localfn[-4:] == ".inc"
59 def inherit(files, d):
60 __inherit_cache = data.getVar('__inherit_cache', d) or ""
64 file = data.expand(f, d)
65 if file[0] != "/" and file[-8:] != ".bbclass":
66 file = os.path.join('classes', '%s.bbclass' % file)
68 if not file in __inherit_cache.split():
69 debug(2, "BB %s:%d: inheriting %s" % (fn, lineno, file))
70 __inherit_cache += " %s" % file
72 data.setVar('__inherit_cache', __inherit_cache, d)
75 def handle(fn, d, include = 0):
76 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __infunc__, __body__, __bbpath_found__, __residue__
84 debug(2, "BB " + fn + ": handle(data)")
86 debug(2, "BB " + fn + ": handle(data, include)")
88 (root, ext) = os.path.splitext(os.path.basename(fn))
89 base_name = "%s%s" % (root,ext)
94 classes.append(__classname__)
97 oldfile = data.getVar('FILE', d)
102 bbpath = (data.getVar('BBPATH', d, 1) or '').split(':')
103 if not os.path.isabs(fn):
106 p = data.expand(p, d)
107 j = os.path.join(p, fn)
108 if os.access(j, os.R_OK):
113 raise IOError("file not found")
118 if ext != ".bbclass":
119 bbpath.insert(0, os.path.dirname(abs_fn))
120 data.setVar('BBPATH', ":".join(bbpath), d)
123 bb.parse.mark_dependency(d, abs_fn)
125 if ext != ".bbclass":
126 data.setVar('FILE', fn, d)
127 i = (data.getVar("INHERIT", d, 1) or "").split()
128 if not "base" in i and __classname__ != "base":
138 feeder(lineno, s, fn, base_name, d)
140 # add a blank line to close out any python definition
141 feeder(lineno + 1, "", fn, base_name, d)
142 if ext == ".bbclass":
143 classes.remove(__classname__)
148 anonqueue = data.getVar("__anonqueue", d, 1) or []
149 for anon in anonqueue:
150 data.setVar("__anonfunc", anon["content"], d)
151 data.setVarFlags("__anonfunc", anon["flags"], d)
154 t = data.getVar('T', d)
155 data.setVar('T', '${TMPDIR}/', d)
156 build.exec_func("__anonfunc", d)
159 data.setVar('T', t, d)
161 bb.debug(1, "executing anonymous function: %s" % e)
163 data.delVar("__anonqueue", d)
164 data.delVar("__anonfunc", d)
165 set_additional_vars(fn, d, include)
168 for var in data.keys(d):
169 if data.getVarFlag(var, 'handler', d):
170 bb.event.register(var, data.getVar(var, d))
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)
186 bb.data.setVar("FILE", oldfile, d)
188 # we have parsed the bb class now
189 if ext == ".bbclass" or ext == ".inc":
190 __parsed_methods__[base_name] = 1
194 def feeder(lineno, s, fn, root, d):
195 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__
199 data.setVar(__infunc__, '\n'.join(__body__), d)
200 data.setVarFlag(__infunc__, "func", 1, d)
201 if __infunc__ == "__anonymous":
202 anonqueue = bb.data.getVar("__anonqueue", d) or []
204 anonitem["content"] = bb.data.getVar("__anonymous", d)
205 anonitem["flags"] = bb.data.getVarFlags("__anonymous", d)
206 anonqueue.append(anonitem)
207 bb.data.setVar("__anonqueue", anonqueue, d)
208 bb.data.delVarFlags("__anonymous", d)
209 bb.data.delVar("__anonymous", d)
217 m = __python_func_regexp__.match(s)
222 if not root in __parsed_methods__:
223 text = '\n'.join(__body__)
224 comp = bb.utils.better_compile(text, "<bb>", fn )
225 bb.utils.better_exec(comp, __builtins__, text, fn)
226 funcs = data.getVar('__functions__', d) or ""
227 data.setVar('__functions__', "%s\n%s" % (funcs, text), d)
233 if s == '' or s[0] == '#': return # skip comments and empty lines
236 __residue__.append(s[:-1])
239 s = "".join(__residue__) + s
242 m = __func_start_regexp__.match(s)
244 __infunc__ = m.group("func") or "__anonymous"
246 if data.getVar(key, d):
247 # clean up old version of this piece of metadata, as its
248 # flags could cause problems
249 data.setVarFlag(key, 'python', None, d)
250 data.setVarFlag(key, 'fakeroot', None, d)
251 if m.group("py") is not None:
252 data.setVarFlag(key, "python", "1", d)
254 data.delVarFlag(key, "python", d)
255 if m.group("fr") is not None:
256 data.setVarFlag(key, "fakeroot", "1", d)
258 data.delVarFlag(key, "fakeroot", d)
261 m = __def_regexp__.match(s)
267 m = __export_func_regexp__.match(s)
270 n = __word__.findall(fns)
274 allvars.append(classes[-1] + "_" + f)
276 vars = [[ allvars[0], allvars[1] ]]
277 if len(classes) > 1 and classes[-2] is not None:
278 allvars.append(classes[-2] + "_" + f)
280 vars.append([allvars[2], allvars[1]])
281 vars.append([allvars[0], allvars[2]])
283 for (var, calledvar) in vars:
284 if data.getVar(var, d) and not data.getVarFlag(var, 'export_func', d):
287 if data.getVar(var, d):
288 data.setVarFlag(var, 'python', None, d)
289 data.setVarFlag(var, 'func', None, d)
291 for flag in [ "func", "python" ]:
292 if data.getVarFlag(calledvar, flag, d):
293 data.setVarFlag(var, flag, data.getVarFlag(calledvar, flag, d), d)
294 for flag in [ "dirs" ]:
295 if data.getVarFlag(var, flag, d):
296 data.setVarFlag(calledvar, flag, data.getVarFlag(var, flag, d), d)
298 if data.getVarFlag(calledvar, "python", d):
299 data.setVar(var, "\tbb.build.exec_func('" + calledvar + "', d)\n", d)
301 data.setVar(var, "\t" + calledvar + "\n", d)
302 data.setVarFlag(var, 'export_func', '1', d)
306 m = __addtask_regexp__.match(s)
308 func = m.group("func")
309 before = m.group("before")
310 after = m.group("after")
315 data.setVarFlag(var, "task", 1, d)
317 if after is not None:
318 # set up deps for function
319 data.setVarFlag(var, "deps", after.split(), d)
320 if before is not None:
321 # set up things that depend on this func
322 data.setVarFlag(var, "postdeps", before.split(), d)
325 m = __addhandler_regexp__.match(s)
328 hs = __word__.findall(fns)
330 data.setVarFlag(h, "handler", 1, d)
333 m = __inherit_regexp__.match(s)
337 n = __word__.findall(files)
341 from bb.parse import ConfHandler
342 return ConfHandler.feeder(lineno, s, fn, d)
344 __pkgsplit_cache__={}
345 def vars_from_file(mypkg, d):
347 return (None, None, None)
348 if mypkg in __pkgsplit_cache__:
349 return __pkgsplit_cache__[mypkg]
351 myfile = os.path.splitext(os.path.basename(mypkg))
352 parts = myfile[0].split('_')
353 __pkgsplit_cache__[mypkg] = parts
359 parts.extend(tmplist)
362 def set_additional_vars(file, d, include):
363 """Deduce rest of variables, e.g. ${A} out of ${SRC_URI}"""
365 debug(2,"BB %s: set_additional_vars" % file)
367 src_uri = data.getVar('SRC_URI', d)
370 src_uri = data.expand(src_uri, d)
372 a = data.getVar('A', d)
374 a = data.expand(a, d).split()
380 fetch.init(src_uri.split(), d)
381 except fetch.NoMethodError:
383 except bb.MalformedUrl,e:
384 raise ParseError("Unable to generate local paths for SRC_URI due to malformed uri: %s" % e)
386 a += fetch.localpaths(d)
388 data.setVar('A', " ".join(a), d)
391 # Add us to the handlers list
392 from bb.parse import handlers
393 handlers.append({'supports': supports, 'handle': handle, 'init': init})