diff options
author | Richard Purdie <richard@openedhand.com> | 2007-01-08 23:53:01 +0000 |
---|---|---|
committer | Richard Purdie <richard@openedhand.com> | 2007-01-08 23:53:01 +0000 |
commit | f5665d5bfcfb13d01da9e4c7d5046453e80f7baf (patch) | |
tree | b8908549afaf3006bf3763419711090ac999c2a4 /bitbake/bin | |
parent | aec95de5f7dca2afa3a4a0bdb0d4d553c13f680d (diff) | |
download | poky-f5665d5bfcfb13d01da9e4c7d5046453e80f7baf.tar.gz |
bitbake: Sync with upstream.
* File licence headers were sanitised causing most of the diff.
* cooker.py was created from bin/bitbake.
* cvs fetcher port option was added
* The -f force option was fixed to work correctly
* Multiple entries in rrecrdeps are now handled correctly
(allows adding do_deploy to image depends)
git-svn-id: https://svn.o-hand.com/repos/poky/trunk@1129 311d38ba-8fff-0310-9ca6-ca027cbcb966
Diffstat (limited to 'bitbake/bin')
-rwxr-xr-x | bitbake/bin/bbimage | 24 | ||||
-rwxr-xr-x | bitbake/bin/bitbake | 679 | ||||
-rwxr-xr-x | bitbake/bin/bitdoc | 28 |
3 files changed, 41 insertions, 690 deletions
diff --git a/bitbake/bin/bbimage b/bitbake/bin/bbimage index 9adedbfc63..fdc417617b 100755 --- a/bitbake/bin/bbimage +++ b/bitbake/bin/bbimage | |||
@@ -4,18 +4,18 @@ | |||
4 | # | 4 | # |
5 | # Copyright (C) 2003 Chris Larson | 5 | # Copyright (C) 2003 Chris Larson |
6 | # | 6 | # |
7 | # This program is free software; you can redistribute it and/or modify it under | 7 | # This program is free software; you can redistribute it and/or modify |
8 | # the terms of the GNU General Public License as published by the Free Software | 8 | # it under the terms of the GNU General Public License version 2 as |
9 | # Foundation; either version 2 of the License, or (at your option) any later | 9 | # published by the Free Software Foundation. |
10 | # version. | 10 | # |
11 | # | 11 | # This program is distributed in the hope that it will be useful, |
12 | # This program is distributed in the hope that it will be useful, but WITHOUT | 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. | 14 | # GNU General Public License for more details. |
15 | # | 15 | # |
16 | # You should have received a copy of the GNU General Public License along with | 16 | # You should have received a copy of the GNU General Public License along |
17 | # this program; if not, write to the Free Software Foundation, Inc., 59 Temple | 17 | # with this program; if not, write to the Free Software Foundation, Inc., |
18 | # Place, Suite 330, Boston, MA 02111-1307 USA. | 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | 19 | ||
20 | import sys, os | 20 | import sys, os |
21 | sys.path.insert(0,os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib')) | 21 | sys.path.insert(0,os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib')) |
diff --git a/bitbake/bin/bitbake b/bitbake/bin/bitbake index 33e8933c90..001f229331 100755 --- a/bitbake/bin/bitbake +++ b/bitbake/bin/bitbake | |||
@@ -9,55 +9,27 @@ | |||
9 | # Copyright (C) 2005 ROAD GmbH | 9 | # Copyright (C) 2005 ROAD GmbH |
10 | # Copyright (C) 2006 Richard Purdie | 10 | # Copyright (C) 2006 Richard Purdie |
11 | # | 11 | # |
12 | # This program is free software; you can redistribute it and/or modify it under | 12 | # This program is free software; you can redistribute it and/or modify |
13 | # the terms of the GNU General Public License as published by the Free Software | 13 | # it under the terms of the GNU General Public License version 2 as |
14 | # Foundation; either version 2 of the License, or (at your option) any later | 14 | # published by the Free Software Foundation. |
15 | # version. | ||
16 | # | 15 | # |
17 | # This program is distributed in the hope that it will be useful, but WITHOUT | 16 | # This program is distributed in the hope that it will be useful, |
18 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. | 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | # GNU General Public License for more details. | ||
20 | # | 20 | # |
21 | # You should have received a copy of the GNU General Public License along with | 21 | # You should have received a copy of the GNU General Public License along |
22 | # this program; if not, write to the Free Software Foundation, Inc., 59 Temple | 22 | # with this program; if not, write to the Free Software Foundation, Inc., |
23 | # Place, Suite 330, Boston, MA 02111-1307 USA. | 23 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
24 | 24 | ||
25 | import sys, os, getopt, glob, copy, os.path, re, time | 25 | import sys, os, getopt, re, time, optparse |
26 | sys.path.insert(0,os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib')) | 26 | sys.path.insert(0,os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib')) |
27 | import bb | 27 | import bb |
28 | from bb import utils, data, parse, event, cache, providers, taskdata, runqueue | 28 | from bb import cooker |
29 | from sets import Set | ||
30 | import itertools, optparse | ||
31 | |||
32 | parsespin = itertools.cycle( r'|/-\\' ) | ||
33 | 29 | ||
34 | __version__ = "1.7.4" | 30 | __version__ = "1.7.4" |
35 | 31 | ||
36 | #============================================================================# | 32 | #============================================================================# |
37 | # BBStatistics | ||
38 | #============================================================================# | ||
39 | class BBStatistics: | ||
40 | """ | ||
41 | Manage build statistics for one run | ||
42 | """ | ||
43 | def __init__(self ): | ||
44 | self.attempt = 0 | ||
45 | self.success = 0 | ||
46 | self.fail = 0 | ||
47 | self.deps = 0 | ||
48 | |||
49 | def show( self ): | ||
50 | print "Build statistics:" | ||
51 | print " Attempted builds: %d" % self.attempt | ||
52 | if self.fail: | ||
53 | print " Failed builds: %d" % self.fail | ||
54 | if self.deps: | ||
55 | print " Dependencies not satisfied: %d" % self.deps | ||
56 | if self.fail or self.deps: return 1 | ||
57 | else: return 0 | ||
58 | |||
59 | |||
60 | #============================================================================# | ||
61 | # BBOptions | 33 | # BBOptions |
62 | #============================================================================# | 34 | #============================================================================# |
63 | class BBConfiguration( object ): | 35 | class BBConfiguration( object ): |
@@ -68,622 +40,6 @@ class BBConfiguration( object ): | |||
68 | for key, val in options.__dict__.items(): | 40 | for key, val in options.__dict__.items(): |
69 | setattr( self, key, val ) | 41 | setattr( self, key, val ) |
70 | 42 | ||
71 | #============================================================================# | ||
72 | # BBCooker | ||
73 | #============================================================================# | ||
74 | class BBCooker: | ||
75 | """ | ||
76 | Manages one bitbake build run | ||
77 | """ | ||
78 | |||
79 | Statistics = BBStatistics # make it visible from the shell | ||
80 | |||
81 | def __init__( self ): | ||
82 | self.build_cache_fail = [] | ||
83 | self.build_cache = [] | ||
84 | self.stats = BBStatistics() | ||
85 | self.status = None | ||
86 | |||
87 | self.cache = None | ||
88 | self.bb_cache = None | ||
89 | |||
90 | def tryBuildPackage(self, fn, item, task, the_data, build_depends): | ||
91 | """ | ||
92 | Build one task of a package, optionally build following task depends | ||
93 | """ | ||
94 | bb.event.fire(bb.event.PkgStarted(item, the_data)) | ||
95 | try: | ||
96 | self.stats.attempt += 1 | ||
97 | if self.configuration.force: | ||
98 | bb.data.setVarFlag('do_%s' % task, 'force', 1, the_data) | ||
99 | if not build_depends: | ||
100 | bb.data.setVarFlag('do_%s' % task, 'dontrundeps', 1, the_data) | ||
101 | if not self.configuration.dry_run: | ||
102 | bb.build.exec_task('do_%s' % task, the_data) | ||
103 | bb.event.fire(bb.event.PkgSucceeded(item, the_data)) | ||
104 | self.build_cache.append(fn) | ||
105 | return True | ||
106 | except bb.build.FuncFailed: | ||
107 | self.stats.fail += 1 | ||
108 | bb.msg.error(bb.msg.domain.Build, "task stack execution failed") | ||
109 | bb.event.fire(bb.event.PkgFailed(item, the_data)) | ||
110 | self.build_cache_fail.append(fn) | ||
111 | raise | ||
112 | except bb.build.EventException, e: | ||
113 | self.stats.fail += 1 | ||
114 | event = e.args[1] | ||
115 | bb.msg.error(bb.msg.domain.Build, "%s event exception, aborting" % bb.event.getName(event)) | ||
116 | bb.event.fire(bb.event.PkgFailed(item, the_data)) | ||
117 | self.build_cache_fail.append(fn) | ||
118 | raise | ||
119 | |||
120 | def tryBuild( self, fn, build_depends): | ||
121 | """ | ||
122 | Build a provider and its dependencies. | ||
123 | build_depends is a list of previous build dependencies (not runtime) | ||
124 | If build_depends is empty, we're dealing with a runtime depends | ||
125 | """ | ||
126 | |||
127 | the_data = self.bb_cache.loadDataFull(fn, self.configuration.data) | ||
128 | |||
129 | item = self.status.pkg_fn[fn] | ||
130 | |||
131 | if bb.build.stamp_is_current('do_%s' % self.configuration.cmd, the_data) and not self.configuration.force: | ||
132 | self.build_cache.append(fn) | ||
133 | return True | ||
134 | |||
135 | return self.tryBuildPackage(fn, item, self.configuration.cmd, the_data, build_depends) | ||
136 | |||
137 | def showVersions( self ): | ||
138 | pkg_pn = self.status.pkg_pn | ||
139 | preferred_versions = {} | ||
140 | latest_versions = {} | ||
141 | |||
142 | # Sort by priority | ||
143 | for pn in pkg_pn.keys(): | ||
144 | (last_ver,last_file,pref_ver,pref_file) = bb.providers.findBestProvider(pn, self.configuration.data, self.status) | ||
145 | preferred_versions[pn] = (pref_ver, pref_file) | ||
146 | latest_versions[pn] = (last_ver, last_file) | ||
147 | |||
148 | pkg_list = pkg_pn.keys() | ||
149 | pkg_list.sort() | ||
150 | |||
151 | for p in pkg_list: | ||
152 | pref = preferred_versions[p] | ||
153 | latest = latest_versions[p] | ||
154 | |||
155 | if pref != latest: | ||
156 | prefstr = pref[0][0] + "-" + pref[0][1] | ||
157 | else: | ||
158 | prefstr = "" | ||
159 | |||
160 | print "%-30s %20s %20s" % (p, latest[0][0] + "-" + latest[0][1], | ||
161 | prefstr) | ||
162 | |||
163 | |||
164 | def showEnvironment( self ): | ||
165 | """Show the outer or per-package environment""" | ||
166 | if self.configuration.buildfile: | ||
167 | self.cb = None | ||
168 | self.bb_cache = bb.cache.init(self) | ||
169 | try: | ||
170 | self.configuration.data = self.bb_cache.loadDataFull(self.configuration.buildfile, self.configuration.data) | ||
171 | except IOError, e: | ||
172 | bb.msg.fatal(bb.msg.domain.Parsing, "Unable to read %s: %s" % ( self.configuration.buildfile, e )) | ||
173 | except Exception, e: | ||
174 | bb.msg.fatal(bb.msg.domain.Parsing, "%s" % e) | ||
175 | # emit variables and shell functions | ||
176 | try: | ||
177 | data.update_data( self.configuration.data ) | ||
178 | data.emit_env(sys.__stdout__, self.configuration.data, True) | ||
179 | except Exception, e: | ||
180 | bb.msg.fatal(bb.msg.domain.Parsing, "%s" % e) | ||
181 | # emit the metadata which isnt valid shell | ||
182 | data.expandKeys( self.configuration.data ) | ||
183 | for e in self.configuration.data.keys(): | ||
184 | if data.getVarFlag( e, 'python', self.configuration.data ): | ||
185 | sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, self.configuration.data, 1))) | ||
186 | |||
187 | def generateDotGraph( self, pkgs_to_build, ignore_deps ): | ||
188 | """ | ||
189 | Generate a task dependency graph. | ||
190 | |||
191 | pkgs_to_build A list of packages that needs to be built | ||
192 | ignore_deps A list of names where processing of dependencies | ||
193 | should be stopped. e.g. dependencies that get | ||
194 | """ | ||
195 | |||
196 | for dep in ignore_deps: | ||
197 | self.status.ignored_dependencies.add(dep) | ||
198 | |||
199 | localdata = data.createCopy(self.configuration.data) | ||
200 | bb.data.update_data(localdata) | ||
201 | bb.data.expandKeys(localdata) | ||
202 | taskdata = bb.taskdata.TaskData(self.configuration.abort) | ||
203 | |||
204 | runlist = [] | ||
205 | try: | ||
206 | for k in pkgs_to_build: | ||
207 | taskdata.add_provider(localdata, self.status, k) | ||
208 | runlist.append([k, "do_%s" % self.configuration.cmd]) | ||
209 | taskdata.add_unresolved(localdata, self.status) | ||
210 | except bb.providers.NoProvider: | ||
211 | sys.exit(1) | ||
212 | rq = bb.runqueue.RunQueue() | ||
213 | rq.prepare_runqueue(self.configuration.data, self.status, taskdata, runlist) | ||
214 | |||
215 | seen_fnids = [] | ||
216 | depends_file = file('depends.dot', 'w' ) | ||
217 | tdepends_file = file('task-depends.dot', 'w' ) | ||
218 | print >> depends_file, "digraph depends {" | ||
219 | print >> tdepends_file, "digraph depends {" | ||
220 | rq.prio_map.reverse() | ||
221 | for task1 in range(len(rq.runq_fnid)): | ||
222 | task = rq.prio_map[task1] | ||
223 | taskname = rq.runq_task[task] | ||
224 | fnid = rq.runq_fnid[task] | ||
225 | fn = taskdata.fn_index[fnid] | ||
226 | pn = self.status.pkg_fn[fn] | ||
227 | version = self.bb_cache.getVar('PV', fn, True ) + '-' + self.bb_cache.getVar('PR', fn, True) | ||
228 | print >> tdepends_file, '"%s.%s" [label="%s %s\\n%s\\n%s"]' % (pn, taskname, pn, taskname, version, fn) | ||
229 | for dep in rq.runq_depends[task]: | ||
230 | depfn = taskdata.fn_index[rq.runq_fnid[dep]] | ||
231 | deppn = self.status.pkg_fn[depfn] | ||
232 | print >> tdepends_file, '"%s.%s" -> "%s.%s"' % (pn, rq.runq_task[task], deppn, rq.runq_task[dep]) | ||
233 | if fnid not in seen_fnids: | ||
234 | seen_fnids.append(fnid) | ||
235 | packages = [] | ||
236 | print >> depends_file, '"%s" [label="%s %s\\n%s"]' % (pn, pn, version, fn) | ||
237 | for depend in self.status.deps[fn]: | ||
238 | print >> depends_file, '"%s" -> "%s"' % (pn, depend) | ||
239 | rdepends = self.status.rundeps[fn] | ||
240 | for package in rdepends: | ||
241 | for rdepend in rdepends[package]: | ||
242 | print >> depends_file, '"%s" -> "%s" [style=dashed]' % (package, rdepend) | ||
243 | packages.append(package) | ||
244 | rrecs = self.status.runrecs[fn] | ||
245 | for package in rrecs: | ||
246 | for rdepend in rrecs[package]: | ||
247 | print >> depends_file, '"%s" -> "%s" [style=dashed]' % (package, rdepend) | ||
248 | if not package in packages: | ||
249 | packages.append(package) | ||
250 | for package in packages: | ||
251 | if package != pn: | ||
252 | print >> depends_file, '"%s" [label="%s(%s) %s\\n%s"]' % (package, package, pn, version, fn) | ||
253 | for depend in self.status.deps[fn]: | ||
254 | print >> depends_file, '"%s" -> "%s"' % (package, depend) | ||
255 | # Prints a flattened form of the above where subpackages of a package are merged into the main pn | ||
256 | #print >> depends_file, '"%s" [label="%s %s\\n%s\\n%s"]' % (pn, pn, taskname, version, fn) | ||
257 | #for rdep in taskdata.rdepids[fnid]: | ||
258 | # print >> depends_file, '"%s" -> "%s" [style=dashed]' % (pn, taskdata.run_names_index[rdep]) | ||
259 | #for dep in taskdata.depids[fnid]: | ||
260 | # print >> depends_file, '"%s" -> "%s"' % (pn, taskdata.build_names_index[dep]) | ||
261 | print >> depends_file, "}" | ||
262 | print >> tdepends_file, "}" | ||
263 | bb.msg.note(1, bb.msg.domain.Collection, "Dependencies saved to 'depends.dot'") | ||
264 | bb.msg.note(1, bb.msg.domain.Collection, "Task dependencies saved to 'task-depends.dot'") | ||
265 | |||
266 | def buildDepgraph( self ): | ||
267 | all_depends = self.status.all_depends | ||
268 | pn_provides = self.status.pn_provides | ||
269 | |||
270 | localdata = data.createCopy(self.configuration.data) | ||
271 | bb.data.update_data(localdata) | ||
272 | bb.data.expandKeys(localdata) | ||
273 | |||
274 | def calc_bbfile_priority(filename): | ||
275 | for (regex, pri) in self.status.bbfile_config_priorities: | ||
276 | if regex.match(filename): | ||
277 | return pri | ||
278 | return 0 | ||
279 | |||
280 | # Handle PREFERRED_PROVIDERS | ||
281 | for p in (bb.data.getVar('PREFERRED_PROVIDERS', localdata, 1) or "").split(): | ||
282 | (providee, provider) = p.split(':') | ||
283 | if providee in self.status.preferred and self.status.preferred[providee] != provider: | ||
284 | bb.msg.error(bb.msg.domain.Provider, "conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.status.preferred[providee])) | ||
285 | self.status.preferred[providee] = provider | ||
286 | |||
287 | # Calculate priorities for each file | ||
288 | for p in self.status.pkg_fn.keys(): | ||
289 | self.status.bbfile_priority[p] = calc_bbfile_priority(p) | ||
290 | |||
291 | def buildWorldTargetList(self): | ||
292 | """ | ||
293 | Build package list for "bitbake world" | ||
294 | """ | ||
295 | all_depends = self.status.all_depends | ||
296 | pn_provides = self.status.pn_provides | ||
297 | bb.msg.debug(1, bb.msg.domain.Parsing, "collating packages for \"world\"") | ||
298 | for f in self.status.possible_world: | ||
299 | terminal = True | ||
300 | pn = self.status.pkg_fn[f] | ||
301 | |||
302 | for p in pn_provides[pn]: | ||
303 | if p.startswith('virtual/'): | ||
304 | bb.msg.debug(2, bb.msg.domain.Parsing, "World build skipping %s due to %s provider starting with virtual/" % (f, p)) | ||
305 | terminal = False | ||
306 | break | ||
307 | for pf in self.status.providers[p]: | ||
308 | if self.status.pkg_fn[pf] != pn: | ||
309 | bb.msg.debug(2, bb.msg.domain.Parsing, "World build skipping %s due to both us and %s providing %s" % (f, pf, p)) | ||
310 | terminal = False | ||
311 | break | ||
312 | if terminal: | ||
313 | self.status.world_target.add(pn) | ||
314 | |||
315 | # drop reference count now | ||
316 | self.status.possible_world = None | ||
317 | self.status.all_depends = None | ||
318 | |||
319 | def myProgressCallback( self, x, y, f, from_cache ): | ||
320 | """Update any tty with the progress change""" | ||
321 | if os.isatty(sys.stdout.fileno()): | ||
322 | sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) ) | ||
323 | sys.stdout.flush() | ||
324 | else: | ||
325 | if x == 1: | ||
326 | sys.stdout.write("Parsing .bb files, please wait...") | ||
327 | sys.stdout.flush() | ||
328 | if x == y: | ||
329 | sys.stdout.write("done.") | ||
330 | sys.stdout.flush() | ||
331 | |||
332 | def interactiveMode( self ): | ||
333 | """Drop off into a shell""" | ||
334 | try: | ||
335 | from bb import shell | ||
336 | except ImportError, details: | ||
337 | bb.msg.fatal(bb.msg.domain.Parsing, "Sorry, shell not available (%s)" % details ) | ||
338 | else: | ||
339 | bb.data.update_data( self.configuration.data ) | ||
340 | bb.data.expandKeys( self.configuration.data ) | ||
341 | shell.start( self ) | ||
342 | sys.exit( 0 ) | ||
343 | |||
344 | def parseConfigurationFile( self, afile ): | ||
345 | try: | ||
346 | self.configuration.data = bb.parse.handle( afile, self.configuration.data ) | ||
347 | |||
348 | # Add the handlers we inherited by INHERIT | ||
349 | # we need to do this manually as it is not guranteed | ||
350 | # we will pick up these classes... as we only INHERIT | ||
351 | # on .inc and .bb files but not on .conf | ||
352 | data = bb.data.createCopy( self.configuration.data ) | ||
353 | inherits = ["base"] + (bb.data.getVar('INHERIT', data, True ) or "").split() | ||
354 | for inherit in inherits: | ||
355 | data = bb.parse.handle( os.path.join('classes', '%s.bbclass' % inherit ), data, True ) | ||
356 | |||
357 | # FIXME: This assumes that we included at least one .inc file | ||
358 | for var in bb.data.keys(data): | ||
359 | if bb.data.getVarFlag(var, 'handler', data): | ||
360 | bb.event.register(var,bb.data.getVar(var, data)) | ||
361 | |||
362 | except IOError: | ||
363 | bb.msg.fatal(bb.msg.domain.Parsing, "Unable to open %s" % afile ) | ||
364 | except bb.parse.ParseError, details: | ||
365 | bb.msg.fatal(bb.msg.domain.Parsing, "Unable to parse %s (%s)" % (afile, details) ) | ||
366 | |||
367 | def handleCollections( self, collections ): | ||
368 | """Handle collections""" | ||
369 | if collections: | ||
370 | collection_list = collections.split() | ||
371 | for c in collection_list: | ||
372 | regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1) | ||
373 | if regex == None: | ||
374 | bb.msg.error(bb.msg.domain.Parsing, "BBFILE_PATTERN_%s not defined" % c) | ||
375 | continue | ||
376 | priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1) | ||
377 | if priority == None: | ||
378 | bb.msg.error(bb.msg.domain.Parsing, "BBFILE_PRIORITY_%s not defined" % c) | ||
379 | continue | ||
380 | try: | ||
381 | cre = re.compile(regex) | ||
382 | except re.error: | ||
383 | bb.msg.error(bb.msg.domain.Parsing, "BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex)) | ||
384 | continue | ||
385 | try: | ||
386 | pri = int(priority) | ||
387 | self.status.bbfile_config_priorities.append((cre, pri)) | ||
388 | except ValueError: | ||
389 | bb.msg.error(bb.msg.domain.Parsing, "invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority)) | ||
390 | |||
391 | |||
392 | def cook( self, configuration, args ): | ||
393 | """ | ||
394 | We are building stuff here. We do the building | ||
395 | from here. By default we try to execute task | ||
396 | build. | ||
397 | """ | ||
398 | |||
399 | self.configuration = configuration | ||
400 | |||
401 | if self.configuration.verbose: | ||
402 | bb.msg.set_verbose(True) | ||
403 | |||
404 | if self.configuration.debug: | ||
405 | bb.msg.set_debug_level(self.configuration.debug) | ||
406 | else: | ||
407 | bb.msg.set_debug_level(0) | ||
408 | |||
409 | if self.configuration.debug_domains: | ||
410 | bb.msg.set_debug_domains(self.configuration.debug_domains) | ||
411 | |||
412 | self.configuration.data = bb.data.init() | ||
413 | |||
414 | for f in self.configuration.file: | ||
415 | self.parseConfigurationFile( f ) | ||
416 | |||
417 | self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) ) | ||
418 | |||
419 | if not self.configuration.cmd: | ||
420 | self.configuration.cmd = bb.data.getVar("BB_DEFAULT_TASK", self.configuration.data) | ||
421 | |||
422 | # For backwards compatibility - REMOVE ME | ||
423 | if not self.configuration.cmd: | ||
424 | self.configuration.cmd = "build" | ||
425 | |||
426 | # | ||
427 | # Special updated configuration we use for firing events | ||
428 | # | ||
429 | self.configuration.event_data = bb.data.createCopy(self.configuration.data) | ||
430 | bb.data.update_data(self.configuration.event_data) | ||
431 | |||
432 | if self.configuration.show_environment: | ||
433 | self.showEnvironment() | ||
434 | sys.exit( 0 ) | ||
435 | |||
436 | # inject custom variables | ||
437 | if not bb.data.getVar("BUILDNAME", self.configuration.data): | ||
438 | bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data) | ||
439 | bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data) | ||
440 | |||
441 | buildname = bb.data.getVar("BUILDNAME", self.configuration.data) | ||
442 | |||
443 | if self.configuration.interactive: | ||
444 | self.interactiveMode() | ||
445 | |||
446 | if self.configuration.buildfile is not None: | ||
447 | bf = os.path.abspath( self.configuration.buildfile ) | ||
448 | try: | ||
449 | os.stat(bf) | ||
450 | except OSError: | ||
451 | (filelist, masked) = self.collect_bbfiles() | ||
452 | regexp = re.compile(self.configuration.buildfile) | ||
453 | matches = [] | ||
454 | for f in filelist: | ||
455 | if regexp.search(f) and os.path.isfile(f): | ||
456 | bf = f | ||
457 | matches.append(f) | ||
458 | if len(matches) != 1: | ||
459 | bb.msg.error(bb.msg.domain.Parsing, "Unable to match %s (%s matches found):" % (self.configuration.buildfile, len(matches))) | ||
460 | for f in matches: | ||
461 | bb.msg.error(bb.msg.domain.Parsing, " %s" % f) | ||
462 | sys.exit(1) | ||
463 | bf = matches[0] | ||
464 | |||
465 | bbfile_data = bb.parse.handle(bf, self.configuration.data) | ||
466 | |||
467 | item = bb.data.getVar('PN', bbfile_data, 1) | ||
468 | try: | ||
469 | self.tryBuildPackage(bf, item, self.configuration.cmd, bbfile_data, True) | ||
470 | except bb.build.EventException: | ||
471 | bb.msg.error(bb.msg.domain.Build, "Build of '%s' failed" % item ) | ||
472 | |||
473 | sys.exit( self.stats.show() ) | ||
474 | |||
475 | # initialise the parsing status now we know we will need deps | ||
476 | self.status = bb.cache.CacheData() | ||
477 | |||
478 | ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or "" | ||
479 | self.status.ignored_dependencies = Set( ignore.split() ) | ||
480 | |||
481 | self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) ) | ||
482 | |||
483 | pkgs_to_build = None | ||
484 | if args: | ||
485 | if not pkgs_to_build: | ||
486 | pkgs_to_build = [] | ||
487 | pkgs_to_build.extend(args) | ||
488 | if not pkgs_to_build: | ||
489 | bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1) | ||
490 | if bbpkgs: | ||
491 | pkgs_to_build = bbpkgs.split() | ||
492 | if not pkgs_to_build and not self.configuration.show_versions \ | ||
493 | and not self.configuration.interactive \ | ||
494 | and not self.configuration.show_environment: | ||
495 | print "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help'" | ||
496 | print "for usage information." | ||
497 | sys.exit(0) | ||
498 | |||
499 | # Import Psyco if available and not disabled | ||
500 | if not self.configuration.disable_psyco: | ||
501 | try: | ||
502 | import psyco | ||
503 | except ImportError: | ||
504 | bb.msg.note(1, bb.msg.domain.Collection, "Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.") | ||
505 | else: | ||
506 | psyco.bind( self.parse_bbfiles ) | ||
507 | else: | ||
508 | bb.msg.note(1, bb.msg.domain.Collection, "You have disabled Psyco. This decreases performance.") | ||
509 | |||
510 | try: | ||
511 | bb.msg.debug(1, bb.msg.domain.Collection, "collecting .bb files") | ||
512 | (filelist, masked) = self.collect_bbfiles() | ||
513 | self.parse_bbfiles(filelist, masked, self.myProgressCallback) | ||
514 | bb.msg.debug(1, bb.msg.domain.Collection, "parsing complete") | ||
515 | |||
516 | if self.configuration.parse_only: | ||
517 | bb.msg.note(1, bb.msg.domain.Collection, "Requested parsing .bb files only. Exiting.") | ||
518 | return | ||
519 | |||
520 | |||
521 | self.buildDepgraph() | ||
522 | |||
523 | if self.configuration.show_versions: | ||
524 | self.showVersions() | ||
525 | sys.exit( 0 ) | ||
526 | if 'world' in pkgs_to_build: | ||
527 | self.buildWorldTargetList() | ||
528 | pkgs_to_build.remove('world') | ||
529 | for t in self.status.world_target: | ||
530 | pkgs_to_build.append(t) | ||
531 | |||
532 | if self.configuration.dot_graph: | ||
533 | self.generateDotGraph( pkgs_to_build, self.configuration.ignored_dot_deps ) | ||
534 | sys.exit( 0 ) | ||
535 | |||
536 | bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.event_data)) | ||
537 | |||
538 | localdata = data.createCopy(self.configuration.data) | ||
539 | bb.data.update_data(localdata) | ||
540 | bb.data.expandKeys(localdata) | ||
541 | |||
542 | taskdata = bb.taskdata.TaskData(self.configuration.abort) | ||
543 | |||
544 | runlist = [] | ||
545 | try: | ||
546 | for k in pkgs_to_build: | ||
547 | taskdata.add_provider(localdata, self.status, k) | ||
548 | runlist.append([k, "do_%s" % self.configuration.cmd]) | ||
549 | taskdata.add_unresolved(localdata, self.status) | ||
550 | except bb.providers.NoProvider: | ||
551 | sys.exit(1) | ||
552 | |||
553 | rq = bb.runqueue.RunQueue() | ||
554 | rq.prepare_runqueue(self.configuration.data, self.status, taskdata, runlist) | ||
555 | try: | ||
556 | failures = rq.execute_runqueue(self, self.configuration.data, self.status, taskdata, runlist) | ||
557 | except runqueue.TaskFailure, fnids: | ||
558 | for fnid in fnids: | ||
559 | bb.msg.error(bb.msg.domain.Build, "'%s' failed" % taskdata.fn_index[fnid]) | ||
560 | sys.exit(1) | ||
561 | bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.event_data, failures)) | ||
562 | |||
563 | sys.exit( self.stats.show() ) | ||
564 | |||
565 | except KeyboardInterrupt: | ||
566 | bb.msg.note(1, bb.msg.domain.Collection, "KeyboardInterrupt - Build not completed.") | ||
567 | sys.exit(1) | ||
568 | |||
569 | def get_bbfiles( self, path = os.getcwd() ): | ||
570 | """Get list of default .bb files by reading out the current directory""" | ||
571 | contents = os.listdir(path) | ||
572 | bbfiles = [] | ||
573 | for f in contents: | ||
574 | (root, ext) = os.path.splitext(f) | ||
575 | if ext == ".bb": | ||
576 | bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f))) | ||
577 | return bbfiles | ||
578 | |||
579 | def find_bbfiles( self, path ): | ||
580 | """Find all the .bb files in a directory (uses find)""" | ||
581 | findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/' | ||
582 | try: | ||
583 | finddata = os.popen(findcmd) | ||
584 | except OSError: | ||
585 | return [] | ||
586 | return finddata.readlines() | ||
587 | |||
588 | def collect_bbfiles( self ): | ||
589 | """Collect all available .bb build files""" | ||
590 | parsed, cached, skipped, masked = 0, 0, 0, 0 | ||
591 | self.bb_cache = bb.cache.init(self) | ||
592 | |||
593 | files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split() | ||
594 | data.setVar("BBFILES", " ".join(files), self.configuration.data) | ||
595 | |||
596 | if not len(files): | ||
597 | files = self.get_bbfiles() | ||
598 | |||
599 | if not len(files): | ||
600 | bb.msg.error(bb.msg.domain.Collection, "no files to build.") | ||
601 | |||
602 | newfiles = [] | ||
603 | for f in files: | ||
604 | if os.path.isdir(f): | ||
605 | dirfiles = self.find_bbfiles(f) | ||
606 | if dirfiles: | ||
607 | newfiles += dirfiles | ||
608 | continue | ||
609 | newfiles += glob.glob(f) or [ f ] | ||
610 | |||
611 | bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1) | ||
612 | |||
613 | if not bbmask: | ||
614 | return (newfiles, 0) | ||
615 | |||
616 | try: | ||
617 | bbmask_compiled = re.compile(bbmask) | ||
618 | except sre_constants.error: | ||
619 | bb.msg.fatal(bb.msg.domain.Collection, "BBMASK is not a valid regular expression.") | ||
620 | |||
621 | finalfiles = [] | ||
622 | for i in xrange( len( newfiles ) ): | ||
623 | f = newfiles[i] | ||
624 | if bbmask and bbmask_compiled.search(f): | ||
625 | bb.msg.debug(1, bb.msg.domain.Collection, "skipping masked file %s" % f) | ||
626 | masked += 1 | ||
627 | continue | ||
628 | finalfiles.append(f) | ||
629 | |||
630 | return (finalfiles, masked) | ||
631 | |||
632 | def parse_bbfiles(self, filelist, masked, progressCallback = None): | ||
633 | parsed, cached, skipped = 0, 0, 0 | ||
634 | for i in xrange( len( filelist ) ): | ||
635 | f = filelist[i] | ||
636 | |||
637 | bb.msg.debug(1, bb.msg.domain.Collection, "parsing %s" % f) | ||
638 | |||
639 | # read a file's metadata | ||
640 | try: | ||
641 | fromCache, skip = self.bb_cache.loadData(f, self.configuration.data) | ||
642 | if skip: | ||
643 | skipped += 1 | ||
644 | bb.msg.debug(2, bb.msg.domain.Collection, "skipping %s" % f) | ||
645 | self.bb_cache.skip(f) | ||
646 | continue | ||
647 | elif fromCache: cached += 1 | ||
648 | else: parsed += 1 | ||
649 | deps = None | ||
650 | |||
651 | # Disabled by RP as was no longer functional | ||
652 | # allow metadata files to add items to BBFILES | ||
653 | #data.update_data(self.pkgdata[f]) | ||
654 | #addbbfiles = self.bb_cache.getVar('BBFILES', f, False) or None | ||
655 | #if addbbfiles: | ||
656 | # for aof in addbbfiles.split(): | ||
657 | # if not files.count(aof): | ||
658 | # if not os.path.isabs(aof): | ||
659 | # aof = os.path.join(os.path.dirname(f),aof) | ||
660 | # files.append(aof) | ||
661 | |||
662 | self.bb_cache.handle_data(f, self.status) | ||
663 | |||
664 | # now inform the caller | ||
665 | if progressCallback is not None: | ||
666 | progressCallback( i + 1, len( filelist ), f, fromCache ) | ||
667 | |||
668 | except IOError, e: | ||
669 | self.bb_cache.remove(f) | ||
670 | bb.msg.error(bb.msg.domain.Collection, "opening %s: %s" % (f, e)) | ||
671 | pass | ||
672 | except KeyboardInterrupt: | ||
673 | self.bb_cache.sync() | ||
674 | raise | ||
675 | except Exception, e: | ||
676 | self.bb_cache.remove(f) | ||
677 | bb.msg.error(bb.msg.domain.Collection, "%s while parsing %s" % (e, f)) | ||
678 | except: | ||
679 | self.bb_cache.remove(f) | ||
680 | raise | ||
681 | |||
682 | if progressCallback is not None: | ||
683 | print "\r" # need newline after Handling Bitbake files message | ||
684 | bb.msg.note(1, bb.msg.domain.Collection, "Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked )) | ||
685 | |||
686 | self.bb_cache.sync() | ||
687 | 43 | ||
688 | #============================================================================# | 44 | #============================================================================# |
689 | # main | 45 | # main |
@@ -747,12 +103,13 @@ Default BBFILES are the .bb files in the current directory.""" ) | |||
747 | action = "append", dest = "debug_domains", default = [] ) | 103 | action = "append", dest = "debug_domains", default = [] ) |
748 | 104 | ||
749 | 105 | ||
750 | options, args = parser.parse_args( sys.argv ) | 106 | options, args = parser.parse_args(sys.argv) |
751 | |||
752 | cooker = BBCooker() | ||
753 | cooker.cook( BBConfiguration( options ), args[1:] ) | ||
754 | 107 | ||
108 | configuration = BBConfiguration(options) | ||
109 | configuration.pkgs_to_build = [] | ||
110 | configuration.pkgs_to_build.extend(args[1:]) | ||
755 | 111 | ||
112 | bb.cooker.BBCooker().cook(configuration) | ||
756 | 113 | ||
757 | if __name__ == "__main__": | 114 | if __name__ == "__main__": |
758 | main() | 115 | main() |
@@ -761,4 +118,6 @@ if __name__ == "__main__": | |||
761 | profile.run('main()', "profile.log") | 118 | profile.run('main()', "profile.log") |
762 | import pstats | 119 | import pstats |
763 | p = pstats.Stats('profile.log') | 120 | p = pstats.Stats('profile.log') |
121 | p.sort_stats('time') | ||
764 | p.print_stats() | 122 | p.print_stats() |
123 | p.print_callers() | ||
diff --git a/bitbake/bin/bitdoc b/bitbake/bin/bitdoc index e865e1b998..3bcc9b344b 100755 --- a/bitbake/bin/bitdoc +++ b/bitbake/bin/bitdoc | |||
@@ -4,26 +4,18 @@ | |||
4 | # | 4 | # |
5 | # Copyright (C) 2005 Holger Hans Peter Freyther | 5 | # Copyright (C) 2005 Holger Hans Peter Freyther |
6 | # | 6 | # |
7 | # This program is free software; you can redistribute it and/or modify | ||
8 | # it under the terms of the GNU General Public License version 2 as | ||
9 | # published by the Free Software Foundation. | ||
7 | # | 10 | # |
8 | # Permission is hereby granted, free of charge, to any person obtaining a copy | 11 | # This program is distributed in the hope that it will be useful, |
9 | # of this software and associated documentation files (the "Software"), to deal | 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | # in the Software without restriction, including without limitation the rights | 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 14 | # GNU General Public License for more details. |
12 | # copies of the Software, and to permit persons to whom the Software is | ||
13 | # furnished to do so, subject to the following conditions: | ||
14 | # | ||
15 | # The above copyright notice and this permission notice shall be included in all | ||
16 | # copies or substantial portions of the Software. | ||
17 | # | ||
18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
20 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||
21 | # SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, | ||
22 | # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
23 | # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR | ||
24 | # THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
25 | # | ||
26 | # | 15 | # |
16 | # You should have received a copy of the GNU General Public License along | ||
17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
27 | 19 | ||
28 | import optparse, os, sys | 20 | import optparse, os, sys |
29 | 21 | ||