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
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)
327 def findBestProvider( self, pn, pkg_pn = None):
329 If there is a PREFERRED_VERSION, find the highest-priority bbfile
330 providing that version. If not, find the latest version provided by
331 an bbfile in the highest-priority set.
334 pkg_pn = self.status.pkg_pn
339 priority = self.status.bbfile_priority[f]
340 if priority not in priorities:
341 priorities[priority] = []
342 priorities[priority].append(f)
343 p_list = priorities.keys()
344 p_list.sort(lambda a, b: a - b)
347 tmp_pn = [priorities[p]] + tmp_pn
349 preferred_file = None
351 localdata = data.createCopy(self.configuration.data)
352 bb.data.setVar('OVERRIDES', "%s:%s" % (pn, data.getVar('OVERRIDES', localdata)), localdata)
353 bb.data.update_data(localdata)
355 preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, localdata, True)
357 m = re.match('(.*)_(.*)', preferred_v)
359 preferred_v = m.group(1)
360 preferred_r = m.group(2)
364 for file_set in tmp_pn:
366 pv,pr = self.status.pkg_pvpr[f]
367 if preferred_v == pv and (preferred_r == pr or preferred_r == None):
369 preferred_ver = (pv, pr)
374 pv_str = '%s-%s' % (preferred_v, preferred_r)
377 if preferred_file is None:
378 bb.note("preferred version %s of %s not available" % (pv_str, pn))
380 bb.debug(1, "selecting %s as PREFERRED_VERSION %s of package %s" % (preferred_file, pv_str, pn))
384 # get highest priority file set
389 for file_name in files:
390 pv,pr = self.status.pkg_pvpr[file_name]
391 dp = self.status.pkg_dp[file_name]
393 if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pv, pr)) < 0)) or (dp > latest_p):
397 if preferred_file is None:
398 preferred_file = latest_f
399 preferred_ver = latest
401 return (latest,latest_f,preferred_ver, preferred_file)
403 def showVersions( self ):
404 pkg_pn = self.status.pkg_pn
405 preferred_versions = {}
409 for pn in pkg_pn.keys():
410 (last_ver,last_file,pref_ver,pref_file) = self.findBestProvider(pn)
411 preferred_versions[pn] = (pref_ver, pref_file)
412 latest_versions[pn] = (last_ver, last_file)
414 pkg_list = pkg_pn.keys()
418 pref = preferred_versions[p]
419 latest = latest_versions[p]
422 prefstr = pref[0][0] + "-" + pref[0][1]
426 print "%-30s %20s %20s" % (p, latest[0][0] + "-" + latest[0][1],
430 def showEnvironment( self ):
431 """Show the outer or per-package environment"""
432 if self.configuration.buildfile:
434 self.bb_cache = bb.cache.init(self)
436 self.configuration.data = self.bb_cache.loadDataFull(self.configuration.buildfile, self)
438 fatal("Unable to read %s: %s" % ( self.configuration.buildfile, e ))
441 # emit variables and shell functions
443 data.update_data( self.configuration.data )
444 data.emit_env(sys.__stdout__, self.configuration.data, True)
447 # emit the metadata which isnt valid shell
448 for e in self.configuration.data.keys():
449 if data.getVarFlag( e, 'python', self.configuration.data ):
450 sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, self.configuration.data, 1)))
452 def generateDotGraph( self, pkgs_to_build ):
454 Generate two graphs one for the DEPENDS and RDEPENDS. The current
455 implementation creates crappy graphs ;)
458 rdepends_file = file('rdepends.dot', 'w' )
459 depends_file = file('depends.dot', 'w' )
463 print >> depends_file, "digraph depends {"
464 print >> rdepends_file, "digraph rdepends {"
467 # try to avoid adding the same rdepends over an over again
471 added_depends_error = False
473 def add_depends(package_list):
475 Add all depends of all packages from this list
477 for package in package_list:
478 if package in seen_depends:
481 seen_depends[package] = 1
483 if not package in self.status.providers:
485 We have not seen this name -> error in
488 print >> depends_file, '"%(package)s" -> ERROR' % vars()
491 # get all providers for this package
492 providers = self.status.providers[package]
494 # now let us find the bestProvider for it
495 elligible = self.filterProviders(providers, package)
496 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % package, self.configuration.data, 1)
498 # try the preferred provider first
501 if prefervar == self.status.pkg_fn[p]:
502 bb.note("Selecting PREFERRED_PROVIDER %s" % prefervar)
504 elligible = [p] + elligible
507 depends = bb.utils.explode_deps(self.bb_cache.getVar('DEPENDS', fn, True) or "")
508 rdepends = bb.utils.explode_deps(self.bb_cache.getVar('RDEPENDS', fn, True) or "")
509 add_depends( depends )
510 add_rdepends( rdepends )
512 for depend in depends:
513 print >> depends_file, '"%(package)s" -> "%(depend)s"' % vars()
515 def add_rdepends(package_list):
517 for each package of the package_list
518 we will see if we have handled it already
522 # start with the initial list
523 add_depends( pkgs_to_build )
524 add_rdepends( pkgs_to_build )
527 print >> depends_file, "}"
528 print >> rdepends_file, "}"
530 def filterProviders(self, providers, item):
532 Take a list of providers and filter/reorder according to the
533 environment variables and previous build results
536 preferred_versions = {}
538 # Collate providers by PN
541 pn = self.status.pkg_fn[p]
546 bb.debug(1, "providers for %s are: %s" % (item, pkg_pn.keys()))
548 for pn in pkg_pn.keys():
549 preferred_versions[pn] = self.findBestProvider(pn, pkg_pn)[2:4]
550 eligible.append(preferred_versions[pn][1])
553 if p in self.build_cache_fail:
554 bb.debug(1, "rejecting already-failed %s" % p)
557 if len(eligible) == 0:
558 bb.error("no eligible providers for %s" % item)
561 # look to see if one of them is already staged, or marked as preferred.
562 # if so, bump it to the head of the queue
564 pn = self.status.pkg_fn[p]
565 pv, pr = self.status.pkg_pvpr[p]
567 stamp = '%s.do_populate_staging' % self.status.stamp[p]
568 if os.path.exists(stamp):
569 (newvers, fn) = preferred_versions[pn]
570 if not fn in eligible:
571 # package was made ineligible by already-failed check
573 oldver = "%s-%s" % (pv, pr)
574 newver = '-'.join(newvers)
575 if (newver != oldver):
576 extra_chat = "%s (%s) already staged but upgrading to %s to satisfy %s" % (pn, oldver, newver, item)
578 extra_chat = "Selecting already-staged %s (%s) to satisfy %s" % (pn, oldver, item)
579 if self.configuration.verbose:
580 bb.note("%s" % extra_chat)
582 eligible = [fn] + eligible
588 def buildProvider( self, item , buildAllDeps , build_depends = [] ):
590 Build something to provide a named build requirement
591 (takes item names from DEPENDS namespace)
595 discriminated = False
597 if not item in self.status.providers:
598 bb.error("Nothing provides dependency %s" % item)
599 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
602 all_p = self.status.providers[item]
605 if p in self.build_cache:
606 bb.debug(1, "already built %s in this run\n" % p)
609 eligible = self.filterProviders(all_p, item)
614 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
616 self.preferred[item] = prefervar
618 if item in self.preferred:
620 pn = self.status.pkg_fn[p]
621 if self.preferred[item] == pn:
622 if self.configuration.verbose:
623 bb.note("selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
625 eligible = [p] + eligible
629 if len(eligible) > 1 and discriminated == False:
630 if item not in self.consider_msgs_cache:
633 providers_list.append(self.status.pkg_fn[fn])
634 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
635 bb.note("consider defining PREFERRED_PROVIDER_%s" % item)
636 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data))
637 self.consider_msgs_cache.append(item)
640 # run through the list until we find one that we can build
642 bb.debug(2, "selecting %s to satisfy %s" % (fn, item))
643 if self.tryBuild(fn, item, buildAllDeps, build_depends + [fn]):
646 bb.note("no buildable providers for %s" % item)
647 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
650 def buildRProvider( self, item , buildAllDeps ):
652 Build something to provide a named runtime requirement
653 (takes item names from RDEPENDS/PACKAGES namespace)
658 discriminated = False
663 all_p = self.getProvidersRun(item)
666 bb.error("Nothing provides runtime dependency %s" % (item))
667 bb.event.fire(bb.event.NoProvider(item,self.configuration.data,runtime=True))
671 if p in self.rbuild_cache:
672 bb.debug(2, "Already built %s providing runtime %s\n" % (p,item))
674 if p in self.build_cache:
675 bb.debug(2, "Already built %s but adding any further RDEPENDS for %s\n" % (p, item))
676 return self.addRunDeps(p, item , buildAllDeps)
678 eligible = self.filterProviders(all_p, item)
684 pn = self.status.pkg_fn[p]
685 provides = self.status.pn_provides[pn]
686 for provide in provides:
687 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, self.configuration.data, 1)
689 if self.configuration.verbose:
690 bb.note("selecting %s to satisfy runtime %s due to PREFERRED_PROVIDERS" % (pn, item))
692 eligible = [p] + eligible
695 if len(eligible) > 1 and len(preferred) == 0:
696 if item not in self.consider_msgs_cache:
699 providers_list.append(self.status.pkg_fn[fn])
700 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
701 bb.note("consider defining a PREFERRED_PROVIDER to match runtime %s" % item)
702 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
703 self.consider_msgs_cache.append(item)
705 if len(preferred) > 1:
706 if item not in self.consider_msgs_cache:
709 providers_list.append(self.status.pkg_fn[fn])
710 bb.note("multiple preferred providers are available (%s);" % ", ".join(providers_list))
711 bb.note("consider defining only one PREFERRED_PROVIDER to match runtime %s" % item)
712 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
713 self.consider_msgs_cache.append(item)
715 # run through the list until we find one that we can build
717 bb.debug(2, "selecting %s to satisfy runtime %s" % (fn, item))
718 if self.tryBuild(fn, item, buildAllDeps):
721 bb.error("No buildable providers for runtime %s" % item)
722 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
725 def getProvidersRun(self, rdepend):
727 Return any potential providers of runtime rdepend
731 if rdepend in self.status.rproviders:
732 rproviders += self.status.rproviders[rdepend]
734 if rdepend in self.status.packages:
735 rproviders += self.status.packages[rdepend]
740 # Only search dynamic packages if we can't find anything in other variables
741 for pattern in self.status.packages_dynamic:
742 regexp = re.compile(pattern)
743 if regexp.match(rdepend):
744 rproviders += self.status.packages_dynamic[pattern]
748 def addRunDeps(self , fn, item , buildAllDeps):
750 Add any runtime dependencies of runtime item provided by fn
751 as long as item has't previously been processed by this function.
754 if item in self.rbuild_cache:
761 self.rbuild_cache.append(item)
763 if fn in self.status.rundeps and item in self.status.rundeps[fn]:
764 rdepends += self.status.rundeps[fn][item].keys()
765 if fn in self.status.runrecs and item in self.status.runrecs[fn]:
766 rdepends += self.status.runrecs[fn][item].keys()
768 bb.debug(2, "Additional runtime dependencies for %s are: %s" % (item, " ".join(rdepends)))
770 for rdepend in rdepends:
771 if rdepend in self.status.ignored_dependencies:
773 if not self.buildRProvider(rdepend, buildAllDeps):
777 def buildDepgraph( self ):
778 all_depends = self.status.all_depends
779 pn_provides = self.status.pn_provides
781 localdata = data.createCopy(self.configuration.data)
782 bb.data.update_data(localdata)
784 def calc_bbfile_priority(filename):
785 for (regex, pri) in self.status.bbfile_config_priorities:
786 if regex.match(filename):
790 # Handle PREFERRED_PROVIDERS
791 for p in (bb.data.getVar('PREFERRED_PROVIDERS', localdata, 1) or "").split():
792 (providee, provider) = p.split(':')
793 if providee in self.preferred and self.preferred[providee] != provider:
794 bb.error("conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.preferred[providee]))
795 self.preferred[providee] = provider
797 # Calculate priorities for each file
798 for p in self.status.pkg_fn.keys():
799 self.status.bbfile_priority[p] = calc_bbfile_priority(p)
801 def buildWorldTargetList(self):
803 Build package list for "bitbake world"
805 all_depends = self.status.all_depends
806 pn_provides = self.status.pn_provides
807 bb.debug(1, "collating packages for \"world\"")
808 for f in self.status.possible_world:
810 pn = self.status.pkg_fn[f]
812 for p in pn_provides[pn]:
813 if p.startswith('virtual/'):
814 bb.debug(2, "skipping %s due to %s provider starting with virtual/" % (f, p))
817 for pf in self.status.providers[p]:
818 if self.status.pkg_fn[pf] != pn:
819 bb.debug(2, "skipping %s due to both us and %s providing %s" % (f, pf, p))
823 self.status.world_target.add(pn)
825 # drop reference count now
826 self.status.possible_world = None
827 self.status.all_depends = None
829 def myProgressCallback( self, x, y, f, bb_cache, from_cache ):
830 # feed the status with new input
832 self.status.handle_bb_data(f, bb_cache, from_cache)
836 if os.isatty(sys.stdout.fileno()):
837 sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
841 sys.stdout.write("Parsing .bb files, please wait...")
844 sys.stdout.write("done.")
847 def interactiveMode( self ):
848 """Drop off into a shell"""
851 except ImportError, details:
852 bb.fatal("Sorry, shell not available (%s)" % details )
854 bb.data.update_data( self.configuration.data )
858 def parseConfigurationFile( self, afile ):
860 self.configuration.data = bb.parse.handle( afile, self.configuration.data )
862 # Add the handlers we inherited by INHERITS
863 # FIXME: This assumes that we included at least one .inc file
864 for var in bb.data.keys(self.configuration.data):
865 if bb.data.getVarFlag(var, 'handler', self.configuration.data):
866 bb.event.register(var,bb.data.getVar(var,self.configuration.data))
869 bb.fatal( "Unable to open %s" % afile )
870 except bb.parse.ParseError, details:
871 bb.fatal( "Unable to parse %s (%s)" % (afile, details) )
873 def handleCollections( self, collections ):
874 """Handle collections"""
876 collection_list = collections.split()
877 for c in collection_list:
878 regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1)
880 bb.error("BBFILE_PATTERN_%s not defined" % c)
882 priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1)
884 bb.error("BBFILE_PRIORITY_%s not defined" % c)
887 cre = re.compile(regex)
889 bb.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
893 self.status.bbfile_config_priorities.append((cre, pri))
895 bb.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
898 def cook( self, configuration, args ):
900 We are building stuff here. We do the building
901 from here. By default we try to execute task
905 self.configuration = configuration
907 if not self.configuration.cmd:
908 self.configuration.cmd = "build"
910 if self.configuration.debug:
911 bb.debug_level = self.configuration.debug
913 self.configuration.data = bb.data.init()
915 for f in self.configuration.file:
916 self.parseConfigurationFile( f )
918 self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
922 # Special updated configuration we use for firing events
924 self.configuration.event_data = bb.data.createCopy(self.configuration.data)
925 bb.data.update_data(self.configuration.event_data)
927 if self.configuration.show_environment:
928 self.showEnvironment()
931 # inject custom variables
932 if not bb.data.getVar("BUILDNAME", self.configuration.data):
933 bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
934 bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data)
936 buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
938 if self.configuration.interactive:
939 self.interactiveMode()
941 if self.configuration.buildfile is not None:
942 bf = os.path.abspath( self.configuration.buildfile )
944 bbfile_data = bb.parse.handle(bf, self.configuration.data)
946 bb.fatal("Unable to open %s" % bf)
948 item = bb.data.getVar('PN', bbfile_data, 1)
950 self.tryBuildPackage( bf, item, bbfile_data )
951 except bb.build.EventException:
952 bb.error( "Build of '%s' failed" % item )
954 sys.exit( self.stats.show() )
956 # initialise the parsing status now we know we will need deps
957 self.status = BBParsingStatus()
959 ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
960 self.status.ignored_dependencies = Set( ignore.split() )
962 self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
966 if not pkgs_to_build:
968 pkgs_to_build.extend(args)
969 if not pkgs_to_build:
970 bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
972 pkgs_to_build = bbpkgs.split()
973 if not pkgs_to_build and not self.configuration.show_versions \
974 and not self.configuration.interactive \
975 and not self.configuration.show_environment:
976 print "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help'"
977 print "for usage information."
980 # Import Psyco if available and not disabled
981 if not self.configuration.disable_psyco:
986 bb.note("Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
988 psyco.bind( self.collect_bbfiles )
990 bb.note("You have disabled Psyco. This decreases performance.")
993 bb.debug(1, "collecting .bb files")
994 self.collect_bbfiles( self.myProgressCallback )
995 bb.debug(1, "parsing complete")
998 if self.configuration.parse_only:
999 print "Requested parsing .bb files only. Exiting."
1003 self.buildDepgraph()
1005 if self.configuration.show_versions:
1008 if 'world' in pkgs_to_build:
1009 self.buildWorldTargetList()
1010 pkgs_to_build.remove('world')
1011 for t in self.status.world_target:
1012 pkgs_to_build.append(t)
1014 if self.configuration.dot_graph:
1015 self.generateDotGraph( pkgs_to_build )
1019 bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.event_data))
1022 for k in pkgs_to_build:
1025 if self.buildProvider( k , False ) == 0:
1028 except bb.build.EventException:
1029 bb.error("Build of " + k + " failed")
1033 failures += failures
1034 if self.configuration.abort:
1037 bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.event_data, failures))
1039 sys.exit( self.stats.show() )
1041 except KeyboardInterrupt:
1042 print "\nNOTE: KeyboardInterrupt - Build not completed."
1045 def get_bbfiles( self, path = os.getcwd() ):
1046 """Get list of default .bb files by reading out the current directory"""
1047 contents = os.listdir(path)
1050 (root, ext) = os.path.splitext(f)
1052 bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
1055 def find_bbfiles( self, path ):
1056 """Find all the .bb files in a directory (uses find)"""
1057 findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
1059 finddata = os.popen(findcmd)
1062 return finddata.readlines()
1064 def collect_bbfiles( self, progressCallback ):
1065 """Collect all available .bb build files"""
1066 self.cb = progressCallback
1067 parsed, cached, skipped, masked = 0, 0, 0, 0
1068 self.bb_cache = bb.cache.init(self)
1070 files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
1071 data.setVar("BBFILES", " ".join(files), self.configuration.data)
1074 files = self.get_bbfiles()
1077 bb.error("no files to build.")
1081 if os.path.isdir(f):
1082 dirfiles = self.find_bbfiles(f)
1084 newfiles += dirfiles
1086 newfiles += glob.glob(f) or [ f ]
1088 bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1) or ""
1090 bbmask_compiled = re.compile(bbmask)
1091 except sre_constants.error:
1092 bb.fatal("BBMASK is not a valid regular expression.")
1094 for i in xrange( len( newfiles ) ):
1096 if bbmask and bbmask_compiled.search(f):
1097 bb.debug(1, "bbmake: skipping %s" % f)
1100 debug(1, "bbmake: parsing %s" % f)
1102 # read a file's metadata
1104 fromCache, skip = self.bb_cache.loadData(f, self)
1107 #bb.note("Skipping %s" % f)
1108 self.bb_cache.skip(f)
1110 elif fromCache: cached += 1
1114 # allow metadata files to add items to BBFILES
1115 #data.update_data(self.pkgdata[f])
1116 addbbfiles = self.bb_cache.getVar('BBFILES', f, False) or None
1118 for aof in addbbfiles.split():
1119 if not files.count(aof):
1120 if not os.path.isabs(aof):
1121 aof = os.path.join(os.path.dirname(f),aof)
1124 # now inform the caller
1125 if self.cb is not None:
1126 self.cb( i + 1, len( newfiles ), f, self.bb_cache, fromCache )
1129 self.bb_cache.remove(f)
1130 bb.error("opening %s: %s" % (f, e))
1132 except KeyboardInterrupt:
1133 self.bb_cache.sync()
1135 except Exception, e:
1136 self.bb_cache.remove(f)
1137 bb.error("%s while parsing %s" % (e, f))
1139 self.bb_cache.remove(f)
1142 if self.cb is not None:
1143 print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ),
1145 self.bb_cache.sync()
1147 #============================================================================#
1149 #============================================================================#
1152 parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
1153 usage = """%prog [options] [package ...]
1155 Executes the specified task (default is 'build') for a given set of BitBake files.
1156 It expects that BBFILES is defined, which is a space seperated list of files to
1157 be executed. BBFILES does support wildcards.
1158 Default BBFILES are the .bb files in the current directory.""" )
1160 parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
1161 action = "store", dest = "buildfile", default = None )
1163 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.",
1164 action = "store_false", dest = "abort", default = True )
1166 parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
1167 action = "store_true", dest = "force", default = False )
1169 parser.add_option( "-i", "--interactive", help = "drop into the interactive mode.",
1170 action = "store_true", dest = "interactive", default = False )
1172 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)",
1173 action = "store", dest = "cmd", default = "build" )
1175 parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
1176 action = "append", dest = "file", default = [] )
1178 parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
1179 action = "store_true", dest = "verbose", default = False )
1181 parser.add_option( "-D", "--debug", help = "Increase the debug level",
1182 action = "count", dest="debug", default = 0)
1184 parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
1185 action = "store_true", dest = "dry_run", default = False )
1187 parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
1188 action = "store_true", dest = "parse_only", default = False )
1190 parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
1191 action = "store_true", dest = "disable_psyco", default = False )
1193 parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
1194 action = "store_true", dest = "show_versions", default = False )
1196 parser.add_option( "-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
1197 action = "store_true", dest = "show_environment", default = False )
1199 parser.add_option( "-g", "--graphviz", help = "emit the dependency trees of the specified packages in the dot syntax",
1200 action = "store_true", dest = "dot_graph", default = False )
1202 options, args = parser.parse_args( sys.argv )
1205 cooker.cook( BBConfiguration( options ), args[1:] )
1209 if __name__ == "__main__":
1210 print """WARNING, WARNING, WARNING
1211 This is a Bitbake from the Unstable/Development Branch.
1212 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."""