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
11 # This program is free software; you can redistribute it and/or modify it under
12 # the terms of the GNU General Public License as published by the Free Software
13 # Foundation; either version 2 of the License, or (at your option) any later
16 # This program is distributed in the hope that it will be useful, but WITHOUT
17 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License along with
21 # this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22 # Place, Suite 330, Boston, MA 02111-1307 USA.
24 import sys, os, getopt, glob, copy, os.path, re, time
25 sys.path.insert(0,os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
27 from bb import utils, data, parse, debug, event, fatal, cache, providers
29 import itertools, optparse
31 parsespin = itertools.cycle( r'|/-\\' )
36 #============================================================================#
38 #============================================================================#
39 class BBParsingStatus:
41 The initial idea for this status class is to use the data when it is
42 already loaded instead of loading it from various place over and over
50 self.packages_dynamic = {}
51 self.bbfile_priority = {}
52 self.bbfile_config_priorities = []
53 self.ignored_dependencies = None
54 self.possible_world = []
55 self.world_target = Set()
61 self.all_depends = Set()
67 def handle_bb_data(self, file_name, bb_cache, cached):
69 We will fill the dictionaries with the stuff we
70 need for building the tree more fast
73 pn = bb_cache.getVar('PN', file_name, True)
74 pv = bb_cache.getVar('PV', file_name, True)
75 pr = bb_cache.getVar('PR', file_name, True)
76 dp = int(bb_cache.getVar('DEFAULT_PREFERENCE', file_name, True) or "0")
77 provides = Set([pn] + (bb_cache.getVar("PROVIDES", file_name, True) or "").split())
78 depends = (bb_cache.getVar("DEPENDS", file_name, True) or "").split()
79 packages = (bb_cache.getVar('PACKAGES', file_name, True) or "").split()
80 packages_dynamic = (bb_cache.getVar('PACKAGES_DYNAMIC', file_name, True) or "").split()
81 rprovides = (bb_cache.getVar("RPROVIDES", file_name, True) or "").split()
83 # build PackageName to FileName lookup table
84 if pn not in self.pkg_pn:
86 self.pkg_pn[pn].append(file_name)
88 self.build_all[file_name] = int(bb_cache.getVar('BUILD_ALL_DEPS', file_name, True) or "0")
89 self.stamp[file_name] = bb_cache.getVar('STAMP', file_name, True)
91 # build FileName to PackageName lookup table
92 self.pkg_fn[file_name] = pn
93 self.pkg_pvpr[file_name] = (pv,pr)
94 self.pkg_dp[file_name] = dp
96 # Build forward and reverse provider hashes
97 # Forward: virtual -> [filenames]
98 # Reverse: PN -> [virtuals]
99 if pn not in self.pn_provides:
100 self.pn_provides[pn] = Set()
101 self.pn_provides[pn] |= provides
103 for provide in provides:
104 if provide not in self.providers:
105 self.providers[provide] = []
106 self.providers[provide].append(file_name)
109 self.all_depends.add(dep)
111 # Build reverse hash for PACKAGES, so runtime dependencies
112 # can be be resolved (RDEPENDS, RRECOMMENDS etc.)
113 for package in packages:
114 if not package in self.packages:
115 self.packages[package] = []
116 self.packages[package].append(file_name)
117 rprovides += (bb_cache.getVar("RPROVIDES_%s" % package, file_name, 1) or "").split()
119 for package in packages_dynamic:
120 if not package in self.packages_dynamic:
121 self.packages_dynamic[package] = []
122 self.packages_dynamic[package].append(file_name)
124 for rprovide in rprovides:
125 if not rprovide in self.rproviders:
126 self.rproviders[rprovide] = []
127 self.rproviders[rprovide].append(file_name)
129 # Build hash of runtime depeneds and rececommends
131 def add_dep(deplist, deps):
133 if not dep in deplist:
136 if not file_name in self.rundeps:
137 self.rundeps[file_name] = {}
138 if not file_name in self.runrecs:
139 self.runrecs[file_name] = {}
141 for package in packages + [pn]:
142 if not package in self.rundeps[file_name]:
143 self.rundeps[file_name][package] = {}
144 if not package in self.runrecs[file_name]:
145 self.runrecs[file_name][package] = {}
147 add_dep(self.rundeps[file_name][package], bb.utils.explode_deps(bb_cache.getVar('RDEPENDS', file_name, True) or ""))
148 add_dep(self.runrecs[file_name][package], bb.utils.explode_deps(bb_cache.getVar('RRECOMMENDS', file_name, True) or ""))
149 add_dep(self.rundeps[file_name][package], bb.utils.explode_deps(bb_cache.getVar("RDEPENDS_%s" % package, file_name, True) or ""))
150 add_dep(self.runrecs[file_name][package], bb.utils.explode_deps(bb_cache.getVar("RRECOMMENDS_%s" % package, file_name, True) or ""))
152 # Collect files we may need for possible world-dep
154 if not bb_cache.getVar('BROKEN', file_name, True) and not bb_cache.getVar('EXCLUDE_FROM_WORLD', file_name, True):
155 self.possible_world.append(file_name)
158 #============================================================================#
160 #============================================================================#
163 Manage build statistics for one run
172 print "Build statistics:"
173 print " Attempted builds: %d" % self.attempt
175 print " Failed builds: %d" % self.fail
177 print " Dependencies not satisfied: %d" % self.deps
178 if self.fail or self.deps: return 1
182 #============================================================================#
184 #============================================================================#
185 class BBConfiguration( object ):
187 Manages build options and configurations for one run
189 def __init__( self, options ):
190 for key, val in options.__dict__.items():
191 setattr( self, key, val )
193 #============================================================================#
195 #============================================================================#
198 Manages one bitbake build run
201 ParsingStatus = BBParsingStatus # make it visible from the shell
202 Statistics = BBStatistics # make it visible from the shell
204 def __init__( self ):
205 self.build_cache_fail = []
206 self.build_cache = []
207 self.rbuild_cache = []
208 self.building_list = []
210 self.consider_msgs_cache = []
212 self.stats = BBStatistics()
218 def tryBuildPackage( self, fn, item, the_data ):
219 """Build one package"""
220 bb.event.fire(bb.event.PkgStarted(item, the_data))
222 self.stats.attempt += 1
223 if self.configuration.force:
224 bb.data.setVarFlag('do_%s' % self.configuration.cmd, 'force', 1, the_data)
225 if not self.configuration.dry_run:
226 bb.build.exec_task('do_%s' % self.configuration.cmd, the_data)
227 bb.event.fire(bb.event.PkgSucceeded(item, the_data))
228 self.build_cache.append(fn)
230 except bb.build.FuncFailed:
232 bb.error("task stack execution failed")
233 bb.event.fire(bb.event.PkgFailed(item, the_data))
234 self.build_cache_fail.append(fn)
236 except bb.build.EventException, e:
239 bb.error("%s event exception, aborting" % bb.event.getName(event))
240 bb.event.fire(bb.event.PkgFailed(item, the_data))
241 self.build_cache_fail.append(fn)
244 def tryBuild( self, fn, virtual , buildAllDeps , build_depends = []):
246 Build a provider and its dependencies.
247 build_depends is a list of previous build dependencies (not runtime)
248 If build_depends is empty, we're dealing with a runtime depends
251 the_data = self.bb_cache.loadDataFull(fn, self)
253 # Only follow all (runtime) dependencies if doing a build
254 if not buildAllDeps and self.configuration.cmd is "build":
255 buildAllDeps = self.status.build_all[fn]
257 # Error on build time dependency loops
258 if build_depends and build_depends.count(fn) > 1:
259 bb.error("%s depends on itself (eventually)" % fn)
260 bb.error("upwards chain is: %s" % (" -> ".join(self.build_path)))
263 # See if this is a runtime dependency we've already built
264 # Or a build dependency being handled in a different build chain
265 if fn in self.building_list:
266 return self.addRunDeps(fn, virtual , buildAllDeps)
268 item = self.status.pkg_fn[fn]
270 self.building_list.append(fn)
272 pathstr = "%s (%s)" % (item, virtual)
273 self.build_path.append(pathstr)
275 depends_list = (bb.data.getVar('DEPENDS', the_data, True) or "").split()
277 if self.configuration.verbose:
278 bb.note("current path: %s" % (" -> ".join(self.build_path)))
279 bb.note("dependencies for %s are: %s" % (item, " ".join(depends_list)))
284 depcmd = self.configuration.cmd
285 bbdepcmd = bb.data.getVarFlag('do_%s' % self.configuration.cmd, 'bbdepcmd', the_data)
286 if bbdepcmd is not None:
293 oldcmd = self.configuration.cmd
294 self.configuration.cmd = depcmd
296 for dependency in depends_list:
297 if dependency in self.status.ignored_dependencies:
301 if self.buildProvider( dependency , buildAllDeps , build_depends ) == 0:
302 bb.error("dependency %s (for %s) not satisfied" % (dependency,item))
304 if self.configuration.abort:
308 self.configuration.cmd = oldcmd
314 if not self.addRunDeps(fn, virtual , buildAllDeps):
317 if bb.build.stamp_is_current('do_%s' % self.configuration.cmd, the_data):
318 self.build_cache.append(fn)
321 return self.tryBuildPackage( fn, item, the_data )
324 self.building_list.remove(fn)
325 self.build_path.remove(pathstr)
328 def showVersions( self ):
329 pkg_pn = self.status.pkg_pn
330 preferred_versions = {}
334 for pn in pkg_pn.keys():
335 (last_ver,last_file,pref_ver,pref_file) = self.findBestProvider(pn, self.configuration.data, self.status)
336 preferred_versions[pn] = (pref_ver, pref_file)
337 latest_versions[pn] = (last_ver, last_file)
339 pkg_list = pkg_pn.keys()
343 pref = preferred_versions[p]
344 latest = latest_versions[p]
347 prefstr = pref[0][0] + "-" + pref[0][1]
351 print "%-30s %20s %20s" % (p, latest[0][0] + "-" + latest[0][1],
355 def showEnvironment( self ):
356 """Show the outer or per-package environment"""
357 if self.configuration.buildfile:
359 self.bb_cache = bb.cache.init(self)
361 self.configuration.data = self.bb_cache.loadDataFull(self.configuration.buildfile, self)
363 fatal("Unable to read %s: %s" % ( self.configuration.buildfile, e ))
366 # emit variables and shell functions
368 data.update_data( self.configuration.data )
369 data.emit_env(sys.__stdout__, self.configuration.data, True)
372 # emit the metadata which isnt valid shell
373 for e in self.configuration.data.keys():
374 if data.getVarFlag( e, 'python', self.configuration.data ):
375 sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, self.configuration.data, 1)))
377 def generateDotGraph( self, pkgs_to_build, ignore_deps ):
379 Generate two graphs one for the DEPENDS and RDEPENDS. The current
380 implementation creates crappy graphs ;)
382 pkgs_to_build A list of packages that needs to be built
383 ignore_deps A list of names where processing of dependencies
384 should be stopped. e.g. dependencies that get
387 def myFilterProvider( providers, item):
389 Take a list of providers and filter according to environment
390 variables. In contrast to filterProviders we do not discriminate
391 and take PREFERRED_PROVIDER into account.
394 preferred_versions = {}
396 # Collate providers by PN
399 pn = self.status.pkg_fn[p]
404 bb.debug(1, "providers for %s are: %s" % (item, pkg_pn.keys()))
406 for pn in pkg_pn.keys():
407 preferred_versions[pn] = self.findBestProvider(pn, pkg_pn)[2:4]
408 eligible.append(preferred_versions[pn][1])
411 if p in self.build_cache_fail:
412 bb.debug(1, "rejecting already-failed %s" % p)
415 if len(eligible) == 0:
416 bb.error("no eligible providers for %s" % item)
419 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
421 # try the preferred provider first
424 if prefervar == self.status.pkg_fn[p]:
425 bb.note("Selecting PREFERRED_PROVIDER %s" % prefervar)
427 eligible = [p] + eligible
434 # try to avoid adding the same rdepends over an over again
439 def add_depends(package_list):
441 Add all depends of all packages from this list
443 for package in package_list:
444 if package in seen_depends or package in ignore_deps:
447 seen_depends.append( package )
448 if not package in self.status.providers:
450 We have not seen this name -> error in
453 bb.note( "ERROR with provider: %(package)s" % vars() )
454 print >> depends_file, '"%(package)s" -> ERROR' % vars()
457 # get all providers for this package
458 providers = self.status.providers[package]
460 # now let us find the bestProvider for it
461 fn = myFilterProvider(providers, package)[0]
463 depends = bb.utils.explode_deps(self.bb_cache.getVar('DEPENDS', fn, True) or "")
464 version = self.bb_cache.getVar('PV', fn, True ) + '-' + self.bb_cache.getVar('PR', fn, True)
465 add_depends ( depends )
467 # now create the node
468 print >> depends_file, '"%(package)s" [label="%(package)s\\n%(version)s"]' % vars()
470 depends = filter( (lambda x: x not in ignore_deps), depends )
471 for depend in depends:
472 print >> depends_file, '"%(package)s" -> "%(depend)s"' % vars()
475 def add_all_depends( the_depends, the_rdepends ):
477 Add both DEPENDS and RDEPENDS. RDEPENDS will get dashed
480 package_list = the_depends + the_rdepends
481 for package in package_list:
482 if package in seen_rdepends or package in ignore_deps:
485 seen_rdepends.append( package )
487 # Let us find out if the package is a DEPENDS or RDEPENDS
488 # and we will set 'providers' with the avilable providers
490 if package in the_depends:
491 if not package in self.status.providers:
492 bb.note( "ERROR with provider: %(package)s" % vars() )
493 print >> alldepends_file, '"%(package)s" -> ERROR' % vars()
496 providers = self.status.providers[package]
497 elif package in the_rdepends:
498 if len(self.getProvidersRun(package)) == 0:
499 bb.note( "ERROR with rprovider: %(package)s" % vars() )
500 print >> alldepends_file, '"%(package)s" -> ERROR [style="dashed"]' % vars()
503 providers = self.getProvidersRun(package)
505 # something went wrong...
506 print "Complete ERROR! %s" % package
509 # now let us find the bestProvider for it
510 fn = myFilterProvider(providers, package)[0]
512 # Now we have a filename let us get the depends and RDEPENDS of it
513 depends = bb.utils.explode_deps(self.bb_cache.getVar('DEPENDS', fn, True) or "")
514 if fn in self.status.rundeps and package in self.status.rundeps[fn]:
515 rdepends= self.status.rundeps[fn][package].keys()
518 version = self.bb_cache.getVar('PV', fn, True ) + '-' + self.bb_cache.getVar('PR', fn, True)
520 # handle all the depends and rdepends of package
521 add_all_depends ( depends, rdepends )
523 # now create the node using package name
524 print >> alldepends_file, '"%(package)s" [label="%(package)s\\n%(version)s"]' % vars()
526 # remove the stuff we want to ignore and add the edges
527 depends = filter( (lambda x: x not in ignore_deps), depends )
528 rdepends = filter( (lambda x: x not in ignore_deps), rdepends )
529 for depend in depends:
530 print >> alldepends_file, '"%(package)s" -> "%(depend)s"' % vars()
531 for depend in rdepends:
532 print >> alldepends_file, '"%(package)s" -> "%(depend)s" [style=dashed]' % vars()
536 depends_file = file('depends.dot', 'w' )
537 print >> depends_file, "digraph depends {"
538 add_depends( pkgs_to_build )
539 print >> depends_file, "}"
541 # Add all depends now
542 alldepends_file = file('alldepends.dot', 'w' )
543 print >> alldepends_file, "digraph alldepends {"
544 add_all_depends( pkgs_to_build, [] )
545 print >> alldepends_file, "}"
547 def buildProvider( self, item , buildAllDeps , build_depends = [] ):
549 Build something to provide a named build requirement
550 (takes item names from DEPENDS namespace)
554 discriminated = False
556 if not item in self.status.providers:
557 bb.error("Nothing provides dependency %s" % item)
558 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
561 all_p = self.status.providers[item]
564 if p in self.build_cache:
565 bb.debug(1, "already built %s in this run\n" % p)
568 eligible = bb.providers.filterProviders(all_p, item, self.configuration.data, self.status, self.build_cache_fail, self.configuration.verbose)
573 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
575 self.preferred[item] = prefervar
577 if item in self.preferred:
579 pn = self.status.pkg_fn[p]
580 if self.preferred[item] == pn:
581 if self.configuration.verbose:
582 bb.note("selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
584 eligible = [p] + eligible
588 if len(eligible) > 1 and discriminated == False:
589 if item not in self.consider_msgs_cache:
592 providers_list.append(self.status.pkg_fn[fn])
593 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
594 bb.note("consider defining PREFERRED_PROVIDER_%s" % item)
595 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data))
596 self.consider_msgs_cache.append(item)
599 # run through the list until we find one that we can build
601 bb.debug(2, "selecting %s to satisfy %s" % (fn, item))
602 if self.tryBuild(fn, item, buildAllDeps, build_depends + [fn]):
605 bb.note("no buildable providers for %s" % item)
606 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
609 def buildRProvider( self, item , buildAllDeps ):
611 Build something to provide a named runtime requirement
612 (takes item names from RDEPENDS/PACKAGES namespace)
617 discriminated = False
622 all_p = self.getProvidersRun(item)
625 bb.error("Nothing provides runtime dependency %s" % (item))
626 bb.event.fire(bb.event.NoProvider(item,self.configuration.data,runtime=True))
630 if p in self.rbuild_cache:
631 bb.debug(2, "Already built %s providing runtime %s\n" % (p,item))
633 if p in self.build_cache:
634 bb.debug(2, "Already built %s but adding any further RDEPENDS for %s\n" % (p, item))
635 return self.addRunDeps(p, item , buildAllDeps)
637 eligible = bb.providers.filterProviders(all_p, item, self.configuration.data, self.status, self.build_cache_fail, self.configuration.verbose)
643 pn = self.status.pkg_fn[p]
644 provides = self.status.pn_provides[pn]
645 for provide in provides:
646 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, self.configuration.data, 1)
648 if self.configuration.verbose:
649 bb.note("selecting %s to satisfy runtime %s due to PREFERRED_PROVIDERS" % (pn, item))
651 eligible = [p] + eligible
654 if len(eligible) > 1 and len(preferred) == 0:
655 if item not in self.consider_msgs_cache:
658 providers_list.append(self.status.pkg_fn[fn])
659 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
660 bb.note("consider defining a PREFERRED_PROVIDER to match runtime %s" % item)
661 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
662 self.consider_msgs_cache.append(item)
664 if len(preferred) > 1:
665 if item not in self.consider_msgs_cache:
668 providers_list.append(self.status.pkg_fn[fn])
669 bb.note("multiple preferred providers are available (%s);" % ", ".join(providers_list))
670 bb.note("consider defining only one PREFERRED_PROVIDER to match runtime %s" % item)
671 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
672 self.consider_msgs_cache.append(item)
674 # run through the list until we find one that we can build
676 bb.debug(2, "selecting %s to satisfy runtime %s" % (fn, item))
677 if self.tryBuild(fn, item, buildAllDeps):
680 bb.error("No buildable providers for runtime %s" % item)
681 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
684 def getProvidersRun(self, rdepend):
686 Return any potential providers of runtime rdepend
690 if rdepend in self.status.rproviders:
691 rproviders += self.status.rproviders[rdepend]
693 if rdepend in self.status.packages:
694 rproviders += self.status.packages[rdepend]
699 # Only search dynamic packages if we can't find anything in other variables
700 for pattern in self.status.packages_dynamic:
701 regexp = re.compile(pattern)
702 if regexp.match(rdepend):
703 rproviders += self.status.packages_dynamic[pattern]
707 def addRunDeps(self , fn, item , buildAllDeps):
709 Add any runtime dependencies of runtime item provided by fn
710 as long as item has't previously been processed by this function.
713 if item in self.rbuild_cache:
720 self.rbuild_cache.append(item)
722 if fn in self.status.rundeps and item in self.status.rundeps[fn]:
723 rdepends += self.status.rundeps[fn][item].keys()
724 if fn in self.status.runrecs and item in self.status.runrecs[fn]:
725 rdepends += self.status.runrecs[fn][item].keys()
727 bb.debug(2, "Additional runtime dependencies for %s are: %s" % (item, " ".join(rdepends)))
729 for rdepend in rdepends:
730 if rdepend in self.status.ignored_dependencies:
732 if not self.buildRProvider(rdepend, buildAllDeps):
736 def buildDepgraph( self ):
737 all_depends = self.status.all_depends
738 pn_provides = self.status.pn_provides
740 localdata = data.createCopy(self.configuration.data)
741 bb.data.update_data(localdata)
743 def calc_bbfile_priority(filename):
744 for (regex, pri) in self.status.bbfile_config_priorities:
745 if regex.match(filename):
749 # Handle PREFERRED_PROVIDERS
750 for p in (bb.data.getVar('PREFERRED_PROVIDERS', localdata, 1) or "").split():
751 (providee, provider) = p.split(':')
752 if providee in self.preferred and self.preferred[providee] != provider:
753 bb.error("conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.preferred[providee]))
754 self.preferred[providee] = provider
756 # Calculate priorities for each file
757 for p in self.status.pkg_fn.keys():
758 self.status.bbfile_priority[p] = calc_bbfile_priority(p)
760 def buildWorldTargetList(self):
762 Build package list for "bitbake world"
764 all_depends = self.status.all_depends
765 pn_provides = self.status.pn_provides
766 bb.debug(1, "collating packages for \"world\"")
767 for f in self.status.possible_world:
769 pn = self.status.pkg_fn[f]
771 for p in pn_provides[pn]:
772 if p.startswith('virtual/'):
773 bb.debug(2, "skipping %s due to %s provider starting with virtual/" % (f, p))
776 for pf in self.status.providers[p]:
777 if self.status.pkg_fn[pf] != pn:
778 bb.debug(2, "skipping %s due to both us and %s providing %s" % (f, pf, p))
782 self.status.world_target.add(pn)
784 # drop reference count now
785 self.status.possible_world = None
786 self.status.all_depends = None
788 def myProgressCallback( self, x, y, f, bb_cache, from_cache ):
789 # feed the status with new input
791 self.status.handle_bb_data(f, bb_cache, from_cache)
795 if os.isatty(sys.stdout.fileno()):
796 sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
800 sys.stdout.write("Parsing .bb files, please wait...")
803 sys.stdout.write("done.")
806 def interactiveMode( self ):
807 """Drop off into a shell"""
810 except ImportError, details:
811 bb.fatal("Sorry, shell not available (%s)" % details )
813 bb.data.update_data( self.configuration.data )
817 def parseConfigurationFile( self, afile ):
819 self.configuration.data = bb.parse.handle( afile, self.configuration.data )
821 # Add the handlers we inherited by INHERIT
822 # we need to do this manually as it is not guranteed
823 # we will pick up these classes... as we only INHERIT
824 # on .inc and .bb files but not on .conf
825 data = bb.data.createCopy( self.configuration.data )
826 inherits = ["base"] + (bb.data.getVar('INHERIT', data, True ) or "").split()
827 for inherit in inherits:
828 data = bb.parse.handle( os.path.join('classes', '%s.bbclass' % inherit ), data, True )
830 # FIXME: This assumes that we included at least one .inc file
831 for var in bb.data.keys(data):
832 if bb.data.getVarFlag(var, 'handler', data):
833 bb.event.register(var,bb.data.getVar(var, data))
836 bb.fatal( "Unable to open %s" % afile )
837 except bb.parse.ParseError, details:
838 bb.fatal( "Unable to parse %s (%s)" % (afile, details) )
840 def handleCollections( self, collections ):
841 """Handle collections"""
843 collection_list = collections.split()
844 for c in collection_list:
845 regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1)
847 bb.error("BBFILE_PATTERN_%s not defined" % c)
849 priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1)
851 bb.error("BBFILE_PRIORITY_%s not defined" % c)
854 cre = re.compile(regex)
856 bb.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
860 self.status.bbfile_config_priorities.append((cre, pri))
862 bb.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
865 def cook( self, configuration, args ):
867 We are building stuff here. We do the building
868 from here. By default we try to execute task
872 self.configuration = configuration
874 if not self.configuration.cmd:
875 self.configuration.cmd = "build"
877 if self.configuration.debug:
878 bb.debug_level = self.configuration.debug
880 self.configuration.data = bb.data.init()
882 for f in self.configuration.file:
883 self.parseConfigurationFile( f )
885 self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
889 # Special updated configuration we use for firing events
891 self.configuration.event_data = bb.data.createCopy(self.configuration.data)
892 bb.data.update_data(self.configuration.event_data)
894 if self.configuration.show_environment:
895 self.showEnvironment()
898 # inject custom variables
899 if not bb.data.getVar("BUILDNAME", self.configuration.data):
900 bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
901 bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data)
903 buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
905 if self.configuration.interactive:
906 self.interactiveMode()
908 if self.configuration.buildfile is not None:
909 bf = os.path.abspath( self.configuration.buildfile )
911 bbfile_data = bb.parse.handle(bf, self.configuration.data)
913 bb.fatal("Unable to open %s" % bf)
915 item = bb.data.getVar('PN', bbfile_data, 1)
917 self.tryBuildPackage( bf, item, bbfile_data )
918 except bb.build.EventException:
919 bb.error( "Build of '%s' failed" % item )
921 sys.exit( self.stats.show() )
923 # initialise the parsing status now we know we will need deps
924 self.status = BBParsingStatus()
926 ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
927 self.status.ignored_dependencies = Set( ignore.split() )
929 self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
933 if not pkgs_to_build:
935 pkgs_to_build.extend(args)
936 if not pkgs_to_build:
937 bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
939 pkgs_to_build = bbpkgs.split()
940 if not pkgs_to_build and not self.configuration.show_versions \
941 and not self.configuration.interactive \
942 and not self.configuration.show_environment:
943 print "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help'"
944 print "for usage information."
947 # Import Psyco if available and not disabled
948 if not self.configuration.disable_psyco:
953 bb.note("Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
955 psyco.bind( self.collect_bbfiles )
957 bb.note("You have disabled Psyco. This decreases performance.")
960 bb.debug(1, "collecting .bb files")
961 self.collect_bbfiles( self.myProgressCallback )
962 bb.debug(1, "parsing complete")
965 if self.configuration.parse_only:
966 print "Requested parsing .bb files only. Exiting."
972 if self.configuration.show_versions:
975 if 'world' in pkgs_to_build:
976 self.buildWorldTargetList()
977 pkgs_to_build.remove('world')
978 for t in self.status.world_target:
979 pkgs_to_build.append(t)
981 if self.configuration.dot_graph:
982 self.generateDotGraph( pkgs_to_build, self.configuration.ignored_dot_deps )
986 bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.event_data))
989 for k in pkgs_to_build:
992 if self.buildProvider( k , False ) == 0:
995 except bb.build.EventException:
996 bb.error("Build of " + k + " failed")
1000 failures += failures
1001 if self.configuration.abort:
1004 bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.event_data, failures))
1006 sys.exit( self.stats.show() )
1008 except KeyboardInterrupt:
1009 print "\nNOTE: KeyboardInterrupt - Build not completed."
1012 def get_bbfiles( self, path = os.getcwd() ):
1013 """Get list of default .bb files by reading out the current directory"""
1014 contents = os.listdir(path)
1017 (root, ext) = os.path.splitext(f)
1019 bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
1022 def find_bbfiles( self, path ):
1023 """Find all the .bb files in a directory (uses find)"""
1024 findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
1026 finddata = os.popen(findcmd)
1029 return finddata.readlines()
1031 def collect_bbfiles( self, progressCallback ):
1032 """Collect all available .bb build files"""
1033 self.cb = progressCallback
1034 parsed, cached, skipped, masked = 0, 0, 0, 0
1035 self.bb_cache = bb.cache.init(self)
1037 files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
1038 data.setVar("BBFILES", " ".join(files), self.configuration.data)
1041 files = self.get_bbfiles()
1044 bb.error("no files to build.")
1048 if os.path.isdir(f):
1049 dirfiles = self.find_bbfiles(f)
1051 newfiles += dirfiles
1053 newfiles += glob.glob(f) or [ f ]
1055 bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1) or ""
1057 bbmask_compiled = re.compile(bbmask)
1058 except sre_constants.error:
1059 bb.fatal("BBMASK is not a valid regular expression.")
1061 for i in xrange( len( newfiles ) ):
1063 if bbmask and bbmask_compiled.search(f):
1064 bb.debug(1, "bbmake: skipping %s" % f)
1067 debug(1, "bbmake: parsing %s" % f)
1069 # read a file's metadata
1071 fromCache, skip = self.bb_cache.loadData(f, self)
1074 #bb.note("Skipping %s" % f)
1075 self.bb_cache.skip(f)
1077 elif fromCache: cached += 1
1081 # allow metadata files to add items to BBFILES
1082 #data.update_data(self.pkgdata[f])
1083 addbbfiles = self.bb_cache.getVar('BBFILES', f, False) or None
1085 for aof in addbbfiles.split():
1086 if not files.count(aof):
1087 if not os.path.isabs(aof):
1088 aof = os.path.join(os.path.dirname(f),aof)
1091 # now inform the caller
1092 if self.cb is not None:
1093 self.cb( i + 1, len( newfiles ), f, self.bb_cache, fromCache )
1096 self.bb_cache.remove(f)
1097 bb.error("opening %s: %s" % (f, e))
1099 except KeyboardInterrupt:
1100 self.bb_cache.sync()
1102 except Exception, e:
1103 self.bb_cache.remove(f)
1104 bb.error("%s while parsing %s" % (e, f))
1106 self.bb_cache.remove(f)
1109 if self.cb is not None:
1110 print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ),
1112 self.bb_cache.sync()
1114 #============================================================================#
1116 #============================================================================#
1119 parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
1120 usage = """%prog [options] [package ...]
1122 Executes the specified task (default is 'build') for a given set of BitBake files.
1123 It expects that BBFILES is defined, which is a space seperated list of files to
1124 be executed. BBFILES does support wildcards.
1125 Default BBFILES are the .bb files in the current directory.""" )
1127 parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
1128 action = "store", dest = "buildfile", default = None )
1130 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.",
1131 action = "store_false", dest = "abort", default = True )
1133 parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
1134 action = "store_true", dest = "force", default = False )
1136 parser.add_option( "-i", "--interactive", help = "drop into the interactive mode also called the BitBake shell.",
1137 action = "store_true", dest = "interactive", default = False )
1139 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",
1140 action = "store", dest = "cmd", default = "build" )
1142 parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
1143 action = "append", dest = "file", default = [] )
1145 parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
1146 action = "store_true", dest = "verbose", default = False )
1148 parser.add_option( "-D", "--debug", help = "Increase the debug level. You can specify this more than once.",
1149 action = "count", dest="debug", default = 0)
1151 parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
1152 action = "store_true", dest = "dry_run", default = False )
1154 parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
1155 action = "store_true", dest = "parse_only", default = False )
1157 parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
1158 action = "store_true", dest = "disable_psyco", default = False )
1160 parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
1161 action = "store_true", dest = "show_versions", default = False )
1163 parser.add_option( "-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
1164 action = "store_true", dest = "show_environment", default = False )
1166 parser.add_option( "-g", "--graphviz", help = "emit the dependency trees of the specified packages in the dot syntax",
1167 action = "store_true", dest = "dot_graph", default = False )
1168 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""",
1169 action = "append", dest = "ignored_dot_deps", default = [] )
1172 options, args = parser.parse_args( sys.argv )
1175 cooker.cook( BBConfiguration( options ), args[1:] )
1179 if __name__ == "__main__":
1180 print """WARNING, WARNING, WARNING
1181 This is a Bitbake from the Unstable/Development Branch.
1182 You might want to use the bitbake-1.4 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."""