|
@@ -9,54 +9,26 @@
|
|
|
# Copyright (C) 2005 ROAD GmbH
|
|
|
# Copyright (C) 2006 Richard Purdie
|
|
|
#
|
|
|
-# This program is free software; you can redistribute it and/or modify it under
|
|
|
-# the terms of the GNU General Public License as published by the Free Software
|
|
|
-# Foundation; either version 2 of the License, or (at your option) any later
|
|
|
-# version.
|
|
|
+# This program is free software; you can redistribute it and/or modify
|
|
|
+# it under the terms of the GNU General Public License version 2 as
|
|
|
+# published by the Free Software Foundation.
|
|
|
#
|
|
|
-# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
-# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
+# This program is distributed in the hope that it will be useful,
|
|
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
+# GNU General Public License for more details.
|
|
|
#
|
|
|
-# You should have received a copy of the GNU General Public License along with
|
|
|
-# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
|
-# Place, Suite 330, Boston, MA 02111-1307 USA.
|
|
|
+# You should have received a copy of the GNU General Public License along
|
|
|
+# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
|
|
-import sys, os, getopt, glob, copy, os.path, re, time
|
|
|
+import sys, os, getopt, re, time, optparse
|
|
|
sys.path.insert(0,os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
|
|
|
import bb
|
|
|
-from bb import utils, data, parse, event, cache, providers, taskdata, runqueue
|
|
|
-from sets import Set
|
|
|
-import itertools, optparse
|
|
|
-
|
|
|
-parsespin = itertools.cycle( r'|/-\\' )
|
|
|
+from bb import cooker
|
|
|
|
|
|
__version__ = "1.7.4"
|
|
|
|
|
|
-#============================================================================#
|
|
|
-# BBStatistics
|
|
|
-#============================================================================#
|
|
|
-class BBStatistics:
|
|
|
- """
|
|
|
- Manage build statistics for one run
|
|
|
- """
|
|
|
- def __init__(self ):
|
|
|
- self.attempt = 0
|
|
|
- self.success = 0
|
|
|
- self.fail = 0
|
|
|
- self.deps = 0
|
|
|
-
|
|
|
- def show( self ):
|
|
|
- print "Build statistics:"
|
|
|
- print " Attempted builds: %d" % self.attempt
|
|
|
- if self.fail:
|
|
|
- print " Failed builds: %d" % self.fail
|
|
|
- if self.deps:
|
|
|
- print " Dependencies not satisfied: %d" % self.deps
|
|
|
- if self.fail or self.deps: return 1
|
|
|
- else: return 0
|
|
|
-
|
|
|
-
|
|
|
#============================================================================#
|
|
|
# BBOptions
|
|
|
#============================================================================#
|
|
@@ -68,622 +40,6 @@ class BBConfiguration( object ):
|
|
|
for key, val in options.__dict__.items():
|
|
|
setattr( self, key, val )
|
|
|
|
|
|
-#============================================================================#
|
|
|
-# BBCooker
|
|
|
-#============================================================================#
|
|
|
-class BBCooker:
|
|
|
- """
|
|
|
- Manages one bitbake build run
|
|
|
- """
|
|
|
-
|
|
|
- Statistics = BBStatistics # make it visible from the shell
|
|
|
-
|
|
|
- def __init__( self ):
|
|
|
- self.build_cache_fail = []
|
|
|
- self.build_cache = []
|
|
|
- self.stats = BBStatistics()
|
|
|
- self.status = None
|
|
|
-
|
|
|
- self.cache = None
|
|
|
- self.bb_cache = None
|
|
|
-
|
|
|
- def tryBuildPackage(self, fn, item, task, the_data, build_depends):
|
|
|
- """
|
|
|
- Build one task of a package, optionally build following task depends
|
|
|
- """
|
|
|
- bb.event.fire(bb.event.PkgStarted(item, the_data))
|
|
|
- try:
|
|
|
- self.stats.attempt += 1
|
|
|
- if self.configuration.force:
|
|
|
- bb.data.setVarFlag('do_%s' % task, 'force', 1, the_data)
|
|
|
- if not build_depends:
|
|
|
- bb.data.setVarFlag('do_%s' % task, 'dontrundeps', 1, the_data)
|
|
|
- if not self.configuration.dry_run:
|
|
|
- bb.build.exec_task('do_%s' % task, the_data)
|
|
|
- bb.event.fire(bb.event.PkgSucceeded(item, the_data))
|
|
|
- self.build_cache.append(fn)
|
|
|
- return True
|
|
|
- except bb.build.FuncFailed:
|
|
|
- self.stats.fail += 1
|
|
|
- bb.msg.error(bb.msg.domain.Build, "task stack execution failed")
|
|
|
- bb.event.fire(bb.event.PkgFailed(item, the_data))
|
|
|
- self.build_cache_fail.append(fn)
|
|
|
- raise
|
|
|
- except bb.build.EventException, e:
|
|
|
- self.stats.fail += 1
|
|
|
- event = e.args[1]
|
|
|
- bb.msg.error(bb.msg.domain.Build, "%s event exception, aborting" % bb.event.getName(event))
|
|
|
- bb.event.fire(bb.event.PkgFailed(item, the_data))
|
|
|
- self.build_cache_fail.append(fn)
|
|
|
- raise
|
|
|
-
|
|
|
- def tryBuild( self, fn, build_depends):
|
|
|
- """
|
|
|
- Build a provider and its dependencies.
|
|
|
- build_depends is a list of previous build dependencies (not runtime)
|
|
|
- If build_depends is empty, we're dealing with a runtime depends
|
|
|
- """
|
|
|
-
|
|
|
- the_data = self.bb_cache.loadDataFull(fn, self.configuration.data)
|
|
|
-
|
|
|
- item = self.status.pkg_fn[fn]
|
|
|
-
|
|
|
- if bb.build.stamp_is_current('do_%s' % self.configuration.cmd, the_data) and not self.configuration.force:
|
|
|
- self.build_cache.append(fn)
|
|
|
- return True
|
|
|
-
|
|
|
- return self.tryBuildPackage(fn, item, self.configuration.cmd, the_data, build_depends)
|
|
|
-
|
|
|
- def showVersions( self ):
|
|
|
- pkg_pn = self.status.pkg_pn
|
|
|
- preferred_versions = {}
|
|
|
- latest_versions = {}
|
|
|
-
|
|
|
- # Sort by priority
|
|
|
- for pn in pkg_pn.keys():
|
|
|
- (last_ver,last_file,pref_ver,pref_file) = bb.providers.findBestProvider(pn, self.configuration.data, self.status)
|
|
|
- preferred_versions[pn] = (pref_ver, pref_file)
|
|
|
- latest_versions[pn] = (last_ver, last_file)
|
|
|
-
|
|
|
- pkg_list = pkg_pn.keys()
|
|
|
- pkg_list.sort()
|
|
|
-
|
|
|
- for p in pkg_list:
|
|
|
- pref = preferred_versions[p]
|
|
|
- latest = latest_versions[p]
|
|
|
-
|
|
|
- if pref != latest:
|
|
|
- prefstr = pref[0][0] + "-" + pref[0][1]
|
|
|
- else:
|
|
|
- prefstr = ""
|
|
|
-
|
|
|
- print "%-30s %20s %20s" % (p, latest[0][0] + "-" + latest[0][1],
|
|
|
- prefstr)
|
|
|
-
|
|
|
-
|
|
|
- def showEnvironment( self ):
|
|
|
- """Show the outer or per-package environment"""
|
|
|
- if self.configuration.buildfile:
|
|
|
- self.cb = None
|
|
|
- self.bb_cache = bb.cache.init(self)
|
|
|
- try:
|
|
|
- self.configuration.data = self.bb_cache.loadDataFull(self.configuration.buildfile, self.configuration.data)
|
|
|
- except IOError, e:
|
|
|
- bb.msg.fatal(bb.msg.domain.Parsing, "Unable to read %s: %s" % ( self.configuration.buildfile, e ))
|
|
|
- except Exception, e:
|
|
|
- bb.msg.fatal(bb.msg.domain.Parsing, "%s" % e)
|
|
|
- # emit variables and shell functions
|
|
|
- try:
|
|
|
- data.update_data( self.configuration.data )
|
|
|
- data.emit_env(sys.__stdout__, self.configuration.data, True)
|
|
|
- except Exception, e:
|
|
|
- bb.msg.fatal(bb.msg.domain.Parsing, "%s" % e)
|
|
|
- # emit the metadata which isnt valid shell
|
|
|
- data.expandKeys( self.configuration.data )
|
|
|
- for e in self.configuration.data.keys():
|
|
|
- if data.getVarFlag( e, 'python', self.configuration.data ):
|
|
|
- sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, self.configuration.data, 1)))
|
|
|
-
|
|
|
- def generateDotGraph( self, pkgs_to_build, ignore_deps ):
|
|
|
- """
|
|
|
- Generate a task dependency graph.
|
|
|
-
|
|
|
- pkgs_to_build A list of packages that needs to be built
|
|
|
- ignore_deps A list of names where processing of dependencies
|
|
|
- should be stopped. e.g. dependencies that get
|
|
|
- """
|
|
|
-
|
|
|
- for dep in ignore_deps:
|
|
|
- self.status.ignored_dependencies.add(dep)
|
|
|
-
|
|
|
- localdata = data.createCopy(self.configuration.data)
|
|
|
- bb.data.update_data(localdata)
|
|
|
- bb.data.expandKeys(localdata)
|
|
|
- taskdata = bb.taskdata.TaskData(self.configuration.abort)
|
|
|
-
|
|
|
- runlist = []
|
|
|
- try:
|
|
|
- for k in pkgs_to_build:
|
|
|
- taskdata.add_provider(localdata, self.status, k)
|
|
|
- runlist.append([k, "do_%s" % self.configuration.cmd])
|
|
|
- taskdata.add_unresolved(localdata, self.status)
|
|
|
- except bb.providers.NoProvider:
|
|
|
- sys.exit(1)
|
|
|
- rq = bb.runqueue.RunQueue()
|
|
|
- rq.prepare_runqueue(self.configuration.data, self.status, taskdata, runlist)
|
|
|
-
|
|
|
- seen_fnids = []
|
|
|
- depends_file = file('depends.dot', 'w' )
|
|
|
- tdepends_file = file('task-depends.dot', 'w' )
|
|
|
- print >> depends_file, "digraph depends {"
|
|
|
- print >> tdepends_file, "digraph depends {"
|
|
|
- rq.prio_map.reverse()
|
|
|
- for task1 in range(len(rq.runq_fnid)):
|
|
|
- task = rq.prio_map[task1]
|
|
|
- taskname = rq.runq_task[task]
|
|
|
- fnid = rq.runq_fnid[task]
|
|
|
- fn = taskdata.fn_index[fnid]
|
|
|
- pn = self.status.pkg_fn[fn]
|
|
|
- version = self.bb_cache.getVar('PV', fn, True ) + '-' + self.bb_cache.getVar('PR', fn, True)
|
|
|
- print >> tdepends_file, '"%s.%s" [label="%s %s\\n%s\\n%s"]' % (pn, taskname, pn, taskname, version, fn)
|
|
|
- for dep in rq.runq_depends[task]:
|
|
|
- depfn = taskdata.fn_index[rq.runq_fnid[dep]]
|
|
|
- deppn = self.status.pkg_fn[depfn]
|
|
|
- print >> tdepends_file, '"%s.%s" -> "%s.%s"' % (pn, rq.runq_task[task], deppn, rq.runq_task[dep])
|
|
|
- if fnid not in seen_fnids:
|
|
|
- seen_fnids.append(fnid)
|
|
|
- packages = []
|
|
|
- print >> depends_file, '"%s" [label="%s %s\\n%s"]' % (pn, pn, version, fn)
|
|
|
- for depend in self.status.deps[fn]:
|
|
|
- print >> depends_file, '"%s" -> "%s"' % (pn, depend)
|
|
|
- rdepends = self.status.rundeps[fn]
|
|
|
- for package in rdepends:
|
|
|
- for rdepend in rdepends[package]:
|
|
|
- print >> depends_file, '"%s" -> "%s" [style=dashed]' % (package, rdepend)
|
|
|
- packages.append(package)
|
|
|
- rrecs = self.status.runrecs[fn]
|
|
|
- for package in rrecs:
|
|
|
- for rdepend in rrecs[package]:
|
|
|
- print >> depends_file, '"%s" -> "%s" [style=dashed]' % (package, rdepend)
|
|
|
- if not package in packages:
|
|
|
- packages.append(package)
|
|
|
- for package in packages:
|
|
|
- if package != pn:
|
|
|
- print >> depends_file, '"%s" [label="%s(%s) %s\\n%s"]' % (package, package, pn, version, fn)
|
|
|
- for depend in self.status.deps[fn]:
|
|
|
- print >> depends_file, '"%s" -> "%s"' % (package, depend)
|
|
|
- # Prints a flattened form of the above where subpackages of a package are merged into the main pn
|
|
|
- #print >> depends_file, '"%s" [label="%s %s\\n%s\\n%s"]' % (pn, pn, taskname, version, fn)
|
|
|
- #for rdep in taskdata.rdepids[fnid]:
|
|
|
- # print >> depends_file, '"%s" -> "%s" [style=dashed]' % (pn, taskdata.run_names_index[rdep])
|
|
|
- #for dep in taskdata.depids[fnid]:
|
|
|
- # print >> depends_file, '"%s" -> "%s"' % (pn, taskdata.build_names_index[dep])
|
|
|
- print >> depends_file, "}"
|
|
|
- print >> tdepends_file, "}"
|
|
|
- bb.msg.note(1, bb.msg.domain.Collection, "Dependencies saved to 'depends.dot'")
|
|
|
- bb.msg.note(1, bb.msg.domain.Collection, "Task dependencies saved to 'task-depends.dot'")
|
|
|
-
|
|
|
- def buildDepgraph( self ):
|
|
|
- all_depends = self.status.all_depends
|
|
|
- pn_provides = self.status.pn_provides
|
|
|
-
|
|
|
- localdata = data.createCopy(self.configuration.data)
|
|
|
- bb.data.update_data(localdata)
|
|
|
- bb.data.expandKeys(localdata)
|
|
|
-
|
|
|
- def calc_bbfile_priority(filename):
|
|
|
- for (regex, pri) in self.status.bbfile_config_priorities:
|
|
|
- if regex.match(filename):
|
|
|
- return pri
|
|
|
- return 0
|
|
|
-
|
|
|
- # Handle PREFERRED_PROVIDERS
|
|
|
- for p in (bb.data.getVar('PREFERRED_PROVIDERS', localdata, 1) or "").split():
|
|
|
- (providee, provider) = p.split(':')
|
|
|
- if providee in self.status.preferred and self.status.preferred[providee] != provider:
|
|
|
- bb.msg.error(bb.msg.domain.Provider, "conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.status.preferred[providee]))
|
|
|
- self.status.preferred[providee] = provider
|
|
|
-
|
|
|
- # Calculate priorities for each file
|
|
|
- for p in self.status.pkg_fn.keys():
|
|
|
- self.status.bbfile_priority[p] = calc_bbfile_priority(p)
|
|
|
-
|
|
|
- def buildWorldTargetList(self):
|
|
|
- """
|
|
|
- Build package list for "bitbake world"
|
|
|
- """
|
|
|
- all_depends = self.status.all_depends
|
|
|
- pn_provides = self.status.pn_provides
|
|
|
- bb.msg.debug(1, bb.msg.domain.Parsing, "collating packages for \"world\"")
|
|
|
- for f in self.status.possible_world:
|
|
|
- terminal = True
|
|
|
- pn = self.status.pkg_fn[f]
|
|
|
-
|
|
|
- for p in pn_provides[pn]:
|
|
|
- if p.startswith('virtual/'):
|
|
|
- bb.msg.debug(2, bb.msg.domain.Parsing, "World build skipping %s due to %s provider starting with virtual/" % (f, p))
|
|
|
- terminal = False
|
|
|
- break
|
|
|
- for pf in self.status.providers[p]:
|
|
|
- if self.status.pkg_fn[pf] != pn:
|
|
|
- bb.msg.debug(2, bb.msg.domain.Parsing, "World build skipping %s due to both us and %s providing %s" % (f, pf, p))
|
|
|
- terminal = False
|
|
|
- break
|
|
|
- if terminal:
|
|
|
- self.status.world_target.add(pn)
|
|
|
-
|
|
|
- # drop reference count now
|
|
|
- self.status.possible_world = None
|
|
|
- self.status.all_depends = None
|
|
|
-
|
|
|
- def myProgressCallback( self, x, y, f, from_cache ):
|
|
|
- """Update any tty with the progress change"""
|
|
|
- if os.isatty(sys.stdout.fileno()):
|
|
|
- sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
|
|
|
- sys.stdout.flush()
|
|
|
- else:
|
|
|
- if x == 1:
|
|
|
- sys.stdout.write("Parsing .bb files, please wait...")
|
|
|
- sys.stdout.flush()
|
|
|
- if x == y:
|
|
|
- sys.stdout.write("done.")
|
|
|
- sys.stdout.flush()
|
|
|
-
|
|
|
- def interactiveMode( self ):
|
|
|
- """Drop off into a shell"""
|
|
|
- try:
|
|
|
- from bb import shell
|
|
|
- except ImportError, details:
|
|
|
- bb.msg.fatal(bb.msg.domain.Parsing, "Sorry, shell not available (%s)" % details )
|
|
|
- else:
|
|
|
- bb.data.update_data( self.configuration.data )
|
|
|
- bb.data.expandKeys( self.configuration.data )
|
|
|
- shell.start( self )
|
|
|
- sys.exit( 0 )
|
|
|
-
|
|
|
- def parseConfigurationFile( self, afile ):
|
|
|
- try:
|
|
|
- self.configuration.data = bb.parse.handle( afile, self.configuration.data )
|
|
|
-
|
|
|
- # Add the handlers we inherited by INHERIT
|
|
|
- # we need to do this manually as it is not guranteed
|
|
|
- # we will pick up these classes... as we only INHERIT
|
|
|
- # on .inc and .bb files but not on .conf
|
|
|
- data = bb.data.createCopy( self.configuration.data )
|
|
|
- inherits = ["base"] + (bb.data.getVar('INHERIT', data, True ) or "").split()
|
|
|
- for inherit in inherits:
|
|
|
- data = bb.parse.handle( os.path.join('classes', '%s.bbclass' % inherit ), data, True )
|
|
|
-
|
|
|
- # FIXME: This assumes that we included at least one .inc file
|
|
|
- for var in bb.data.keys(data):
|
|
|
- if bb.data.getVarFlag(var, 'handler', data):
|
|
|
- bb.event.register(var,bb.data.getVar(var, data))
|
|
|
-
|
|
|
- except IOError:
|
|
|
- bb.msg.fatal(bb.msg.domain.Parsing, "Unable to open %s" % afile )
|
|
|
- except bb.parse.ParseError, details:
|
|
|
- bb.msg.fatal(bb.msg.domain.Parsing, "Unable to parse %s (%s)" % (afile, details) )
|
|
|
-
|
|
|
- def handleCollections( self, collections ):
|
|
|
- """Handle collections"""
|
|
|
- if collections:
|
|
|
- collection_list = collections.split()
|
|
|
- for c in collection_list:
|
|
|
- regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1)
|
|
|
- if regex == None:
|
|
|
- bb.msg.error(bb.msg.domain.Parsing, "BBFILE_PATTERN_%s not defined" % c)
|
|
|
- continue
|
|
|
- priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1)
|
|
|
- if priority == None:
|
|
|
- bb.msg.error(bb.msg.domain.Parsing, "BBFILE_PRIORITY_%s not defined" % c)
|
|
|
- continue
|
|
|
- try:
|
|
|
- cre = re.compile(regex)
|
|
|
- except re.error:
|
|
|
- bb.msg.error(bb.msg.domain.Parsing, "BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
|
|
|
- continue
|
|
|
- try:
|
|
|
- pri = int(priority)
|
|
|
- self.status.bbfile_config_priorities.append((cre, pri))
|
|
|
- except ValueError:
|
|
|
- bb.msg.error(bb.msg.domain.Parsing, "invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
|
|
|
-
|
|
|
-
|
|
|
- def cook( self, configuration, args ):
|
|
|
- """
|
|
|
- We are building stuff here. We do the building
|
|
|
- from here. By default we try to execute task
|
|
|
- build.
|
|
|
- """
|
|
|
-
|
|
|
- self.configuration = configuration
|
|
|
-
|
|
|
- if self.configuration.verbose:
|
|
|
- bb.msg.set_verbose(True)
|
|
|
-
|
|
|
- if self.configuration.debug:
|
|
|
- bb.msg.set_debug_level(self.configuration.debug)
|
|
|
- else:
|
|
|
- bb.msg.set_debug_level(0)
|
|
|
-
|
|
|
- if self.configuration.debug_domains:
|
|
|
- bb.msg.set_debug_domains(self.configuration.debug_domains)
|
|
|
-
|
|
|
- self.configuration.data = bb.data.init()
|
|
|
-
|
|
|
- for f in self.configuration.file:
|
|
|
- self.parseConfigurationFile( f )
|
|
|
-
|
|
|
- self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
|
|
|
-
|
|
|
- if not self.configuration.cmd:
|
|
|
- self.configuration.cmd = bb.data.getVar("BB_DEFAULT_TASK", self.configuration.data)
|
|
|
-
|
|
|
- # For backwards compatibility - REMOVE ME
|
|
|
- if not self.configuration.cmd:
|
|
|
- self.configuration.cmd = "build"
|
|
|
-
|
|
|
- #
|
|
|
- # Special updated configuration we use for firing events
|
|
|
- #
|
|
|
- self.configuration.event_data = bb.data.createCopy(self.configuration.data)
|
|
|
- bb.data.update_data(self.configuration.event_data)
|
|
|
-
|
|
|
- if self.configuration.show_environment:
|
|
|
- self.showEnvironment()
|
|
|
- sys.exit( 0 )
|
|
|
-
|
|
|
- # inject custom variables
|
|
|
- if not bb.data.getVar("BUILDNAME", self.configuration.data):
|
|
|
- bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
|
|
|
- bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data)
|
|
|
-
|
|
|
- buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
|
|
|
-
|
|
|
- if self.configuration.interactive:
|
|
|
- self.interactiveMode()
|
|
|
-
|
|
|
- if self.configuration.buildfile is not None:
|
|
|
- bf = os.path.abspath( self.configuration.buildfile )
|
|
|
- try:
|
|
|
- os.stat(bf)
|
|
|
- except OSError:
|
|
|
- (filelist, masked) = self.collect_bbfiles()
|
|
|
- regexp = re.compile(self.configuration.buildfile)
|
|
|
- matches = []
|
|
|
- for f in filelist:
|
|
|
- if regexp.search(f) and os.path.isfile(f):
|
|
|
- bf = f
|
|
|
- matches.append(f)
|
|
|
- if len(matches) != 1:
|
|
|
- bb.msg.error(bb.msg.domain.Parsing, "Unable to match %s (%s matches found):" % (self.configuration.buildfile, len(matches)))
|
|
|
- for f in matches:
|
|
|
- bb.msg.error(bb.msg.domain.Parsing, " %s" % f)
|
|
|
- sys.exit(1)
|
|
|
- bf = matches[0]
|
|
|
-
|
|
|
- bbfile_data = bb.parse.handle(bf, self.configuration.data)
|
|
|
-
|
|
|
- item = bb.data.getVar('PN', bbfile_data, 1)
|
|
|
- try:
|
|
|
- self.tryBuildPackage(bf, item, self.configuration.cmd, bbfile_data, True)
|
|
|
- except bb.build.EventException:
|
|
|
- bb.msg.error(bb.msg.domain.Build, "Build of '%s' failed" % item )
|
|
|
-
|
|
|
- sys.exit( self.stats.show() )
|
|
|
-
|
|
|
- # initialise the parsing status now we know we will need deps
|
|
|
- self.status = bb.cache.CacheData()
|
|
|
-
|
|
|
- ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
|
|
|
- self.status.ignored_dependencies = Set( ignore.split() )
|
|
|
-
|
|
|
- self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
|
|
|
-
|
|
|
- pkgs_to_build = None
|
|
|
- if args:
|
|
|
- if not pkgs_to_build:
|
|
|
- pkgs_to_build = []
|
|
|
- pkgs_to_build.extend(args)
|
|
|
- if not pkgs_to_build:
|
|
|
- bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
|
|
|
- if bbpkgs:
|
|
|
- pkgs_to_build = bbpkgs.split()
|
|
|
- if not pkgs_to_build and not self.configuration.show_versions \
|
|
|
- and not self.configuration.interactive \
|
|
|
- and not self.configuration.show_environment:
|
|
|
- print "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help'"
|
|
|
- print "for usage information."
|
|
|
- sys.exit(0)
|
|
|
-
|
|
|
- # Import Psyco if available and not disabled
|
|
|
- if not self.configuration.disable_psyco:
|
|
|
- try:
|
|
|
- import psyco
|
|
|
- except ImportError:
|
|
|
- bb.msg.note(1, bb.msg.domain.Collection, "Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
|
|
|
- else:
|
|
|
- psyco.bind( self.parse_bbfiles )
|
|
|
- else:
|
|
|
- bb.msg.note(1, bb.msg.domain.Collection, "You have disabled Psyco. This decreases performance.")
|
|
|
-
|
|
|
- try:
|
|
|
- bb.msg.debug(1, bb.msg.domain.Collection, "collecting .bb files")
|
|
|
- (filelist, masked) = self.collect_bbfiles()
|
|
|
- self.parse_bbfiles(filelist, masked, self.myProgressCallback)
|
|
|
- bb.msg.debug(1, bb.msg.domain.Collection, "parsing complete")
|
|
|
- print
|
|
|
- if self.configuration.parse_only:
|
|
|
- bb.msg.note(1, bb.msg.domain.Collection, "Requested parsing .bb files only. Exiting.")
|
|
|
- return
|
|
|
-
|
|
|
-
|
|
|
- self.buildDepgraph()
|
|
|
-
|
|
|
- if self.configuration.show_versions:
|
|
|
- self.showVersions()
|
|
|
- sys.exit( 0 )
|
|
|
- if 'world' in pkgs_to_build:
|
|
|
- self.buildWorldTargetList()
|
|
|
- pkgs_to_build.remove('world')
|
|
|
- for t in self.status.world_target:
|
|
|
- pkgs_to_build.append(t)
|
|
|
-
|
|
|
- if self.configuration.dot_graph:
|
|
|
- self.generateDotGraph( pkgs_to_build, self.configuration.ignored_dot_deps )
|
|
|
- sys.exit( 0 )
|
|
|
-
|
|
|
- bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.event_data))
|
|
|
-
|
|
|
- localdata = data.createCopy(self.configuration.data)
|
|
|
- bb.data.update_data(localdata)
|
|
|
- bb.data.expandKeys(localdata)
|
|
|
-
|
|
|
- taskdata = bb.taskdata.TaskData(self.configuration.abort)
|
|
|
-
|
|
|
- runlist = []
|
|
|
- try:
|
|
|
- for k in pkgs_to_build:
|
|
|
- taskdata.add_provider(localdata, self.status, k)
|
|
|
- runlist.append([k, "do_%s" % self.configuration.cmd])
|
|
|
- taskdata.add_unresolved(localdata, self.status)
|
|
|
- except bb.providers.NoProvider:
|
|
|
- sys.exit(1)
|
|
|
-
|
|
|
- rq = bb.runqueue.RunQueue()
|
|
|
- rq.prepare_runqueue(self.configuration.data, self.status, taskdata, runlist)
|
|
|
- try:
|
|
|
- failures = rq.execute_runqueue(self, self.configuration.data, self.status, taskdata, runlist)
|
|
|
- except runqueue.TaskFailure, fnids:
|
|
|
- for fnid in fnids:
|
|
|
- bb.msg.error(bb.msg.domain.Build, "'%s' failed" % taskdata.fn_index[fnid])
|
|
|
- sys.exit(1)
|
|
|
- bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.event_data, failures))
|
|
|
-
|
|
|
- sys.exit( self.stats.show() )
|
|
|
-
|
|
|
- except KeyboardInterrupt:
|
|
|
- bb.msg.note(1, bb.msg.domain.Collection, "KeyboardInterrupt - Build not completed.")
|
|
|
- sys.exit(1)
|
|
|
-
|
|
|
- def get_bbfiles( self, path = os.getcwd() ):
|
|
|
- """Get list of default .bb files by reading out the current directory"""
|
|
|
- contents = os.listdir(path)
|
|
|
- bbfiles = []
|
|
|
- for f in contents:
|
|
|
- (root, ext) = os.path.splitext(f)
|
|
|
- if ext == ".bb":
|
|
|
- bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
|
|
|
- return bbfiles
|
|
|
-
|
|
|
- def find_bbfiles( self, path ):
|
|
|
- """Find all the .bb files in a directory (uses find)"""
|
|
|
- findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
|
|
|
- try:
|
|
|
- finddata = os.popen(findcmd)
|
|
|
- except OSError:
|
|
|
- return []
|
|
|
- return finddata.readlines()
|
|
|
-
|
|
|
- def collect_bbfiles( self ):
|
|
|
- """Collect all available .bb build files"""
|
|
|
- parsed, cached, skipped, masked = 0, 0, 0, 0
|
|
|
- self.bb_cache = bb.cache.init(self)
|
|
|
-
|
|
|
- files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
|
|
|
- data.setVar("BBFILES", " ".join(files), self.configuration.data)
|
|
|
-
|
|
|
- if not len(files):
|
|
|
- files = self.get_bbfiles()
|
|
|
-
|
|
|
- if not len(files):
|
|
|
- bb.msg.error(bb.msg.domain.Collection, "no files to build.")
|
|
|
-
|
|
|
- newfiles = []
|
|
|
- for f in files:
|
|
|
- if os.path.isdir(f):
|
|
|
- dirfiles = self.find_bbfiles(f)
|
|
|
- if dirfiles:
|
|
|
- newfiles += dirfiles
|
|
|
- continue
|
|
|
- newfiles += glob.glob(f) or [ f ]
|
|
|
-
|
|
|
- bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1)
|
|
|
-
|
|
|
- if not bbmask:
|
|
|
- return (newfiles, 0)
|
|
|
-
|
|
|
- try:
|
|
|
- bbmask_compiled = re.compile(bbmask)
|
|
|
- except sre_constants.error:
|
|
|
- bb.msg.fatal(bb.msg.domain.Collection, "BBMASK is not a valid regular expression.")
|
|
|
-
|
|
|
- finalfiles = []
|
|
|
- for i in xrange( len( newfiles ) ):
|
|
|
- f = newfiles[i]
|
|
|
- if bbmask and bbmask_compiled.search(f):
|
|
|
- bb.msg.debug(1, bb.msg.domain.Collection, "skipping masked file %s" % f)
|
|
|
- masked += 1
|
|
|
- continue
|
|
|
- finalfiles.append(f)
|
|
|
-
|
|
|
- return (finalfiles, masked)
|
|
|
-
|
|
|
- def parse_bbfiles(self, filelist, masked, progressCallback = None):
|
|
|
- parsed, cached, skipped = 0, 0, 0
|
|
|
- for i in xrange( len( filelist ) ):
|
|
|
- f = filelist[i]
|
|
|
-
|
|
|
- bb.msg.debug(1, bb.msg.domain.Collection, "parsing %s" % f)
|
|
|
-
|
|
|
- # read a file's metadata
|
|
|
- try:
|
|
|
- fromCache, skip = self.bb_cache.loadData(f, self.configuration.data)
|
|
|
- if skip:
|
|
|
- skipped += 1
|
|
|
- bb.msg.debug(2, bb.msg.domain.Collection, "skipping %s" % f)
|
|
|
- self.bb_cache.skip(f)
|
|
|
- continue
|
|
|
- elif fromCache: cached += 1
|
|
|
- else: parsed += 1
|
|
|
- deps = None
|
|
|
-
|
|
|
- # Disabled by RP as was no longer functional
|
|
|
- # allow metadata files to add items to BBFILES
|
|
|
- #data.update_data(self.pkgdata[f])
|
|
|
- #addbbfiles = self.bb_cache.getVar('BBFILES', f, False) or None
|
|
|
- #if addbbfiles:
|
|
|
- # for aof in addbbfiles.split():
|
|
|
- # if not files.count(aof):
|
|
|
- # if not os.path.isabs(aof):
|
|
|
- # aof = os.path.join(os.path.dirname(f),aof)
|
|
|
- # files.append(aof)
|
|
|
-
|
|
|
- self.bb_cache.handle_data(f, self.status)
|
|
|
-
|
|
|
- # now inform the caller
|
|
|
- if progressCallback is not None:
|
|
|
- progressCallback( i + 1, len( filelist ), f, fromCache )
|
|
|
-
|
|
|
- except IOError, e:
|
|
|
- self.bb_cache.remove(f)
|
|
|
- bb.msg.error(bb.msg.domain.Collection, "opening %s: %s" % (f, e))
|
|
|
- pass
|
|
|
- except KeyboardInterrupt:
|
|
|
- self.bb_cache.sync()
|
|
|
- raise
|
|
|
- except Exception, e:
|
|
|
- self.bb_cache.remove(f)
|
|
|
- bb.msg.error(bb.msg.domain.Collection, "%s while parsing %s" % (e, f))
|
|
|
- except:
|
|
|
- self.bb_cache.remove(f)
|
|
|
- raise
|
|
|
-
|
|
|
- if progressCallback is not None:
|
|
|
- print "\r" # need newline after Handling Bitbake files message
|
|
|
- bb.msg.note(1, bb.msg.domain.Collection, "Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ))
|
|
|
-
|
|
|
- self.bb_cache.sync()
|
|
|
|
|
|
#============================================================================#
|
|
|
# main
|
|
@@ -747,12 +103,13 @@ Default BBFILES are the .bb files in the current directory.""" )
|
|
|
action = "append", dest = "debug_domains", default = [] )
|
|
|
|
|
|
|
|
|
- options, args = parser.parse_args( sys.argv )
|
|
|
-
|
|
|
- cooker = BBCooker()
|
|
|
- cooker.cook( BBConfiguration( options ), args[1:] )
|
|
|
+ options, args = parser.parse_args(sys.argv)
|
|
|
|
|
|
+ configuration = BBConfiguration(options)
|
|
|
+ configuration.pkgs_to_build = []
|
|
|
+ configuration.pkgs_to_build.extend(args[1:])
|
|
|
|
|
|
+ bb.cooker.BBCooker().cook(configuration)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
main()
|
|
@@ -761,4 +118,6 @@ if __name__ == "__main__":
|
|
|
profile.run('main()', "profile.log")
|
|
|
import pstats
|
|
|
p = pstats.Stats('profile.log')
|
|
|
+ p.sort_stats('time')
|
|
|
p.print_stats()
|
|
|
+ p.print_callers()
|