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, event, cache, providers
29 import itertools, optparse
31 parsespin = itertools.cycle( r'|/-\\' )
35 #============================================================================#
37 #============================================================================#
38 class BBParsingStatus:
40 The initial idea for this status class is to use the data when it is
41 already loaded instead of loading it from various place over and over
49 self.packages_dynamic = {}
50 self.bbfile_priority = {}
51 self.bbfile_config_priorities = []
52 self.ignored_dependencies = None
53 self.possible_world = []
54 self.world_target = Set()
60 self.all_depends = Set()
66 def handle_bb_data(self, file_name, bb_cache, cached):
68 We will fill the dictionaries with the stuff we
69 need for building the tree more fast
72 pn = bb_cache.getVar('PN', file_name, True)
73 pv = bb_cache.getVar('PV', file_name, True)
74 pr = bb_cache.getVar('PR', file_name, True)
75 dp = int(bb_cache.getVar('DEFAULT_PREFERENCE', file_name, True) or "0")
76 provides = Set([pn] + (bb_cache.getVar("PROVIDES", file_name, True) or "").split())
77 depends = (bb_cache.getVar("DEPENDS", file_name, True) or "").split()
78 packages = (bb_cache.getVar('PACKAGES', file_name, True) or "").split()
79 packages_dynamic = (bb_cache.getVar('PACKAGES_DYNAMIC', file_name, True) or "").split()
80 rprovides = (bb_cache.getVar("RPROVIDES", file_name, True) or "").split()
82 # build PackageName to FileName lookup table
83 if pn not in self.pkg_pn:
85 self.pkg_pn[pn].append(file_name)
87 self.build_all[file_name] = int(bb_cache.getVar('BUILD_ALL_DEPS', file_name, True) or "0")
88 self.stamp[file_name] = bb_cache.getVar('STAMP', file_name, True)
90 # build FileName to PackageName lookup table
91 self.pkg_fn[file_name] = pn
92 self.pkg_pvpr[file_name] = (pv,pr)
93 self.pkg_dp[file_name] = dp
95 # Build forward and reverse provider hashes
96 # Forward: virtual -> [filenames]
97 # Reverse: PN -> [virtuals]
98 if pn not in self.pn_provides:
99 self.pn_provides[pn] = Set()
100 self.pn_provides[pn] |= provides
102 for provide in provides:
103 if provide not in self.providers:
104 self.providers[provide] = []
105 self.providers[provide].append(file_name)
108 self.all_depends.add(dep)
110 # Build reverse hash for PACKAGES, so runtime dependencies
111 # can be be resolved (RDEPENDS, RRECOMMENDS etc.)
112 for package in packages:
113 if not package in self.packages:
114 self.packages[package] = []
115 self.packages[package].append(file_name)
116 rprovides += (bb_cache.getVar("RPROVIDES_%s" % package, file_name, 1) or "").split()
118 for package in packages_dynamic:
119 if not package in self.packages_dynamic:
120 self.packages_dynamic[package] = []
121 self.packages_dynamic[package].append(file_name)
123 for rprovide in rprovides:
124 if not rprovide in self.rproviders:
125 self.rproviders[rprovide] = []
126 self.rproviders[rprovide].append(file_name)
128 # Build hash of runtime depeneds and rececommends
130 def add_dep(deplist, deps):
132 if not dep in deplist:
135 if not file_name in self.rundeps:
136 self.rundeps[file_name] = {}
137 if not file_name in self.runrecs:
138 self.runrecs[file_name] = {}
140 for package in packages + [pn]:
141 if not package in self.rundeps[file_name]:
142 self.rundeps[file_name][package] = {}
143 if not package in self.runrecs[file_name]:
144 self.runrecs[file_name][package] = {}
146 add_dep(self.rundeps[file_name][package], bb.utils.explode_deps(bb_cache.getVar('RDEPENDS', file_name, True) or ""))
147 add_dep(self.runrecs[file_name][package], bb.utils.explode_deps(bb_cache.getVar('RRECOMMENDS', file_name, True) or ""))
148 add_dep(self.rundeps[file_name][package], bb.utils.explode_deps(bb_cache.getVar("RDEPENDS_%s" % package, file_name, True) or ""))
149 add_dep(self.runrecs[file_name][package], bb.utils.explode_deps(bb_cache.getVar("RRECOMMENDS_%s" % package, file_name, True) or ""))
151 # Collect files we may need for possible world-dep
153 if not bb_cache.getVar('BROKEN', file_name, True) and not bb_cache.getVar('EXCLUDE_FROM_WORLD', file_name, True):
154 self.possible_world.append(file_name)
157 #============================================================================#
159 #============================================================================#
162 Manage build statistics for one run
171 print "Build statistics:"
172 print " Attempted builds: %d" % self.attempt
174 print " Failed builds: %d" % self.fail
176 print " Dependencies not satisfied: %d" % self.deps
177 if self.fail or self.deps: return 1
181 #============================================================================#
183 #============================================================================#
184 class BBConfiguration( object ):
186 Manages build options and configurations for one run
188 def __init__( self, options ):
189 for key, val in options.__dict__.items():
190 setattr( self, key, val )
192 #============================================================================#
194 #============================================================================#
197 Manages one bitbake build run
200 ParsingStatus = BBParsingStatus # make it visible from the shell
201 Statistics = BBStatistics # make it visible from the shell
203 def __init__( self ):
204 self.build_cache_fail = []
205 self.build_cache = []
206 self.rbuild_cache = []
207 self.building_list = []
209 self.consider_msgs_cache = []
211 self.stats = BBStatistics()
217 def tryBuildPackage( self, fn, item, the_data ):
218 """Build one package"""
219 bb.event.fire(bb.event.PkgStarted(item, the_data))
221 self.stats.attempt += 1
222 if self.configuration.force:
223 bb.data.setVarFlag('do_%s' % self.configuration.cmd, 'force', 1, the_data)
224 if not self.configuration.dry_run:
225 bb.build.exec_task('do_%s' % self.configuration.cmd, the_data)
226 bb.event.fire(bb.event.PkgSucceeded(item, the_data))
227 self.build_cache.append(fn)
229 except bb.build.FuncFailed:
231 bb.msg.error(bb.msg.domain.Build, "task stack execution failed")
232 bb.event.fire(bb.event.PkgFailed(item, the_data))
233 self.build_cache_fail.append(fn)
235 except bb.build.EventException, e:
238 bb.msg.error(bb.msg.domain.Build, "%s event exception, aborting" % bb.event.getName(event))
239 bb.event.fire(bb.event.PkgFailed(item, the_data))
240 self.build_cache_fail.append(fn)
243 def tryBuild( self, fn, virtual , buildAllDeps , build_depends = []):
245 Build a provider and its dependencies.
246 build_depends is a list of previous build dependencies (not runtime)
247 If build_depends is empty, we're dealing with a runtime depends
250 the_data = self.bb_cache.loadDataFull(fn, self)
252 # Only follow all (runtime) dependencies if doing a build
253 if not buildAllDeps and self.configuration.cmd is "build":
254 buildAllDeps = self.status.build_all[fn]
256 # Error on build time dependency loops
257 if build_depends and build_depends.count(fn) > 1:
258 bb.msg.error(bb.msg.domain.Depends, "%s depends on itself (eventually)" % fn)
259 bb.msg.error(bb.msg.domain.Depends, "upwards chain is: %s" % (" -> ".join(self.build_path)))
262 # See if this is a runtime dependency we've already built
263 # Or a build dependency being handled in a different build chain
264 if fn in self.building_list:
265 return self.addRunDeps(fn, virtual , buildAllDeps)
267 item = self.status.pkg_fn[fn]
269 self.building_list.append(fn)
271 pathstr = "%s (%s)" % (item, virtual)
272 self.build_path.append(pathstr)
274 depends_list = (bb.data.getVar('DEPENDS', the_data, True) or "").split()
276 bb.msg.note(2, bb.msg.domain.Depends, "current path: %s" % (" -> ".join(self.build_path)))
277 bb.msg.note(2, bb.msg.domain.Depends, "dependencies for %s are: %s" % (item, " ".join(depends_list)))
282 depcmd = self.configuration.cmd
283 bbdepcmd = bb.data.getVarFlag('do_%s' % self.configuration.cmd, 'bbdepcmd', the_data)
284 if bbdepcmd is not None:
291 oldcmd = self.configuration.cmd
292 self.configuration.cmd = depcmd
294 for dependency in depends_list:
295 if dependency in self.status.ignored_dependencies:
299 if self.buildProvider( dependency , buildAllDeps , build_depends ) == 0:
300 bb.msg.error(bb.msg.domain.Depends, "dependency %s (for %s) not satisfied" % (dependency,item))
302 if self.configuration.abort:
306 self.configuration.cmd = oldcmd
312 if not self.addRunDeps(fn, virtual , buildAllDeps):
315 if bb.build.stamp_is_current('do_%s' % self.configuration.cmd, the_data):
316 self.build_cache.append(fn)
319 return self.tryBuildPackage( fn, item, the_data )
322 self.building_list.remove(fn)
323 self.build_path.remove(pathstr)
326 def showVersions( self ):
327 pkg_pn = self.status.pkg_pn
328 preferred_versions = {}
332 for pn in pkg_pn.keys():
333 (last_ver,last_file,pref_ver,pref_file) = self.findBestProvider(pn, self.configuration.data, self.status)
334 preferred_versions[pn] = (pref_ver, pref_file)
335 latest_versions[pn] = (last_ver, last_file)
337 pkg_list = pkg_pn.keys()
341 pref = preferred_versions[p]
342 latest = latest_versions[p]
345 prefstr = pref[0][0] + "-" + pref[0][1]
349 print "%-30s %20s %20s" % (p, latest[0][0] + "-" + latest[0][1],
353 def showEnvironment( self ):
354 """Show the outer or per-package environment"""
355 if self.configuration.buildfile:
357 self.bb_cache = bb.cache.init(self)
359 self.configuration.data = self.bb_cache.loadDataFull(self.configuration.buildfile, self)
361 bb.msg.fatal(bb.msg.domain.Parsing, "Unable to read %s: %s" % ( self.configuration.buildfile, e ))
363 bb.msg.fatal(bb.msg.domain.Parsing, "%s" % e)
364 # emit variables and shell functions
366 data.update_data( self.configuration.data )
367 data.emit_env(sys.__stdout__, self.configuration.data, True)
369 bb.msg.fatal(bb.msg.domain.Parsing, "%s" % e)
370 # emit the metadata which isnt valid shell
371 for e in self.configuration.data.keys():
372 if data.getVarFlag( e, 'python', self.configuration.data ):
373 sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, self.configuration.data, 1)))
375 def generateDotGraph( self, pkgs_to_build, ignore_deps ):
377 Generate two graphs one for the DEPENDS and RDEPENDS. The current
378 implementation creates crappy graphs ;)
380 pkgs_to_build A list of packages that needs to be built
381 ignore_deps A list of names where processing of dependencies
382 should be stopped. e.g. dependencies that get
385 def myFilterProvider( providers, item):
387 Take a list of providers and filter according to environment
388 variables. In contrast to filterProviders we do not discriminate
389 and take PREFERRED_PROVIDER into account.
392 preferred_versions = {}
394 # Collate providers by PN
397 pn = self.status.pkg_fn[p]
402 bb.msg.debug(1, bb.msg.domain.Provider, "providers for %s are: %s" % (item, pkg_pn.keys()))
404 for pn in pkg_pn.keys():
405 preferred_versions[pn] = self.findBestProvider(pn, pkg_pn)[2:4]
406 eligible.append(preferred_versions[pn][1])
409 if p in self.build_cache_fail:
410 bb.msg.debug(1, bb.msg.domain.Provider, "rejecting already-failed %s" % p)
413 if len(eligible) == 0:
414 bb.msg.error(bb.msg.domain.Provider, "no eligible providers for %s" % item)
417 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
419 # try the preferred provider first
422 if prefervar == self.status.pkg_fn[p]:
423 bb.msg.note(1, bb.msg.domain.Provider, "Selecting PREFERRED_PROVIDER %s" % prefervar)
425 eligible = [p] + eligible
432 # try to avoid adding the same rdepends over an over again
437 def add_depends(package_list):
439 Add all depends of all packages from this list
441 for package in package_list:
442 if package in seen_depends or package in ignore_deps:
445 seen_depends.append( package )
446 if not package in self.status.providers:
448 We have not seen this name -> error in
451 bb.note( "ERROR with provider: %(package)s" % vars() )
452 print >> depends_file, '"%(package)s" -> ERROR' % vars()
455 # get all providers for this package
456 providers = self.status.providers[package]
458 # now let us find the bestProvider for it
459 fn = myFilterProvider(providers, package)[0]
461 depends = bb.utils.explode_deps(self.bb_cache.getVar('DEPENDS', fn, True) or "")
462 version = self.bb_cache.getVar('PV', fn, True ) + '-' + self.bb_cache.getVar('PR', fn, True)
463 add_depends ( depends )
465 # now create the node
466 print >> depends_file, '"%(package)s" [label="%(package)s\\n%(version)s"]' % vars()
468 depends = filter( (lambda x: x not in ignore_deps), depends )
469 for depend in depends:
470 print >> depends_file, '"%(package)s" -> "%(depend)s"' % vars()
473 def add_all_depends( the_depends, the_rdepends ):
475 Add both DEPENDS and RDEPENDS. RDEPENDS will get dashed
478 package_list = the_depends + the_rdepends
479 for package in package_list:
480 if package in seen_rdepends or package in ignore_deps:
483 seen_rdepends.append( package )
485 # Let us find out if the package is a DEPENDS or RDEPENDS
486 # and we will set 'providers' with the avilable providers
488 if package in the_depends:
489 if not package in self.status.providers:
490 bb.note( "ERROR with provider: %(package)s" % vars() )
491 print >> alldepends_file, '"%(package)s" -> ERROR' % vars()
494 providers = self.status.providers[package]
495 elif package in the_rdepends:
496 if len(self.getProvidersRun(package)) == 0:
497 bb.note( "ERROR with rprovider: %(package)s" % vars() )
498 print >> alldepends_file, '"%(package)s" -> ERROR [style="dashed"]' % vars()
501 providers = self.getProvidersRun(package)
503 # something went wrong...
504 print "Complete ERROR! %s" % package
507 # now let us find the bestProvider for it
508 fn = myFilterProvider(providers, package)[0]
510 # Now we have a filename let us get the depends and RDEPENDS of it
511 depends = bb.utils.explode_deps(self.bb_cache.getVar('DEPENDS', fn, True) or "")
512 if fn in self.status.rundeps and package in self.status.rundeps[fn]:
513 rdepends= self.status.rundeps[fn][package].keys()
516 version = self.bb_cache.getVar('PV', fn, True ) + '-' + self.bb_cache.getVar('PR', fn, True)
518 # handle all the depends and rdepends of package
519 add_all_depends ( depends, rdepends )
521 # now create the node using package name
522 print >> alldepends_file, '"%(package)s" [label="%(package)s\\n%(version)s"]' % vars()
524 # remove the stuff we want to ignore and add the edges
525 depends = filter( (lambda x: x not in ignore_deps), depends )
526 rdepends = filter( (lambda x: x not in ignore_deps), rdepends )
527 for depend in depends:
528 print >> alldepends_file, '"%(package)s" -> "%(depend)s"' % vars()
529 for depend in rdepends:
530 print >> alldepends_file, '"%(package)s" -> "%(depend)s" [style=dashed]' % vars()
534 depends_file = file('depends.dot', 'w' )
535 print >> depends_file, "digraph depends {"
536 add_depends( pkgs_to_build )
537 print >> depends_file, "}"
539 # Add all depends now
540 alldepends_file = file('alldepends.dot', 'w' )
541 print >> alldepends_file, "digraph alldepends {"
542 add_all_depends( pkgs_to_build, [] )
543 print >> alldepends_file, "}"
545 def buildProvider( self, item , buildAllDeps , build_depends = [] ):
547 Build something to provide a named build requirement
548 (takes item names from DEPENDS namespace)
552 discriminated = False
554 if not item in self.status.providers:
555 bb.msg.error(bb.msg.domain.Depends, "Nothing provides dependency %s" % item)
556 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
559 all_p = self.status.providers[item]
562 if p in self.build_cache:
563 bb.msg.debug(1, bb.msg.domain.Provider, "already built %s in this run" % p)
566 eligible = bb.providers.filterProviders(all_p, item, self.configuration.data, self.status, self.build_cache_fail)
571 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
573 self.preferred[item] = prefervar
575 if item in self.preferred:
577 pn = self.status.pkg_fn[p]
578 if self.preferred[item] == pn:
579 bb.msg.note(2, bb.msg.domain.Provider, "selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
581 eligible = [p] + eligible
585 if len(eligible) > 1 and discriminated == False:
586 if item not in self.consider_msgs_cache:
589 providers_list.append(self.status.pkg_fn[fn])
590 bb.msg.note(1, bb.msg.domain.Provider, "multiple providers are available (%s);" % ", ".join(providers_list))
591 bb.msg.note(1, bb.msg.domain.Provider, "consider defining PREFERRED_PROVIDER_%s" % item)
592 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data))
593 self.consider_msgs_cache.append(item)
596 # run through the list until we find one that we can build
598 bb.msg.debug(2, bb.msg.domain.Provider, "selecting %s to satisfy %s" % (fn, item))
599 if self.tryBuild(fn, item, buildAllDeps, build_depends + [fn]):
602 bb.msg.note(1, bb.msg.domain.Provider, "no buildable providers for %s" % item)
603 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
606 def buildRProvider( self, item , buildAllDeps ):
608 Build something to provide a named runtime requirement
609 (takes item names from RDEPENDS/PACKAGES namespace)
614 discriminated = False
619 all_p = self.getProvidersRun(item)
622 bb.msg.error(bb.msg.domain.Provider, "Nothing provides runtime dependency %s" % (item))
623 bb.event.fire(bb.event.NoProvider(item,self.configuration.data,runtime=True))
627 if p in self.rbuild_cache:
628 bb.msg.debug(2, bb.msg.domain.Provider, "Already built %s providing runtime %s" % (p,item))
630 if p in self.build_cache:
631 bb.msg.debug(2, bb.msg.domain.Provider, "Already built %s but adding any further RDEPENDS for %s" % (p, item))
632 return self.addRunDeps(p, item , buildAllDeps)
634 eligible = bb.providers.filterProviders(all_p, item, self.configuration.data, self.status, self.build_cache_fail)
640 pn = self.status.pkg_fn[p]
641 provides = self.status.pn_provides[pn]
642 for provide in provides:
643 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, self.configuration.data, 1)
645 bb.msg.note(2, bb.msg.domain.Provider, "selecting %s to satisfy runtime %s due to PREFERRED_PROVIDERS" % (pn, item))
647 eligible = [p] + eligible
650 if len(eligible) > 1 and len(preferred) == 0:
651 if item not in self.consider_msgs_cache:
654 providers_list.append(self.status.pkg_fn[fn])
655 bb.msg.note(1, bb.msg.domain.Provider, "multiple providers are available (%s);" % ", ".join(providers_list))
656 bb.msg.note(1, bb.msg.domain.Provider, "consider defining a PREFERRED_PROVIDER to match runtime %s" % item)
657 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
658 self.consider_msgs_cache.append(item)
660 if len(preferred) > 1:
661 if item not in self.consider_msgs_cache:
664 providers_list.append(self.status.pkg_fn[fn])
665 bb.msg.note(1, bb.msg.domain.Provider, "multiple preferred providers are available (%s);" % ", ".join(providers_list))
666 bb.msg.note(1, bb.msg.domain.Provider, "consider defining only one PREFERRED_PROVIDER to match runtime %s" % item)
667 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
668 self.consider_msgs_cache.append(item)
670 # run through the list until we find one that we can build
672 bb.msg.debug(2, bb.msg.domain.Provider, "selecting %s to satisfy runtime %s" % (fn, item))
673 if self.tryBuild(fn, item, buildAllDeps):
676 bb.msg.error(bb.msg.domain.Provider, "No buildable providers for runtime %s" % item)
677 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
680 def getProvidersRun(self, rdepend):
682 Return any potential providers of runtime rdepend
686 if rdepend in self.status.rproviders:
687 rproviders += self.status.rproviders[rdepend]
689 if rdepend in self.status.packages:
690 rproviders += self.status.packages[rdepend]
695 # Only search dynamic packages if we can't find anything in other variables
696 for pattern in self.status.packages_dynamic:
697 regexp = re.compile(pattern)
698 if regexp.match(rdepend):
699 rproviders += self.status.packages_dynamic[pattern]
703 def addRunDeps(self , fn, item , buildAllDeps):
705 Add any runtime dependencies of runtime item provided by fn
706 as long as item has't previously been processed by this function.
709 if item in self.rbuild_cache:
716 self.rbuild_cache.append(item)
718 if fn in self.status.rundeps and item in self.status.rundeps[fn]:
719 rdepends += self.status.rundeps[fn][item].keys()
720 if fn in self.status.runrecs and item in self.status.runrecs[fn]:
721 rdepends += self.status.runrecs[fn][item].keys()
723 bb.msg.debug(2, bb.msg.domain.Provider, "Additional runtime dependencies for %s are: %s" % (item, " ".join(rdepends)))
725 for rdepend in rdepends:
726 if rdepend in self.status.ignored_dependencies:
728 if not self.buildRProvider(rdepend, buildAllDeps):
732 def buildDepgraph( self ):
733 all_depends = self.status.all_depends
734 pn_provides = self.status.pn_provides
736 localdata = data.createCopy(self.configuration.data)
737 bb.data.update_data(localdata)
739 def calc_bbfile_priority(filename):
740 for (regex, pri) in self.status.bbfile_config_priorities:
741 if regex.match(filename):
745 # Handle PREFERRED_PROVIDERS
746 for p in (bb.data.getVar('PREFERRED_PROVIDERS', localdata, 1) or "").split():
747 (providee, provider) = p.split(':')
748 if providee in self.preferred and self.preferred[providee] != provider:
749 bb.msg.error(bb.msg.domain.Provider, "conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.preferred[providee]))
750 self.preferred[providee] = provider
752 # Calculate priorities for each file
753 for p in self.status.pkg_fn.keys():
754 self.status.bbfile_priority[p] = calc_bbfile_priority(p)
756 def buildWorldTargetList(self):
758 Build package list for "bitbake world"
760 all_depends = self.status.all_depends
761 pn_provides = self.status.pn_provides
762 bb.msg.debug(1, bb.msg.domain.Parsing, "collating packages for \"world\"")
763 for f in self.status.possible_world:
765 pn = self.status.pkg_fn[f]
767 for p in pn_provides[pn]:
768 if p.startswith('virtual/'):
769 bb.msg.debug(2, bb.msg.domain.Parsing, "World build skipping %s due to %s provider starting with virtual/" % (f, p))
772 for pf in self.status.providers[p]:
773 if self.status.pkg_fn[pf] != pn:
774 bb.msg.debug(2, bb.msg.domain.Parsing, "World build skipping %s due to both us and %s providing %s" % (f, pf, p))
778 self.status.world_target.add(pn)
780 # drop reference count now
781 self.status.possible_world = None
782 self.status.all_depends = None
784 def myProgressCallback( self, x, y, f, bb_cache, from_cache ):
785 # feed the status with new input
787 self.status.handle_bb_data(f, bb_cache, from_cache)
789 if os.isatty(sys.stdout.fileno()):
790 sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
794 sys.stdout.write("Parsing .bb files, please wait...")
797 sys.stdout.write("done.")
800 def interactiveMode( self ):
801 """Drop off into a shell"""
804 except ImportError, details:
805 bb.msg.fatal(bb.msg.domain.Parsing, "Sorry, shell not available (%s)" % details )
807 bb.data.update_data( self.configuration.data )
811 def parseConfigurationFile( self, afile ):
813 self.configuration.data = bb.parse.handle( afile, self.configuration.data )
815 # Add the handlers we inherited by INHERIT
816 # we need to do this manually as it is not guranteed
817 # we will pick up these classes... as we only INHERIT
818 # on .inc and .bb files but not on .conf
819 data = bb.data.createCopy( self.configuration.data )
820 inherits = ["base"] + (bb.data.getVar('INHERIT', data, True ) or "").split()
821 for inherit in inherits:
822 data = bb.parse.handle( os.path.join('classes', '%s.bbclass' % inherit ), data, True )
824 # FIXME: This assumes that we included at least one .inc file
825 for var in bb.data.keys(data):
826 if bb.data.getVarFlag(var, 'handler', data):
827 bb.event.register(var,bb.data.getVar(var, data))
830 bb.msg.fatal(bb.msg.domain.Parsing, "Unable to open %s" % afile )
831 except bb.parse.ParseError, details:
832 bb.msg.fatal(bb.msg.domain.Parsing, "Unable to parse %s (%s)" % (afile, details) )
834 def handleCollections( self, collections ):
835 """Handle collections"""
837 collection_list = collections.split()
838 for c in collection_list:
839 regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1)
841 bb.msg.error(bb.msg.domain.Parsing, "BBFILE_PATTERN_%s not defined" % c)
843 priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1)
845 bb.msg.error(bb.msg.domain.Parsing, "BBFILE_PRIORITY_%s not defined" % c)
848 cre = re.compile(regex)
850 bb.msg.error(bb.msg.domain.Parsing, "BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
854 self.status.bbfile_config_priorities.append((cre, pri))
856 bb.msg.error(bb.msg.domain.Parsing, "invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
859 def cook( self, configuration, args ):
861 We are building stuff here. We do the building
862 from here. By default we try to execute task
866 self.configuration = configuration
868 if self.configuration.verbose:
869 bb.msg.set_verbose(True)
871 if not self.configuration.cmd:
872 self.configuration.cmd = "build"
874 if self.configuration.debug:
875 bb.msg.set_debug_level(self.configuration.debug)
877 self.configuration.data = bb.data.init()
879 for f in self.configuration.file:
880 self.parseConfigurationFile( f )
882 self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
886 # Special updated configuration we use for firing events
888 self.configuration.event_data = bb.data.createCopy(self.configuration.data)
889 bb.data.update_data(self.configuration.event_data)
891 if self.configuration.show_environment:
892 self.showEnvironment()
895 # inject custom variables
896 if not bb.data.getVar("BUILDNAME", self.configuration.data):
897 bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
898 bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data)
900 buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
902 if self.configuration.interactive:
903 self.interactiveMode()
905 if self.configuration.buildfile is not None:
906 bf = os.path.abspath( self.configuration.buildfile )
908 bbfile_data = bb.parse.handle(bf, self.configuration.data)
910 bb.msg.fatal(bb.msg.domain.Parsing, "Unable to open %s" % bf)
912 item = bb.data.getVar('PN', bbfile_data, 1)
914 self.tryBuildPackage( bf, item, bbfile_data )
915 except bb.build.EventException:
916 bb.msg.error(bb.msg.domain.Build, "Build of '%s' failed" % item )
918 sys.exit( self.stats.show() )
920 # initialise the parsing status now we know we will need deps
921 self.status = BBParsingStatus()
923 ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
924 self.status.ignored_dependencies = Set( ignore.split() )
926 self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
930 if not pkgs_to_build:
932 pkgs_to_build.extend(args)
933 if not pkgs_to_build:
934 bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
936 pkgs_to_build = bbpkgs.split()
937 if not pkgs_to_build and not self.configuration.show_versions \
938 and not self.configuration.interactive \
939 and not self.configuration.show_environment:
940 print "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help'"
941 print "for usage information."
944 # Import Psyco if available and not disabled
945 if not self.configuration.disable_psyco:
949 bb.msg.note(1, bb.msg.domain.Collection, "Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
951 psyco.bind( self.collect_bbfiles )
953 bb.msg.note(1, bb.msg.domain.Collection, "You have disabled Psyco. This decreases performance.")
956 bb.msg.debug(1, bb.msg.domain.Collection, "collecting .bb files")
957 self.collect_bbfiles( self.myProgressCallback )
958 bb.msg.debug(1, bb.msg.domain.Collection, "parsing complete")
960 if self.configuration.parse_only:
961 bb.msg.note(1, bb.msg.domain.Collection, "Requested parsing .bb files only. Exiting.")
967 if self.configuration.show_versions:
970 if 'world' in pkgs_to_build:
971 self.buildWorldTargetList()
972 pkgs_to_build.remove('world')
973 for t in self.status.world_target:
974 pkgs_to_build.append(t)
976 if self.configuration.dot_graph:
977 self.generateDotGraph( pkgs_to_build, self.configuration.ignored_dot_deps )
981 bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.event_data))
984 for k in pkgs_to_build:
987 if self.buildProvider( k , False ) == 0:
990 except bb.build.EventException:
991 bb.msg.error(bb.msg.domain.Build, "Build of " + k + " failed")
996 if self.configuration.abort:
999 bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.event_data, failures))
1001 sys.exit( self.stats.show() )
1003 except KeyboardInterrupt:
1004 bb.msg.note(1, bb.msg.domain.Collection, "KeyboardInterrupt - Build not completed.")
1007 def get_bbfiles( self, path = os.getcwd() ):
1008 """Get list of default .bb files by reading out the current directory"""
1009 contents = os.listdir(path)
1012 (root, ext) = os.path.splitext(f)
1014 bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
1017 def find_bbfiles( self, path ):
1018 """Find all the .bb files in a directory (uses find)"""
1019 findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
1021 finddata = os.popen(findcmd)
1024 return finddata.readlines()
1026 def collect_bbfiles( self, progressCallback ):
1027 """Collect all available .bb build files"""
1028 self.cb = progressCallback
1029 parsed, cached, skipped, masked = 0, 0, 0, 0
1030 self.bb_cache = bb.cache.init(self)
1032 files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
1033 data.setVar("BBFILES", " ".join(files), self.configuration.data)
1036 files = self.get_bbfiles()
1039 bb.msg.error(bb.msg.domain.Collection, "no files to build.")
1043 if os.path.isdir(f):
1044 dirfiles = self.find_bbfiles(f)
1046 newfiles += dirfiles
1048 newfiles += glob.glob(f) or [ f ]
1050 bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1) or ""
1052 bbmask_compiled = re.compile(bbmask)
1053 except sre_constants.error:
1054 bb.msg.fatal(bb.msg.domain.Collection, "BBMASK is not a valid regular expression.")
1056 for i in xrange( len( newfiles ) ):
1058 if bbmask and bbmask_compiled.search(f):
1059 bb.msg.debug(1, bb.msg.domain.Collection, "bbmake: skipping %s" % f, f)
1062 bb.msg.debug(1, bb.msg.domain.Collection, "bbmake: parsing %s" % f, f)
1064 # read a file's metadata
1066 fromCache, skip = self.bb_cache.loadData(f, self)
1069 bb.msg.debug(2, bb.msg.domain.Collection, "Skipping %s" % f, f)
1070 self.bb_cache.skip(f)
1072 elif fromCache: cached += 1
1076 # allow metadata files to add items to BBFILES
1077 #data.update_data(self.pkgdata[f])
1078 addbbfiles = self.bb_cache.getVar('BBFILES', f, False) or None
1080 for aof in addbbfiles.split():
1081 if not files.count(aof):
1082 if not os.path.isabs(aof):
1083 aof = os.path.join(os.path.dirname(f),aof)
1086 # now inform the caller
1087 if self.cb is not None:
1088 self.cb( i + 1, len( newfiles ), f, self.bb_cache, fromCache )
1091 self.bb_cache.remove(f)
1092 bb.msg.error(bb.msg.domain.Collection, "opening %s: %s" % (f, e), f)
1094 except KeyboardInterrupt:
1095 self.bb_cache.sync()
1097 except Exception, e:
1098 self.bb_cache.remove(f)
1099 bb.msg.error(bb.msg.domain.Collection, "%s while parsing %s" % (e, f), f)
1101 self.bb_cache.remove(f)
1104 if self.cb is not None:
1105 print "\r" # need newline after Handling Bitbake files message
1106 bb.msg.note(1, bb.msg.domain.Collection, "Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ))
1108 self.bb_cache.sync()
1110 #============================================================================#
1112 #============================================================================#
1115 parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
1116 usage = """%prog [options] [package ...]
1118 Executes the specified task (default is 'build') for a given set of BitBake files.
1119 It expects that BBFILES is defined, which is a space seperated list of files to
1120 be executed. BBFILES does support wildcards.
1121 Default BBFILES are the .bb files in the current directory.""" )
1123 parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
1124 action = "store", dest = "buildfile", default = None )
1126 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.",
1127 action = "store_false", dest = "abort", default = True )
1129 parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
1130 action = "store_true", dest = "force", default = False )
1132 parser.add_option( "-i", "--interactive", help = "drop into the interactive mode also called the BitBake shell.",
1133 action = "store_true", dest = "interactive", default = False )
1135 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",
1136 action = "store", dest = "cmd", default = "build" )
1138 parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
1139 action = "append", dest = "file", default = [] )
1141 parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
1142 action = "store_true", dest = "verbose", default = False )
1144 parser.add_option( "-D", "--debug", help = "Increase the debug level. You can specify this more than once.",
1145 action = "count", dest="debug", default = 0)
1147 parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
1148 action = "store_true", dest = "dry_run", default = False )
1150 parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
1151 action = "store_true", dest = "parse_only", default = False )
1153 parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
1154 action = "store_true", dest = "disable_psyco", default = False )
1156 parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
1157 action = "store_true", dest = "show_versions", default = False )
1159 parser.add_option( "-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
1160 action = "store_true", dest = "show_environment", default = False )
1162 parser.add_option( "-g", "--graphviz", help = "emit the dependency trees of the specified packages in the dot syntax",
1163 action = "store_true", dest = "dot_graph", default = False )
1164 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""",
1165 action = "append", dest = "ignored_dot_deps", default = [] )
1168 options, args = parser.parse_args( sys.argv )
1171 cooker.cook( BBConfiguration( options ), args[1:] )
1175 if __name__ == "__main__":
1176 print """WARNING, WARNING, WARNING
1177 This is a Bitbake from the Unstable/Development Branch.
1178 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."""