2 # ex:ts=4:sw=4:sts=4:et
3 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
5 # Copyright (C) 2003, 2004 Chris Larson
6 # Copyright (C) 2003, 2004 Phil Blundell
7 # Copyright (C) 2003 - 2005 Michael 'Mickey' Lauer
8 # Copyright (C) 2005 Holger Hans Peter Freyther
9 # Copyright (C) 2005 ROAD GmbH
10 # Copyright (C) 2006 Richard Purdie
12 # This program is free software; you can redistribute it and/or modify it under
13 # the terms of the GNU General Public License as published by the Free Software
14 # Foundation; either version 2 of the License, or (at your option) any later
17 # This program is distributed in the hope that it will be useful, but WITHOUT
18 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License along with
22 # this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23 # Place, Suite 330, Boston, MA 02111-1307 USA.
25 import sys, os, getopt, glob, copy, os.path, re, time
26 sys.path.insert(0,os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
28 from bb import utils, data, parse, event, cache, providers, taskdata, runqueue
30 import itertools, optparse
32 parsespin = itertools.cycle( r'|/-\\' )
36 #============================================================================#
38 #============================================================================#
41 Manage build statistics for one run
50 print "Build statistics:"
51 print " Attempted builds: %d" % self.attempt
53 print " Failed builds: %d" % self.fail
55 print " Dependencies not satisfied: %d" % self.deps
56 if self.fail or self.deps: return 1
60 #============================================================================#
62 #============================================================================#
63 class BBConfiguration( object ):
65 Manages build options and configurations for one run
67 def __init__( self, options ):
68 for key, val in options.__dict__.items():
69 setattr( self, key, val )
71 #============================================================================#
73 #============================================================================#
76 Manages one bitbake build run
79 Statistics = BBStatistics # make it visible from the shell
82 self.build_cache_fail = []
84 self.stats = BBStatistics()
90 def tryBuildPackage(self, fn, item, task, the_data, build_depends):
92 Build one task of a package, optionally build following task depends
94 bb.event.fire(bb.event.PkgStarted(item, the_data))
96 self.stats.attempt += 1
97 if self.configuration.force:
98 bb.data.setVarFlag('do_%s' % task, 'force', 1, the_data)
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)
106 except bb.build.FuncFailed:
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)
112 except bb.build.EventException, e:
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)
120 def tryBuild( self, fn, build_depends):
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
127 the_data = self.bb_cache.loadDataFull(fn, self.configuration.data)
129 item = self.status.pkg_fn[fn]
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)
135 return self.tryBuildPackage(fn, item, self.configuration.cmd, the_data, build_depends)
137 def showVersions( self ):
138 pkg_pn = self.status.pkg_pn
139 preferred_versions = {}
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)
148 pkg_list = pkg_pn.keys()
152 pref = preferred_versions[p]
153 latest = latest_versions[p]
156 prefstr = pref[0][0] + "-" + pref[0][1]
160 print "%-30s %20s %20s" % (p, latest[0][0] + "-" + latest[0][1],
164 def showEnvironment( self ):
165 """Show the outer or per-package environment"""
166 if self.configuration.buildfile:
168 self.bb_cache = bb.cache.init(self)
170 self.configuration.data = self.bb_cache.loadDataFull(self.configuration.buildfile, self.configuration.data)
172 bb.msg.fatal(bb.msg.domain.Parsing, "Unable to read %s: %s" % ( self.configuration.buildfile, e ))
174 bb.msg.fatal(bb.msg.domain.Parsing, "%s" % e)
175 # emit variables and shell functions
177 data.update_data( self.configuration.data )
178 data.emit_env(sys.__stdout__, self.configuration.data, True)
180 bb.msg.fatal(bb.msg.domain.Parsing, "%s" % e)
181 # emit the metadata which isnt valid shell
182 for e in self.configuration.data.keys():
183 if data.getVarFlag( e, 'python', self.configuration.data ):
184 sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, self.configuration.data, 1)))
186 def generateDotGraph( self, pkgs_to_build, ignore_deps ):
188 Generate two graphs one for the DEPENDS and RDEPENDS. The current
189 implementation creates crappy graphs ;)
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
196 def myFilterProvider( providers, item):
198 Take a list of providers and filter according to environment
199 variables. In contrast to filterProviders we do not discriminate
200 and take PREFERRED_PROVIDER into account.
203 preferred_versions = {}
205 # Collate providers by PN
208 pn = self.status.pkg_fn[p]
213 bb.msg.debug(1, bb.msg.domain.Provider, "providers for %s are: %s" % (item, pkg_pn.keys()))
215 for pn in pkg_pn.keys():
216 preferred_versions[pn] = bb.providers.findBestProvider(pn, self.configuration.data, self.status, pkg_pn)[2:4]
217 eligible.append(preferred_versions[pn][1])
220 if p in self.build_cache_fail:
221 bb.msg.debug(1, bb.msg.domain.Provider, "rejecting already-failed %s" % p)
224 if len(eligible) == 0:
225 bb.msg.error(bb.msg.domain.Provider, "no eligible providers for %s" % item)
228 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
230 # try the preferred provider first
233 if prefervar == self.status.pkg_fn[p]:
234 bb.msg.note(1, bb.msg.domain.Provider, "Selecting PREFERRED_PROVIDER %s" % prefervar)
236 eligible = [p] + eligible
241 # try to avoid adding the same rdepends over an over again
246 def add_depends(package_list):
248 Add all depends of all packages from this list
250 for package in package_list:
251 if package in seen_depends or package in ignore_deps:
254 seen_depends.append( package )
255 if not package in self.status.providers:
257 We have not seen this name -> error in
260 bb.msg.note(1, bb.msg.domain.Depends, "ERROR with provider: %(package)s" % vars() )
261 print >> depends_file, '"%(package)s" -> ERROR' % vars()
264 # get all providers for this package
265 providers = self.status.providers[package]
267 # now let us find the bestProvider for it
268 fn = myFilterProvider(providers, package)[0]
270 depends = bb.utils.explode_deps(self.bb_cache.getVar('DEPENDS', fn, True) or "")
271 version = self.bb_cache.getVar('PV', fn, True ) + '-' + self.bb_cache.getVar('PR', fn, True)
272 add_depends ( depends )
274 # now create the node
275 print >> depends_file, '"%(package)s" [label="%(package)s\\n%(version)s"]' % vars()
277 depends = filter( (lambda x: x not in ignore_deps), depends )
278 for depend in depends:
279 print >> depends_file, '"%(package)s" -> "%(depend)s"' % vars()
282 def add_all_depends( the_depends, the_rdepends ):
284 Add both DEPENDS and RDEPENDS. RDEPENDS will get dashed
287 package_list = the_depends + the_rdepends
288 for package in package_list:
289 if package in seen_rdepends or package in ignore_deps:
292 seen_rdepends.append( package )
294 # Let us find out if the package is a DEPENDS or RDEPENDS
295 # and we will set 'providers' with the avilable providers
297 if package in the_depends:
298 if not package in self.status.providers:
299 bb.msg.note(1, bb.msg.domain.Depends, "ERROR with provider: %(package)s" % vars() )
300 print >> alldepends_file, '"%(package)s" -> ERROR' % vars()
303 providers = self.status.providers[package]
304 elif package in the_rdepends:
305 if len(bb.providers.getRuntimeProviders(self.status, package)) == 0:
306 bb.msg.note(1, bb.msg.domain.Depends, "ERROR with rprovider: %(package)s" % vars() )
307 print >> alldepends_file, '"%(package)s" -> ERROR [style="dashed"]' % vars()
310 providers = bb.providers.getRuntimeProviders(self.status, package)
312 # something went wrong...
313 print "Complete ERROR! %s" % package
316 # now let us find the bestProvider for it
317 fn = myFilterProvider(providers, package)[0]
319 # Now we have a filename let us get the depends and RDEPENDS of it
320 depends = bb.utils.explode_deps(self.bb_cache.getVar('DEPENDS', fn, True) or "")
321 if fn in self.status.rundeps and package in self.status.rundeps[fn]:
322 rdepends= self.status.rundeps[fn][package].keys()
325 version = self.bb_cache.getVar('PV', fn, True ) + '-' + self.bb_cache.getVar('PR', fn, True)
327 # handle all the depends and rdepends of package
328 add_all_depends ( depends, rdepends )
330 # now create the node using package name
331 print >> alldepends_file, '"%(package)s" [label="%(package)s\\n%(version)s"]' % vars()
333 # remove the stuff we want to ignore and add the edges
334 depends = filter( (lambda x: x not in ignore_deps), depends )
335 rdepends = filter( (lambda x: x not in ignore_deps), rdepends )
336 for depend in depends:
337 print >> alldepends_file, '"%(package)s" -> "%(depend)s"' % vars()
338 for depend in rdepends:
339 print >> alldepends_file, '"%(package)s" -> "%(depend)s" [style=dashed]' % vars()
343 depends_file = file('depends.dot', 'w' )
344 print >> depends_file, "digraph depends {"
345 add_depends( pkgs_to_build )
346 print >> depends_file, "}"
348 # Add all depends now
349 alldepends_file = file('alldepends.dot', 'w' )
350 print >> alldepends_file, "digraph alldepends {"
351 add_all_depends( pkgs_to_build, [] )
352 print >> alldepends_file, "}"
354 def buildDepgraph( self ):
355 all_depends = self.status.all_depends
356 pn_provides = self.status.pn_provides
358 localdata = data.createCopy(self.configuration.data)
359 bb.data.update_data(localdata)
361 def calc_bbfile_priority(filename):
362 for (regex, pri) in self.status.bbfile_config_priorities:
363 if regex.match(filename):
367 # Handle PREFERRED_PROVIDERS
368 for p in (bb.data.getVar('PREFERRED_PROVIDERS', localdata, 1) or "").split():
369 (providee, provider) = p.split(':')
370 if providee in self.status.preferred and self.status.preferred[providee] != provider:
371 bb.msg.error(bb.msg.domain.Provider, "conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.status.preferred[providee]))
372 self.status.preferred[providee] = provider
374 # Calculate priorities for each file
375 for p in self.status.pkg_fn.keys():
376 self.status.bbfile_priority[p] = calc_bbfile_priority(p)
378 def buildWorldTargetList(self):
380 Build package list for "bitbake world"
382 all_depends = self.status.all_depends
383 pn_provides = self.status.pn_provides
384 bb.msg.debug(1, bb.msg.domain.Parsing, "collating packages for \"world\"")
385 for f in self.status.possible_world:
387 pn = self.status.pkg_fn[f]
389 for p in pn_provides[pn]:
390 if p.startswith('virtual/'):
391 bb.msg.debug(2, bb.msg.domain.Parsing, "World build skipping %s due to %s provider starting with virtual/" % (f, p))
394 for pf in self.status.providers[p]:
395 if self.status.pkg_fn[pf] != pn:
396 bb.msg.debug(2, bb.msg.domain.Parsing, "World build skipping %s due to both us and %s providing %s" % (f, pf, p))
400 self.status.world_target.add(pn)
402 # drop reference count now
403 self.status.possible_world = None
404 self.status.all_depends = None
406 def myProgressCallback( self, x, y, f, from_cache ):
407 """Update any tty with the progress change"""
408 if os.isatty(sys.stdout.fileno()):
409 sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
413 sys.stdout.write("Parsing .bb files, please wait...")
416 sys.stdout.write("done.")
419 def interactiveMode( self ):
420 """Drop off into a shell"""
423 except ImportError, details:
424 bb.msg.fatal(bb.msg.domain.Parsing, "Sorry, shell not available (%s)" % details )
426 bb.data.update_data( self.configuration.data )
430 def parseConfigurationFile( self, afile ):
432 self.configuration.data = bb.parse.handle( afile, self.configuration.data )
434 # Add the handlers we inherited by INHERIT
435 # we need to do this manually as it is not guranteed
436 # we will pick up these classes... as we only INHERIT
437 # on .inc and .bb files but not on .conf
438 data = bb.data.createCopy( self.configuration.data )
439 inherits = ["base"] + (bb.data.getVar('INHERIT', data, True ) or "").split()
440 for inherit in inherits:
441 data = bb.parse.handle( os.path.join('classes', '%s.bbclass' % inherit ), data, True )
443 # FIXME: This assumes that we included at least one .inc file
444 for var in bb.data.keys(data):
445 if bb.data.getVarFlag(var, 'handler', data):
446 bb.event.register(var,bb.data.getVar(var, data))
449 bb.msg.fatal(bb.msg.domain.Parsing, "Unable to open %s" % afile )
450 except bb.parse.ParseError, details:
451 bb.msg.fatal(bb.msg.domain.Parsing, "Unable to parse %s (%s)" % (afile, details) )
453 def handleCollections( self, collections ):
454 """Handle collections"""
456 collection_list = collections.split()
457 for c in collection_list:
458 regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1)
460 bb.msg.error(bb.msg.domain.Parsing, "BBFILE_PATTERN_%s not defined" % c)
462 priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1)
464 bb.msg.error(bb.msg.domain.Parsing, "BBFILE_PRIORITY_%s not defined" % c)
467 cre = re.compile(regex)
469 bb.msg.error(bb.msg.domain.Parsing, "BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
473 self.status.bbfile_config_priorities.append((cre, pri))
475 bb.msg.error(bb.msg.domain.Parsing, "invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
478 def cook( self, configuration, args ):
480 We are building stuff here. We do the building
481 from here. By default we try to execute task
485 self.configuration = configuration
487 if self.configuration.verbose:
488 bb.msg.set_verbose(True)
490 if self.configuration.debug:
491 bb.msg.set_debug_level(self.configuration.debug)
493 bb.msg.set_debug_level(0)
495 if self.configuration.debug_domains:
496 bb.msg.set_debug_domains(self.configuration.debug_domains)
498 self.configuration.data = bb.data.init()
500 for f in self.configuration.file:
501 self.parseConfigurationFile( f )
503 self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
505 if not self.configuration.cmd:
506 self.configuration.cmd = bb.data.getVar("BB_DEFAULT_TASK", self.configuration.data)
508 # For backwards compatibility - REMOVE ME
509 if not self.configuration.cmd:
510 self.configuration.cmd = "build"
513 # Special updated configuration we use for firing events
515 self.configuration.event_data = bb.data.createCopy(self.configuration.data)
516 bb.data.update_data(self.configuration.event_data)
518 if self.configuration.show_environment:
519 self.showEnvironment()
522 # inject custom variables
523 if not bb.data.getVar("BUILDNAME", self.configuration.data):
524 bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
525 bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data)
527 buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
529 if self.configuration.interactive:
530 self.interactiveMode()
532 if self.configuration.buildfile is not None:
533 bf = os.path.abspath( self.configuration.buildfile )
537 (filelist, masked) = self.collect_bbfiles()
538 regexp = re.compile(self.configuration.buildfile)
543 matches = matches + 1
545 bb.msg.fatal(bb.msg.domain.Parsing, "Unable to match %s (%s matches found)" % (self.configuration.buildfile, matches))
547 bbfile_data = bb.parse.handle(bf, self.configuration.data)
549 item = bb.data.getVar('PN', bbfile_data, 1)
551 self.tryBuildPackage(bf, item, self.configuration.cmd, bbfile_data, True)
552 except bb.build.EventException:
553 bb.msg.error(bb.msg.domain.Build, "Build of '%s' failed" % item )
555 sys.exit( self.stats.show() )
557 # initialise the parsing status now we know we will need deps
558 self.status = bb.cache.CacheData()
560 ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
561 self.status.ignored_dependencies = Set( ignore.split() )
563 self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
567 if not pkgs_to_build:
569 pkgs_to_build.extend(args)
570 if not pkgs_to_build:
571 bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
573 pkgs_to_build = bbpkgs.split()
574 if not pkgs_to_build and not self.configuration.show_versions \
575 and not self.configuration.interactive \
576 and not self.configuration.show_environment:
577 print "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help'"
578 print "for usage information."
581 # Import Psyco if available and not disabled
582 if not self.configuration.disable_psyco:
586 bb.msg.note(1, bb.msg.domain.Collection, "Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
588 psyco.bind( self.parse_bbfiles )
590 bb.msg.note(1, bb.msg.domain.Collection, "You have disabled Psyco. This decreases performance.")
593 bb.msg.debug(1, bb.msg.domain.Collection, "collecting .bb files")
594 (filelist, masked) = self.collect_bbfiles()
595 self.parse_bbfiles(filelist, masked, self.myProgressCallback)
596 bb.msg.debug(1, bb.msg.domain.Collection, "parsing complete")
598 if self.configuration.parse_only:
599 bb.msg.note(1, bb.msg.domain.Collection, "Requested parsing .bb files only. Exiting.")
605 if self.configuration.show_versions:
608 if 'world' in pkgs_to_build:
609 self.buildWorldTargetList()
610 pkgs_to_build.remove('world')
611 for t in self.status.world_target:
612 pkgs_to_build.append(t)
614 if self.configuration.dot_graph:
615 self.generateDotGraph( pkgs_to_build, self.configuration.ignored_dot_deps )
618 bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.event_data))
620 taskdata = bb.taskdata.TaskData()
624 for k in pkgs_to_build:
625 taskdata.add_provider(self.configuration.data, self.status, k)
626 runlist.append([k, "do_%s" % self.configuration.cmd])
627 taskdata.add_unresolved(self.configuration.data, self.status)
628 except bb.providers.NoProvider:
631 rq = bb.runqueue.RunQueue()
632 rq.prepare_runqueue(self.configuration.data, self.status, taskdata, runlist)
634 failures = rq.execute_runqueue(self, self.configuration.data, self.status, taskdata, runlist)
635 except runqueue.TaskFailure, (fnid, fn, taskname):
636 bb.msg.error(bb.msg.domain.Build, "'%s, %s' failed" % (fn, taskname))
639 bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.event_data, failures))
641 sys.exit( self.stats.show() )
643 except KeyboardInterrupt:
644 bb.msg.note(1, bb.msg.domain.Collection, "KeyboardInterrupt - Build not completed.")
647 def get_bbfiles( self, path = os.getcwd() ):
648 """Get list of default .bb files by reading out the current directory"""
649 contents = os.listdir(path)
652 (root, ext) = os.path.splitext(f)
654 bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
657 def find_bbfiles( self, path ):
658 """Find all the .bb files in a directory (uses find)"""
659 findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
661 finddata = os.popen(findcmd)
664 return finddata.readlines()
666 def collect_bbfiles( self ):
667 """Collect all available .bb build files"""
668 parsed, cached, skipped, masked = 0, 0, 0, 0
669 self.bb_cache = bb.cache.init(self)
671 files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
672 data.setVar("BBFILES", " ".join(files), self.configuration.data)
675 files = self.get_bbfiles()
678 bb.msg.error(bb.msg.domain.Collection, "no files to build.")
683 dirfiles = self.find_bbfiles(f)
687 newfiles += glob.glob(f) or [ f ]
689 bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1)
695 bbmask_compiled = re.compile(bbmask)
696 except sre_constants.error:
697 bb.msg.fatal(bb.msg.domain.Collection, "BBMASK is not a valid regular expression.")
700 for i in xrange( len( newfiles ) ):
702 if bbmask and bbmask_compiled.search(f):
703 bb.msg.debug(1, bb.msg.domain.Collection, "skipping masked file %s" % f)
708 return (finalfiles, masked)
710 def parse_bbfiles(self, filelist, masked, progressCallback = None):
711 parsed, cached, skipped = 0, 0, 0
712 for i in xrange( len( filelist ) ):
715 bb.msg.debug(1, bb.msg.domain.Collection, "parsing %s" % f)
717 # read a file's metadata
719 fromCache, skip = self.bb_cache.loadData(f, self.configuration.data)
722 bb.msg.debug(2, bb.msg.domain.Collection, "skipping %s" % f)
723 self.bb_cache.skip(f)
725 elif fromCache: cached += 1
729 # Disabled by RP as was no longer functional
730 # allow metadata files to add items to BBFILES
731 #data.update_data(self.pkgdata[f])
732 #addbbfiles = self.bb_cache.getVar('BBFILES', f, False) or None
734 # for aof in addbbfiles.split():
735 # if not files.count(aof):
736 # if not os.path.isabs(aof):
737 # aof = os.path.join(os.path.dirname(f),aof)
740 self.bb_cache.handle_data(f, self.status)
742 # now inform the caller
743 if progressCallback is not None:
744 progressCallback( i + 1, len( filelist ), f, fromCache )
747 self.bb_cache.remove(f)
748 bb.msg.error(bb.msg.domain.Collection, "opening %s: %s" % (f, e))
750 except KeyboardInterrupt:
754 self.bb_cache.remove(f)
755 bb.msg.error(bb.msg.domain.Collection, "%s while parsing %s" % (e, f))
757 self.bb_cache.remove(f)
760 if progressCallback is not None:
761 print "\r" # need newline after Handling Bitbake files message
762 bb.msg.note(1, bb.msg.domain.Collection, "Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ))
766 #============================================================================#
768 #============================================================================#
771 parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
772 usage = """%prog [options] [package ...]
774 Executes the specified task (default is 'build') for a given set of BitBake files.
775 It expects that BBFILES is defined, which is a space seperated list of files to
776 be executed. BBFILES does support wildcards.
777 Default BBFILES are the .bb files in the current directory.""" )
779 parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
780 action = "store", dest = "buildfile", default = None )
782 parser.add_option( "-k", "--continue", help = "continue as much as possible after an error. While the target that failed, and those that depend on it, cannot be remade, the other dependencies of these targets can be processed all the same.",
783 action = "store_false", dest = "abort", default = True )
785 parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
786 action = "store_true", dest = "force", default = False )
788 parser.add_option( "-i", "--interactive", help = "drop into the interactive mode also called the BitBake shell.",
789 action = "store_true", dest = "interactive", default = False )
791 parser.add_option( "-c", "--cmd", help = "Specify task to execute. Note that this only executes the specified task for the providee and the packages it depends on, i.e. 'compile' does not implicitly call stage for the dependencies (IOW: use only if you know what you are doing). Depending on the base.bbclass a listtaks tasks is defined and will show available tasks",
792 action = "store", dest = "cmd" )
794 parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
795 action = "append", dest = "file", default = [] )
797 parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
798 action = "store_true", dest = "verbose", default = False )
800 parser.add_option( "-D", "--debug", help = "Increase the debug level. You can specify this more than once.",
801 action = "count", dest="debug", default = 0)
803 parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
804 action = "store_true", dest = "dry_run", default = False )
806 parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
807 action = "store_true", dest = "parse_only", default = False )
809 parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
810 action = "store_true", dest = "disable_psyco", default = False )
812 parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
813 action = "store_true", dest = "show_versions", default = False )
815 parser.add_option( "-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
816 action = "store_true", dest = "show_environment", default = False )
818 parser.add_option( "-g", "--graphviz", help = "emit the dependency trees of the specified packages in the dot syntax",
819 action = "store_true", dest = "dot_graph", default = False )
821 parser.add_option( "-I", "--ignore-deps", help = """Stop processing at the given list of dependencies when generating dependency graphs. This can help to make the graph more appealing""",
822 action = "append", dest = "ignored_dot_deps", default = [] )
824 parser.add_option( "-l", "--log-domains", help = """Show debug logging for the specified logging domains""",
825 action = "append", dest = "debug_domains", default = [] )
828 options, args = parser.parse_args( sys.argv )
831 cooker.cook( BBConfiguration( options ), args[1:] )
835 if __name__ == "__main__":
836 print """WARNING, WARNING, WARNING
837 This is a Bitbake from the Unstable/Development Branch.
838 You might want to use the bitbake-1.6 stable branch (if you are not a BitBake developer or tester). I'm going to sleep 5 seconds now to make sure you see that."""