# Place, Suite 330, Boston, MA 02111-1307 USA.
import sys, os, getopt, glob, copy, os.path, re, time
-sys.path.append(os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
+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, debug, event, fatal
from sets import Set
parsespin = itertools.cycle( r'|/-\\' )
bbdebug = 0
-__version__ = "1.3.2"
+__version__ = "1.3.3.2"
#============================================================================#
# BBParsingStatus
def __init__(self):
self.cache_dirty = False
self.providers = {}
+ self.rproviders = {}
self.packages = {}
self.packages_dynamic = {}
self.bbfile_priority = {}
depends = (bb.data.getVar("DEPENDS", bb_data, True) or "").split()
packages = (bb.data.getVar('PACKAGES', bb_data, True) or "").split()
packages_dynamic = (bb.data.getVar('PACKAGES_DYNAMIC', bb_data, True) or "").split()
+ rprovides = (bb.data.getVar("RPROVIDES", bb_data, 1) or "").split()
# build PackageName to FileName lookup table
# Build reverse hash for PACKAGES, so runtime dependencies
# can be be resolved (RDEPENDS, RRECOMMENDS etc.)
-
for package in packages:
if not package in self.packages:
self.packages[package] = []
self.packages[package].append(file_name)
+ rprovides += (bb.data.getVar("RPROVIDES_%s" % package, bb_data, 1) or "").split()
for package in packages_dynamic:
if not package in self.packages_dynamic:
self.packages_dynamic[package] = []
self.packages_dynamic[package].append(file_name)
+ for rprovide in rprovides:
+ if not rprovide in self.rproviders:
+ self.rproviders[rprovide] = []
+ self.rproviders[rprovide].append(file_name)
+
# Collect files we may need for possible world-dep
# calculations
if not bb.data.getVar('BROKEN', bb_data, True) and not bb.data.getVar('EXCLUDE_FROM_WORLD', bb_data, True):
def __init__( self ):
self.build_cache_fail = []
self.build_cache = []
+ self.rbuild_cache = []
self.building_list = []
self.build_path = []
self.consider_msgs_cache = []
self.build_cache_fail.append(fn)
raise
- def tryBuild( self, fn, virtual , buildAllDeps ):
- """Build a provider and its dependencies"""
- if fn in self.building_list:
+ def tryBuild( self, fn, virtual , buildAllDeps , 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.pkgdata[fn]
+
+ if not buildAllDeps:
+ buildAllDeps = bb.data.getVar('BUILD_ALL_DEPS', the_data, True) or False
+
+ # Error on build time dependency loops
+ if build_depends and build_depends.count(fn) > 1:
bb.error("%s depends on itself (eventually)" % fn)
bb.error("upwards chain is: %s" % (" -> ".join(self.build_path)))
return False
- the_data = self.pkgdata[fn]
+ # See if this is a runtime dependency we've already built
+ # Or a build dependency being handled in a different build chain
+ if fn in self.building_list:
+ return self.addRunDeps(fn, virtual , buildAllDeps)
+
item = self.status.pkg_fn[fn]
self.building_list.append(fn)
pathstr = "%s (%s)" % (item, virtual)
self.build_path.append(pathstr)
- depends_list = (bb.data.getVar('DEPENDS', the_data, 1) or "")
- if not buildAllDeps:
- buildAllDeps = bb.data.getVar('BUILD_ALL_DEPS', the_data, 1) or False
-
- if buildAllDeps:
- depends_list = "%s %s %s" % (depends_list, (bb.data.getVar('RDEPENDS', the_data, 1) or ""), (bb.data.getVar('RRECOMMENDS', the_data, 1) or ""))
+ depends_list = (bb.data.getVar('DEPENDS', the_data, True) or "").split()
if self.configuration.verbose:
bb.note("current path: %s" % (" -> ".join(self.build_path)))
- bb.note("dependencies for %s are: %s" % (item, depends_list))
-
- depends_list = depends_list.split()
+ bb.note("dependencies for %s are: %s" % (item, " ".join(depends_list)))
try:
failed = False
continue
if not depcmd:
continue
- if self.buildProvider( dependency , buildAllDeps ) == 0:
+ if self.buildProvider( dependency , buildAllDeps , build_depends ) == 0:
bb.error("dependency %s (for %s) not satisfied" % (dependency,item))
failed = True
if self.configuration.abort:
self.stats.deps += 1
return False
+ if not self.addRunDeps(fn, virtual , buildAllDeps):
+ return False
+
if bb.build.stamp_is_current('do_%s' % self.configuration.cmd, the_data):
self.build_cache.append(fn)
return True
bb.data.setVar('OVERRIDES', "%s:%s" % (pn, data.getVar('OVERRIDES', localdata)), localdata)
bb.data.update_data(localdata)
- preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, localdata, 1)
+ preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, localdata, True)
if preferred_v:
m = re.match('(.*)_(.*)', preferred_v)
if m:
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 getProviders(self, item, buildAllDeps):
-
- if item in self.status.providers:
- return self.status.providers[item]
-
- if not buildAllDeps:
- return False
-
- if item in self.status.packages:
- return self.status.packages[item]
-
- matches = []
- for pattern in self.status.packages_dynamic:
- regexp = re.compile(pattern)
- if regexp.match(item):
- for fn in self.status.packages_dynamic[pattern]:
- matches.append(fn)
-
- if matches:
- return matches
-
- return False
-
- def buildProvider( self, item , buildAllDeps ):
- fn = None
-
- discriminated = False
-
- all_p = self.getProviders(item, buildAllDeps)
-
- if not all_p:
- bb.error("Nothing provides %s" % item)
- return 0
-
- for p in all_p:
- if p in self.build_cache:
- bb.debug(1, "already built %s in this run\n" % p)
- return 1
-
+ def filterProviders(self, providers, item):
+ """
+ Take a list of providers and filter/reorder according to the
+ environment variables and previous build results
+ """
eligible = []
preferred_versions = {}
# Collate providers by PN
pkg_pn = {}
- for p in all_p:
+ for p in providers:
pn = self.status.pkg_fn[p]
if pn not in pkg_pn:
pkg_pn[pn] = []
# look to see if one of them is already staged, or marked as preferred.
# if so, bump it to the head of the queue
- for p in all_p:
+ for p in providers:
the_data = self.pkgdata[p]
pn = bb.data.getVar('PN', the_data, 1)
pv = bb.data.getVar('PV', the_data, 1)
pr = bb.data.getVar('PR', the_data, 1)
- tmpdir = bb.data.getVar('TMPDIR', the_data, 1)
- stamp = '%s/stamps/%s-%s-%s.do_populate_staging' % (tmpdir, pn, pv, pr)
+ stamp = '%s.do_populate_staging' % bb.data.getVar('STAMP', the_data, 1)
if os.path.exists(stamp):
(newvers, fn) = preferred_versions[pn]
if not fn in eligible:
discriminated = True
break
+ return eligible
+
+ def buildProvider( self, item , buildAllDeps , build_depends = [] ):
+ """
+ Build something to provide a named build requirement
+ (takes item names from DEPENDS namespace)
+ """
+
+ fn = None
+ discriminated = False
+
+ if not item in self.status.providers:
+ bb.error("Nothing provides dependency %s" % item)
+ bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
+ return 0
+
+ all_p = self.status.providers[item]
+
+ for p in all_p:
+ if p in self.build_cache:
+ bb.debug(1, "already built %s in this run\n" % p)
+ return 1
+
+ eligible = self.filterProviders(all_p, item)
+
+ if not eligible:
+ return 0
+
prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
if prefervar:
self.preferred[item] = prefervar
providers_list.append(self.status.pkg_fn[fn])
bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
bb.note("consider defining PREFERRED_PROVIDER_%s" % item)
+ bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data))
self.consider_msgs_cache.append(item)
# run through the list until we find one that we can build
for fn in eligible:
bb.debug(2, "selecting %s to satisfy %s" % (fn, item))
- if self.tryBuild(fn, item, buildAllDeps):
+ if self.tryBuild(fn, item, buildAllDeps, build_depends + [fn]):
return 1
bb.note("no buildable providers for %s" % item)
+ bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
return 0
+ def buildRProvider( self, item , buildAllDeps ):
+ """
+ Build something to provide a named runtime requirement
+ (takes item names from RDEPENDS/PACKAGES namespace)
+ """
+
+ fn = None
+ all_p = []
+ discriminated = False
+
+ if not buildAllDeps:
+ return True
+
+ all_p = self.getProvidersRun(item)
+
+ if not all_p:
+ bb.error("Nothing provides runtime dependency %s" % (item))
+ bb.event.fire(bb.event.NoProvider(item,self.configuration.data,runtime=True))
+ return False
+
+ for p in all_p:
+ if p in self.rbuild_cache:
+ bb.debug(2, "Already built %s providing runtime %s\n" % (p,item))
+ return True
+ if p in self.build_cache:
+ bb.debug(2, "Already built %s but adding any further RDEPENDS for %s\n" % (p, item))
+ return self.addRunDeps(p, item , buildAllDeps)
+
+ eligible = self.filterProviders(all_p, item)
+ if not eligible:
+ return 0
+
+ preferred = []
+ for p in eligible:
+ pn = self.status.pkg_fn[p]
+ provides = self.status.pn_provides[pn]
+ for provide in provides:
+ prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, self.configuration.data, 1)
+ if prefervar == pn:
+ if self.configuration.verbose:
+ bb.note("selecting %s to satisfy runtime %s due to PREFERRED_PROVIDERS" % (pn, item))
+ eligible.remove(p)
+ eligible = [p] + eligible
+ preferred.append(p)
+
+ if len(eligible) > 1 and len(preferred) == 0:
+ if item not in self.consider_msgs_cache:
+ providers_list = []
+ for fn in eligible:
+ providers_list.append(self.status.pkg_fn[fn])
+ bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
+ bb.note("consider defining a PREFERRED_PROVIDER to match runtime %s" % item)
+ bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
+ self.consider_msgs_cache.append(item)
+
+ if len(preferred) > 1:
+ if item not in self.consider_msgs_cache:
+ providers_list = []
+ for fn in preferred:
+ providers_list.append(self.status.pkg_fn[fn])
+ bb.note("multiple preferred providers are available (%s);" % ", ".join(providers_list))
+ bb.note("consider defining only one PREFERRED_PROVIDER to match runtime %s" % item)
+ bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
+ self.consider_msgs_cache.append(item)
+
+ # run through the list until we find one that we can build
+ for fn in eligible:
+ bb.debug(2, "selecting %s to satisfy runtime %s" % (fn, item))
+ if self.tryBuild(fn, item, buildAllDeps):
+ return True
+
+ bb.error("No buildable providers for runtime %s" % item)
+ bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
+ return False
+
+ def getProvidersRun(self, rdepend):
+ """
+ Return any potential providers of runtime rdepend
+ """
+ rproviders = []
+
+ if rdepend in self.status.rproviders:
+ rproviders += self.status.rproviders[rdepend]
+
+ if rdepend in self.status.packages:
+ rproviders += self.status.packages[rdepend]
+
+ if rproviders:
+ return rproviders
+
+ # Only search dynamic packages if we can't find anything in other variables
+ for pattern in self.status.packages_dynamic:
+ regexp = re.compile(pattern)
+ if regexp.match(rdepend):
+ rproviders += self.status.packages_dynamic[pattern]
+
+ return rproviders
+
+ def addRunDeps(self , fn, item , buildAllDeps):
+ """
+ Add any runtime dependencies of runtime item provided by fn
+ as long as item has't previously been processed by this function.
+ """
+
+ if item in self.rbuild_cache:
+ return True
+
+ if not buildAllDeps:
+ return True
+
+ rdepends = []
+ self.rbuild_cache.append(item)
+ the_data = self.pkgdata[fn]
+ pn = self.status.pkg_fn[fn]
+
+ if (item == pn):
+ rdepends += bb.utils.explode_deps(bb.data.getVar('RDEPENDS', the_data, True) or "")
+ rdepends += bb.utils.explode_deps(bb.data.getVar('RRECOMMENDS', the_data, True) or "")
+ rdepends += bb.utils.explode_deps(bb.data.getVar("RDEPENDS_%s" % pn, the_data, True) or "")
+ rdepends += bb.utils.explode_deps(bb.data.getVar('RRECOMMENDS_%s' % pn, the_data, True) or "")
+ else:
+ packages = (bb.data.getVar('PACKAGES', the_data, 1).split() or "")
+ for package in packages:
+ if package == item:
+ rdepends += bb.utils.explode_deps(bb.data.getVar("RDEPENDS_%s" % package, the_data, True) or "")
+ rdepends += bb.utils.explode_deps(bb.data.getVar("RRECOMMENDS_%s" % package, the_data, True) or "")
+
+ bb.debug(2, "Additional runtime dependencies for %s are: %s" % (item, " ".join(rdepends)))
+
+ for rdepend in rdepends:
+ if rdepend in self.status.ignored_dependencies:
+ continue
+ if not self.buildRProvider(rdepend, buildAllDeps):
+ return False
+ return True
+
def buildDepgraph( self ):
all_depends = self.status.all_depends
pn_provides = self.status.pn_provides
for p in self.pkgdata.keys():
self.status.bbfile_priority[p] = calc_bbfile_priority(p)
- # Build package list for "bitbake world"
+ def buildWorldTargetList(self):
+ """
+ Build package list for "bitbake world"
+ """
+ all_depends = self.status.all_depends
+ pn_provides = self.status.pn_provides
bb.debug(1, "collating packages for \"world\"")
for f in self.status.possible_world:
terminal = True
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)
bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.data))
+ failures = 0
for k in pkgs_to_build:
failed = False
try:
failed = True
if failed:
+ failures += failures
if self.configuration.abort:
sys.exit(1)
- bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.data))
+ bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.data, failures))
sys.exit( self.stats.show() )
if not os.path.isabs(aof):
aof = os.path.join(os.path.dirname(f),aof)
files.append(aof)
- for var in bb_data.keys():
- if data.getVarFlag(var, "handler", bb_data) and data.getVar(var, bb_data):
- event.register(data.getVar(var, bb_data))
self.pkgdata[f] = bb_data
# now inform the caller
# main
#============================================================================#
-if __name__ == "__main__":
-
+def main():
parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
usage = """%prog [options] [package ...]
cooker = BBCooker()
cooker.cook( BBConfiguration( options ), args[1:] )
+
+
+
+if __name__ == "__main__":
+ main()