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
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 localfn = localpath(fn, d)
49 return localfn[-3:] == ".bb" or localfn[-8:] == ".bbclass" or localfn[-4:] == ".inc"
51 def inherit(files, d):
52 __inherit_cache = data.getVar('__inherit_cache', d) or ""
56 file = data.expand(f, d)
57 if file[0] != "/" and file[-8:] != ".bbclass":
58 file = os.path.join('classes', '%s.bbclass' % file)
60 if not file in __inherit_cache.split():
61 debug(2, "BB %s:%d: inheriting %s" % (fn, lineno, file))
62 __inherit_cache += " %s" % file
64 data.setVar('__inherit_cache', __inherit_cache, d)
67 def handle(fn, d, include = 0):
68 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __infunc__, __body__, __bbpath_found__, __residue__
76 debug(2, "BB " + fn + ": handle(data)")
78 debug(2, "BB " + fn + ": handle(data, include)")
80 (root, ext) = os.path.splitext(os.path.basename(fn))
85 classes.append(__classname__)
88 oldfile = data.getVar('FILE', d)
93 bbpath = (data.getVar('BBPATH', d, 1) or '').split(':')
94 if not os.path.isabs(fn):
98 j = os.path.join(p, fn)
99 if os.access(j, os.R_OK):
104 raise IOError("file not found")
109 if ext != ".bbclass":
110 bbpath.insert(0, os.path.dirname(abs_fn))
111 data.setVar('BBPATH', ":".join(bbpath), d)
114 bb.parse.mark_dependency(d, abs_fn)
116 if ext != ".bbclass":
117 data.setVar('FILE', fn, d)
118 i = (data.getVar("INHERIT", d, 1) or "").split()
119 if not "base" in i and __classname__ != "base":
129 feeder(lineno, s, fn, d)
131 # add a blank line to close out any python definition
132 feeder(lineno + 1, "", fn, d)
133 if ext == ".bbclass":
134 classes.remove(__classname__)
139 anonqueue = data.getVar("__anonqueue", d, 1) or []
140 for anon in anonqueue:
141 data.setVar("__anonfunc", anon["content"], d)
142 data.setVarFlags("__anonfunc", anon["flags"], d)
145 t = data.getVar('T', d)
146 data.setVar('T', '${TMPDIR}/', d)
147 build.exec_func("__anonfunc", d)
150 data.setVar('T', t, d)
152 bb.debug(1, "executing anonymous function: %s" % e)
154 data.delVar("__anonqueue", d)
155 data.delVar("__anonfunc", d)
156 set_additional_vars(fn, d, include)
159 for var in data.keys(d):
160 if data.getVarFlag(var, 'handler', d):
161 bb.event.register(data.getVar(var, d))
164 if not data.getVarFlag(var, 'task', d):
167 deps = data.getVarFlag(var, 'deps', d) or []
168 postdeps = data.getVarFlag(var, 'postdeps', d) or []
169 bb.build.add_task(var, deps, d)
171 pdeps = data.getVarFlag(p, 'deps', d) or []
173 data.setVarFlag(p, 'deps', pdeps, d)
174 bb.build.add_task(p, pdeps, d)
177 bb.data.setVar("FILE", oldfile, d)
180 def feeder(lineno, s, fn, d):
181 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__
185 data.setVar(__infunc__, '\n'.join(__body__), d)
186 data.setVarFlag(__infunc__, "func", 1, d)
187 if __infunc__ == "__anonymous":
188 anonqueue = bb.data.getVar("__anonqueue", d) or []
190 anonitem["content"] = bb.data.getVar("__anonymous", d)
191 anonitem["flags"] = bb.data.getVarFlags("__anonymous", d)
192 anonqueue.append(anonitem)
193 bb.data.setVar("__anonqueue", anonqueue, d)
194 bb.data.delVarFlags("__anonymous", d)
195 bb.data.delVar("__anonymous", d)
203 m = __python_func_regexp__.match(s)
208 text = '\n'.join(__body__)
209 comp = bb.utils.better_compile(text, "<bb>", fn )
210 bb.utils.better_exec(comp, __builtins__, text, fn)
213 funcs = data.getVar('__functions__', d) or ""
214 data.setVar('__functions__', "%s\n%s" % (funcs, text), d)
217 if s == '' or s[0] == '#': return # skip comments and empty lines
220 __residue__.append(s[:-1])
223 s = "".join(__residue__) + s
226 m = __func_start_regexp__.match(s)
228 __infunc__ = m.group("func") or "__anonymous"
230 if data.getVar(key, d):
231 # clean up old version of this piece of metadata, as its
232 # flags could cause problems
233 data.setVarFlag(key, 'python', None, d)
234 data.setVarFlag(key, 'fakeroot', None, d)
235 if m.group("py") is not None:
236 data.setVarFlag(key, "python", "1", d)
238 data.delVarFlag(key, "python", d)
239 if m.group("fr") is not None:
240 data.setVarFlag(key, "fakeroot", "1", d)
242 data.delVarFlag(key, "fakeroot", d)
245 m = __def_regexp__.match(s)
251 m = __export_func_regexp__.match(s)
254 n = __word__.findall(fns)
258 allvars.append(classes[-1] + "_" + f)
260 vars = [[ allvars[0], allvars[1] ]]
261 if len(classes) > 1 and classes[-2] is not None:
262 allvars.append(classes[-2] + "_" + f)
264 vars.append([allvars[2], allvars[1]])
265 vars.append([allvars[0], allvars[2]])
267 for (var, calledvar) in vars:
268 if data.getVar(var, d) and not data.getVarFlag(var, 'export_func', d):
271 if data.getVar(var, d):
272 data.setVarFlag(var, 'python', None, d)
273 data.setVarFlag(var, 'func', None, d)
275 for flag in [ "func", "python" ]:
276 if data.getVarFlag(calledvar, flag, d):
277 data.setVarFlag(var, flag, data.getVarFlag(calledvar, flag, d), d)
278 for flag in [ "dirs" ]:
279 if data.getVarFlag(var, flag, d):
280 data.setVarFlag(calledvar, flag, data.getVarFlag(var, flag, d), d)
282 if data.getVarFlag(calledvar, "python", d):
283 data.setVar(var, "\tbb.build.exec_func('" + calledvar + "', d)\n", d)
285 data.setVar(var, "\t" + calledvar + "\n", d)
286 data.setVarFlag(var, 'export_func', '1', d)
290 m = __addtask_regexp__.match(s)
292 func = m.group("func")
293 before = m.group("before")
294 after = m.group("after")
299 data.setVarFlag(var, "task", 1, d)
301 if after is not None:
302 # set up deps for function
303 data.setVarFlag(var, "deps", after.split(), d)
304 if before is not None:
305 # set up things that depend on this func
306 data.setVarFlag(var, "postdeps", before.split(), d)
309 m = __addhandler_regexp__.match(s)
312 hs = __word__.findall(fns)
314 data.setVarFlag(h, "handler", 1, d)
317 m = __inherit_regexp__.match(s)
321 n = __word__.findall(files)
325 from bb.parse import ConfHandler
326 return ConfHandler.feeder(lineno, s, fn, d)
328 __pkgsplit_cache__={}
329 def vars_from_file(mypkg, d):
331 return (None, None, None)
332 if mypkg in __pkgsplit_cache__:
333 return __pkgsplit_cache__[mypkg]
335 myfile = os.path.splitext(os.path.basename(mypkg))
336 parts = myfile[0].split('_')
337 __pkgsplit_cache__[mypkg] = parts
343 parts.extend(tmplist)
346 def set_additional_vars(file, d, include):
347 """Deduce rest of variables, e.g. ${A} out of ${SRC_URI}"""
349 debug(2,"BB %s: set_additional_vars" % file)
351 src_uri = data.getVar('SRC_URI', d)
354 src_uri = data.expand(src_uri, d)
356 a = data.getVar('A', d)
358 a = data.expand(a, d).split()
364 fetch.init(src_uri.split(), d)
365 except fetch.NoMethodError:
367 except bb.MalformedUrl,e:
368 raise ParseError("Unable to generate local paths for SRC_URI due to malformed uri: %s" % e)
370 a += fetch.localpaths(d)
372 data.setVar('A', " ".join(a), d)
375 # Add us to the handlers list
376 from bb.parse import handlers
377 handlers.append({'supports': supports, 'handle': handle, 'init': init})