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 | ||
