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.append(os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
27 from bb import utils, data, parse, debug, event, fatal
29 import itertools, optparse
31 parsespin = itertools.cycle( r'|/-\\' )
34 __version__ = "1.3.3.2"
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
47 self.cache_dirty = False
51 self.packages_dynamic = {}
52 self.bbfile_priority = {}
53 self.bbfile_config_priorities = []
54 self.ignored_dependencies = None
55 self.possible_world = []
56 self.world_target = Set()
62 self.all_depends = Set()
64 def handle_bb_data(self, file_name, bb_data, cached):
66 We will fill the dictionaries with the stuff we
67 need for building the tree more fast
73 self.cache_dirty = True
75 pn = bb.data.getVar('PN', bb_data, True)
76 pv = bb.data.getVar('PV', bb_data, True)
77 pr = bb.data.getVar('PR', bb_data, True)
78 dp = int(bb.data.getVar('DEFAULT_PREFERENCE', bb_data, True) or "0")
79 provides = Set([pn] + (bb.data.getVar("PROVIDES", bb_data, 1) or "").split())
80 rprovides = (bb.data.getVar("RPROVIDES", bb_data, 1) or "").split()
81 depends = (bb.data.getVar("DEPENDS", bb_data, True) or "").split()
82 packages = (bb.data.getVar('PACKAGES', bb_data, True) or "").split()
83 packages_dynamic = (bb.data.getVar('PACKAGES_DYNAMIC', bb_data, True) or "").split()
86 # build PackageName to FileName lookup table
87 if pn not in self.pkg_pn:
89 self.pkg_pn[pn].append(file_name)
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)
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 # Collect files we may need for possible world-dep
130 if not bb.data.getVar('BROKEN', bb_data, True) and not bb.data.getVar('EXCLUDE_FROM_WORLD', bb_data, True):
131 self.possible_world.append(file_name)
134 #============================================================================#
136 #============================================================================#
139 Manage build statistics for one run
148 print "Build statistics:"
149 print " Attempted builds: %d" % self.attempt
151 print " Failed builds: %d" % self.fail
153 print " Dependencies not satisfied: %d" % self.deps
154 if self.fail or self.deps: return 1
158 #============================================================================#
160 #============================================================================#
161 class BBConfiguration( object ):
163 Manages build options and configurations for one run
165 def __init__( self, options ):
166 for key, val in options.__dict__.items():
167 setattr( self, key, val )
168 self.data = data.init()
170 #============================================================================#
172 #============================================================================#
175 Manages one bitbake build run
178 ParsingStatus = BBParsingStatus # make it visible from the shell
179 Statistics = BBStatistics # make it visible from the shell
181 def __init__( self ):
182 self.build_cache_fail = []
183 self.build_cache = []
184 self.rbuild_cache = []
185 self.building_list = []
187 self.consider_msgs_cache = []
189 self.stats = BBStatistics()
195 def tryBuildPackage( self, fn, item, the_data ):
196 """Build one package"""
197 bb.event.fire(bb.event.PkgStarted(item, the_data))
199 self.stats.attempt += 1
200 if self.configuration.force:
201 bb.data.setVarFlag('do_%s' % self.configuration.cmd, 'force', 1, the_data)
202 if not self.configuration.dry_run:
203 bb.build.exec_task('do_%s' % self.configuration.cmd, the_data)
204 bb.event.fire(bb.event.PkgSucceeded(item, the_data))
205 self.build_cache.append(fn)
207 except bb.build.FuncFailed:
209 bb.error("task stack execution failed")
210 bb.event.fire(bb.event.PkgFailed(item, the_data))
211 self.build_cache_fail.append(fn)
213 except bb.build.EventException, e:
216 bb.error("%s event exception, aborting" % bb.event.getName(event))
217 bb.event.fire(bb.event.PkgFailed(item, the_data))
218 self.build_cache_fail.append(fn)
221 def tryBuild( self, fn, virtual , buildAllDeps , build_depends = []):
223 Build a provider and its dependencies.
224 build_depends is a list of previous build dependencies (not runtime)
225 If build_depends is empty, we're dealing with a runtime depends
228 the_data = self.pkgdata[fn]
231 buildAllDeps = bb.data.getVar('BUILD_ALL_DEPS', the_data, True) or False
233 # Error on build time dependency loops
234 if build_depends and build_depends.count(fn) > 1:
235 bb.error("%s depends on itself (eventually)" % fn)
236 bb.error("upwards chain is: %s" % (" -> ".join(self.build_path)))
239 # See if this is a runtime dependency we've already built
240 # Or a build dependency being handled in a different build chain
241 if fn in self.building_list:
242 return self.addRunDeps(fn, virtual , buildAllDeps)
244 item = self.status.pkg_fn[fn]
246 self.building_list.append(fn)
248 pathstr = "%s (%s)" % (item, virtual)
249 self.build_path.append(pathstr)
251 depends_list = (bb.data.getVar('DEPENDS', the_data, True) or "").split()
253 if self.configuration.verbose:
254 bb.note("current path: %s" % (" -> ".join(self.build_path)))
255 bb.note("dependencies for %s are: %s" % (item, " ".join(depends_list)))
260 depcmd = self.configuration.cmd
261 bbdepcmd = bb.data.getVarFlag('do_%s' % self.configuration.cmd, 'bbdepcmd', the_data)
262 if bbdepcmd is not None:
269 oldcmd = self.configuration.cmd
270 self.configuration.cmd = depcmd
272 for dependency in depends_list:
273 if dependency in self.status.ignored_dependencies:
277 if self.buildProvider( dependency , buildAllDeps , build_depends ) == 0:
278 bb.error("dependency %s (for %s) not satisfied" % (dependency,item))
280 if self.configuration.abort:
284 self.configuration.cmd = oldcmd
290 if not self.addRunDeps(fn, virtual , buildAllDeps):
293 if bb.build.stamp_is_current('do_%s' % self.configuration.cmd, the_data):
294 self.build_cache.append(fn)
297 return self.tryBuildPackage( fn, item, the_data )
300 self.building_list.remove(fn)
301 self.build_path.remove(pathstr)
303 def findBestProvider( self, pn, pkg_pn = None):
305 If there is a PREFERRED_VERSION, find the highest-priority bbfile
306 providing that version. If not, find the latest version provided by
307 an bbfile in the highest-priority set.
310 pkg_pn = self.status.pkg_pn
315 priority = self.status.bbfile_priority[f]
316 if priority not in priorities:
317 priorities[priority] = []
318 priorities[priority].append(f)
319 p_list = priorities.keys()
320 p_list.sort(lambda a, b: a - b)
323 tmp_pn = [priorities[p]] + tmp_pn
325 preferred_file = None
327 localdata = data.createCopy(self.configuration.data)
328 bb.data.setVar('OVERRIDES', "%s:%s" % (pn, data.getVar('OVERRIDES', localdata)), localdata)
329 bb.data.update_data(localdata)
331 preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, localdata, True)
333 m = re.match('(.*)_(.*)', preferred_v)
335 preferred_v = m.group(1)
336 preferred_r = m.group(2)
340 for file_set in tmp_pn:
342 pv,pr = self.status.pkg_pvpr[f]
343 if preferred_v == pv and (preferred_r == pr or preferred_r == None):
345 preferred_ver = (pv, pr)
350 pv_str = '%s-%s' % (preferred_v, preferred_r)
353 if preferred_file is None:
354 bb.note("preferred version %s of %s not available" % (pv_str, pn))
356 bb.debug(1, "selecting %s as PREFERRED_VERSION %s of package %s" % (preferred_file, pv_str, pn))
360 # get highest priority file set
365 for file_name in files:
366 pv,pr = self.status.pkg_pvpr[file_name]
367 dp = self.status.pkg_dp[file_name]
369 if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pv, pr)) < 0)) or (dp > latest_p):
373 if preferred_file is None:
374 preferred_file = latest_f
375 preferred_ver = latest
377 return (latest,latest_f,preferred_ver, preferred_file)
379 def showVersions( self ):
380 pkg_pn = self.status.pkg_pn
381 preferred_versions = {}
385 for pn in pkg_pn.keys():
386 (last_ver,last_file,pref_ver,pref_file) = self.findBestProvider(pn)
387 preferred_versions[pn] = (pref_ver, pref_file)
388 latest_versions[pn] = (last_ver, last_file)
390 pkg_list = pkg_pn.keys()
394 pref = preferred_versions[p]
395 latest = latest_versions[p]
398 prefstr = pref[0][0] + "-" + pref[0][1]
402 print "%-30s %20s %20s" % (p, latest[0][0] + "-" + latest[0][1],
405 def showEnvironment( self ):
406 """Show the outer or per-package environment"""
407 if self.configuration.buildfile:
409 self.configuration.data, fromCache = self.load_bbfile( self.configuration.buildfile )
411 fatal("Unable to read %s: %s" % ( self.configuration.buildfile, e ))
414 # emit variables and shell functions
416 data.update_data( self.configuration.data )
417 data.emit_env(sys.__stdout__, self.configuration.data, True)
420 # emit the metadata which isnt valid shell
421 for e in self.configuration.data.keys():
422 if data.getVarFlag( e, 'python', self.configuration.data ):
423 sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, self.configuration.data, 1)))
425 def filterProviders(self, providers, item):
427 Take a list of providers and filter/reorder according to the
428 environment variables and previous build results
431 preferred_versions = {}
433 # Collate providers by PN
436 pn = self.status.pkg_fn[p]
441 bb.debug(1, "providers for %s are: %s" % (item, pkg_pn.keys()))
443 for pn in pkg_pn.keys():
444 preferred_versions[pn] = self.findBestProvider(pn, pkg_pn)[2:4]
445 eligible.append(preferred_versions[pn][1])
448 if p in self.build_cache_fail:
449 bb.debug(1, "rejecting already-failed %s" % p)
452 if len(eligible) == 0:
453 bb.error("no eligible providers for %s" % item)
456 # look to see if one of them is already staged, or marked as preferred.
457 # if so, bump it to the head of the queue
459 the_data = self.pkgdata[p]
460 pn = bb.data.getVar('PN', the_data, 1)
461 pv = bb.data.getVar('PV', the_data, 1)
462 pr = bb.data.getVar('PR', the_data, 1)
463 stamp = '%s.do_populate_staging' % bb.data.getVar('STAMP', the_data, 1)
464 if os.path.exists(stamp):
465 (newvers, fn) = preferred_versions[pn]
466 if not fn in eligible:
467 # package was made ineligible by already-failed check
469 oldver = "%s-%s" % (pv, pr)
470 newver = '-'.join(newvers)
471 if (newver != oldver):
472 extra_chat = "; upgrading from %s to %s" % (oldver, newver)
475 if self.configuration.verbose:
476 bb.note("selecting already-staged %s to satisfy %s%s" % (pn, item, extra_chat))
478 eligible = [fn] + eligible
484 def buildProvider( self, item , buildAllDeps , build_depends = [] ):
486 Build something to provide a named build requirement
487 (takes item names from DEPENDS namespace)
491 discriminated = False
493 if not item in self.status.providers:
494 bb.error("Nothing provides dependency %s" % item)
497 all_p = self.status.providers[item]
500 if p in self.build_cache:
501 bb.debug(1, "already built %s in this run\n" % p)
504 eligible = self.filterProviders(all_p, item)
509 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
511 self.preferred[item] = prefervar
513 if item in self.preferred:
515 pn = self.status.pkg_fn[p]
516 if self.preferred[item] == pn:
517 if self.configuration.verbose:
518 bb.note("selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
520 eligible = [p] + eligible
524 if len(eligible) > 1 and discriminated == False:
525 if item not in self.consider_msgs_cache:
528 providers_list.append(self.status.pkg_fn[fn])
529 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
530 bb.note("consider defining PREFERRED_PROVIDER_%s" % item)
531 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data))
532 self.consider_msgs_cache.append(item)
535 # run through the list until we find one that we can build
537 bb.debug(2, "selecting %s to satisfy %s" % (fn, item))
538 if self.tryBuild(fn, item, buildAllDeps, build_depends + [fn]):
541 bb.note("no buildable providers for %s" % item)
544 def buildRProvider( self, item , buildAllDeps ):
546 Build something to provide a named runtime requirement
547 (takes item names from RDEPENDS/PACKAGES namespace)
552 discriminated = False
557 all_p = self.getProvidersRun(item)
560 bb.error("Nothing provides runtime dependency %s" % (item))
564 if p in self.rbuild_cache:
565 bb.debug(2, "Already built %s providing runtime %s\n" % (p,item))
567 if p in self.build_cache:
568 bb.debug(2, "Already built %s but adding any further RDEPENDS for %s\n" % (p, item))
569 return self.addRunDeps(p, item , buildAllDeps)
571 eligible = self.filterProviders(all_p, item)
577 pn = self.status.pkg_fn[p]
578 provides = self.status.pn_provides[pn]
579 for provide in provides:
580 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, self.configuration.data, 1)
582 if self.configuration.verbose:
583 bb.note("selecting %s to satisfy runtime %s due to PREFERRED_PROVIDERS" % (pn, item))
585 eligible = [p] + eligible
588 if len(eligible) > 1 and len(preferred) == 0:
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 a PREFERRED_PROVIDER to match runtime %s" % item)
595 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
596 self.consider_msgs_cache.append(item)
598 if len(preferred) > 1:
599 if item not in self.consider_msgs_cache:
602 providers_list.append(self.status.pkg_fn[fn])
603 bb.note("multiple preferred providers are available (%s);" % ", ".join(providers_list))
604 bb.note("consider defining only one PREFERRED_PROVIDER to match runtime %s" % item)
605 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
606 self.consider_msgs_cache.append(item)
608 # run through the list until we find one that we can build
610 bb.debug(2, "selecting %s to satisfy runtime %s" % (fn, item))
611 if self.tryBuild(fn, item, buildAllDeps):
614 bb.error("No buildable providers for runtime %s" % item)
617 def getProvidersRun(self, rdepend):
619 Return any potential providers of runtime rdepend
623 if rdepend in self.status.rproviders:
624 rproviders += self.status.rproviders[rdepend]
626 if rdepend in self.status.packages:
627 rproviders += self.status.packages[rdepend]
632 # Only search dynamic packages if we can't find anything in other variables
633 for pattern in self.status.packages_dynamic:
634 regexp = re.compile(pattern)
635 if regexp.match(rdepend):
636 rproviders += self.status.packages_dynamic[pattern]
640 def addRunDeps(self , fn, item , buildAllDeps):
642 Add any runtime dependencies of runtime item provided by fn
643 as long as item has't previously been processed by this function.
646 if item in self.rbuild_cache:
653 self.rbuild_cache.append(item)
654 the_data = self.pkgdata[fn]
655 pn = self.status.pkg_fn[fn]
658 rdepends += bb.utils.explode_deps(bb.data.getVar('RDEPENDS', the_data, True) or "")
659 rdepends += bb.utils.explode_deps(bb.data.getVar('RRECOMMENDS', the_data, True) or "")
660 rdepends += bb.utils.explode_deps(bb.data.getVar("RDEPENDS_%s" % pn, the_data, True) or "")
662 packages = (bb.data.getVar('PACKAGES', the_data, 1).split() or "")
663 for package in packages:
665 rdepends += bb.utils.explode_deps(bb.data.getVar("RDEPENDS_%s" % package, the_data, True) or "")
666 rdepends += bb.utils.explode_deps(bb.data.getVar("RRECOMMENDS_%s" % package, the_data, True) or "")
668 bb.debug(2, "Additional runtime dependencies for %s are: %s" % (item, " ".join(rdepends)))
670 for rdepend in rdepends:
671 if rdepend in self.status.ignored_dependencies:
673 if not self.buildRProvider(rdepend, buildAllDeps):
677 def buildDepgraph( self ):
678 all_depends = self.status.all_depends
679 pn_provides = self.status.pn_provides
681 def calc_bbfile_priority(filename):
682 for (regex, pri) in self.status.bbfile_config_priorities:
683 if regex.match(filename):
687 # Handle PREFERRED_PROVIDERS
688 for p in (bb.data.getVar('PREFERRED_PROVIDERS', self.configuration.data, 1) or "").split():
689 (providee, provider) = p.split(':')
690 if providee in self.preferred and self.preferred[providee] != provider:
691 bb.error("conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.preferred[providee]))
692 self.preferred[providee] = provider
694 # Calculate priorities for each file
695 for p in self.pkgdata.keys():
696 self.status.bbfile_priority[p] = calc_bbfile_priority(p)
698 # Build package list for "bitbake world"
699 bb.debug(1, "collating packages for \"world\"")
700 for f in self.status.possible_world:
702 pn = self.status.pkg_fn[f]
704 for p in pn_provides[pn]:
705 if p.startswith('virtual/'):
706 bb.debug(2, "skipping %s due to %s provider starting with virtual/" % (f, p))
709 for pf in self.status.providers[p]:
710 if self.status.pkg_fn[pf] != pn:
711 bb.debug(2, "skipping %s due to both us and %s providing %s" % (f, pf, p))
715 self.status.world_target.add(pn)
717 # drop reference count now
718 self.status.possible_world = None
719 self.status.all_depends = None
721 def myProgressCallback( self, x, y, f, file_data, from_cache ):
722 # feed the status with new input
723 self.status.handle_bb_data(f, file_data, from_cache)
727 if os.isatty(sys.stdout.fileno()):
728 sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
732 sys.stdout.write("Parsing .bb files, please wait...")
735 sys.stdout.write("done.")
738 def interactiveMode( self ):
739 """Drop off into a shell"""
742 except ImportError, details:
743 bb.fatal("Sorry, shell not available (%s)" % details )
745 bb.data.update_data( self.configuration.data )
749 def parseConfigurationFile( self, afile ):
751 self.configuration.data = bb.parse.handle( afile, self.configuration.data )
753 bb.fatal( "Unable to open %s" % afile )
754 except bb.parse.ParseError, details:
755 bb.fatal( "Unable to parse %s (%s)" % (afile, details) )
757 def handleCollections( self, collections ):
758 """Handle collections"""
760 collection_list = collections.split()
761 for c in collection_list:
762 regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1)
764 bb.error("BBFILE_PATTERN_%s not defined" % c)
766 priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1)
768 bb.error("BBFILE_PRIORITY_%s not defined" % c)
771 cre = re.compile(regex)
773 bb.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
777 self.status.bbfile_config_priorities.append((cre, pri))
779 bb.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
782 def cook( self, configuration, args ):
783 self.configuration = configuration
785 if not self.configuration.cmd:
786 self.configuration.cmd = "build"
788 if self.configuration.debug:
789 bb.debug_level = self.configuration.debug
791 self.configuration.data = bb.data.init()
793 for f in self.configuration.file:
794 self.parseConfigurationFile( f )
796 self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
798 if self.configuration.show_environment:
799 self.showEnvironment()
802 # inject custom variables
803 if not bb.data.getVar("BUILDNAME", self.configuration.data):
804 bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
805 bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data)
807 buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
809 if self.configuration.interactive:
810 self.interactiveMode()
812 if self.configuration.buildfile is not None:
813 bf = os.path.abspath( self.configuration.buildfile )
815 bbfile_data = bb.parse.handle(bf, self.configuration.data)
817 bb.fatal("Unable to open %s" % bf)
819 item = bb.data.getVar('PN', bbfile_data, 1)
821 self.tryBuildPackage( bf, item, bbfile_data )
822 except bb.build.EventException:
823 bb.error( "Build of '%s' failed" % item )
825 sys.exit( self.stats.show() )
827 # initialise the parsing status now we know we will need deps
828 self.status = BBParsingStatus()
830 ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
831 self.status.ignored_dependencies = Set( ignore.split() )
833 self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
837 if not pkgs_to_build:
839 pkgs_to_build.extend(args)
840 if not pkgs_to_build:
841 bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
843 pkgs_to_build = bbpkgs.split()
844 if not pkgs_to_build and not self.configuration.show_versions \
845 and not self.configuration.interactive \
846 and not self.configuration.show_environment:
847 print "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help'"
848 print "for usage information."
851 # Import Psyco if available and not disabled
852 if not self.configuration.disable_psyco:
857 bb.note("Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
859 psyco.bind( self.collect_bbfiles )
861 bb.note("You have disabled Psyco. This decreases performance.")
864 bb.debug(1, "collecting .bb files")
865 self.collect_bbfiles( self.myProgressCallback )
866 bb.debug(1, "parsing complete")
869 if self.configuration.parse_only:
870 print "Requested parsing .bb files only. Exiting."
873 bb.data.update_data( self.configuration.data )
876 if self.configuration.show_versions:
879 if 'world' in pkgs_to_build:
880 pkgs_to_build.remove('world')
881 for t in self.status.world_target:
882 pkgs_to_build.append(t)
884 bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.data))
887 for k in pkgs_to_build:
890 if self.buildProvider( k , False ) == 0:
893 except bb.build.EventException:
894 bb.error("Build of " + k + " failed")
899 if self.configuration.abort:
902 bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.data, failures))
904 sys.exit( self.stats.show() )
906 except KeyboardInterrupt:
907 print "\nNOTE: KeyboardInterrupt - Build not completed."
910 def get_bbfiles( self, path = os.getcwd() ):
911 """Get list of default .bb files by reading out the current directory"""
912 contents = os.listdir(path)
915 (root, ext) = os.path.splitext(f)
917 bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
920 def find_bbfiles( self, path ):
921 """Find all the .bb files in a directory (uses find)"""
922 findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
924 finddata = os.popen(findcmd)
927 return finddata.readlines()
929 def deps_clean(self, d):
930 depstr = data.getVar('__depends', d)
932 deps = depstr.split(" ")
934 (f,old_mtime_s) = dep.split("@")
935 old_mtime = int(old_mtime_s)
936 new_mtime = parse.cached_mtime(f)
937 if (new_mtime > old_mtime):
941 def load_bbfile( self, bbfile ):
942 """Load and parse one .bb build file"""
944 if not self.cache in [None, '']:
946 cache_mtime = data.init_db_mtime(self.cache, bbfile)
947 file_mtime = parse.cached_mtime(bbfile)
949 if file_mtime > cache_mtime:
950 #print " : '%s' dirty. reparsing..." % bbfile
953 #print " : '%s' clean. loading from cache..." % bbfile
954 cache_data = data.init_db( self.cache, bbfile, False )
955 if self.deps_clean(cache_data):
956 return cache_data, True
958 topdir = data.getVar('TOPDIR', self.configuration.data)
960 topdir = os.path.abspath(os.getcwd())
962 data.setVar('TOPDIR', topdir, self.configuration)
963 bbfile = os.path.abspath(bbfile)
964 bbfile_loc = os.path.abspath(os.path.dirname(bbfile))
965 # expand tmpdir to include this topdir
966 data.setVar('TMPDIR', data.getVar('TMPDIR', self.configuration.data, 1) or "", self.configuration.data)
967 # set topdir to location of .bb file
969 #data.setVar('TOPDIR', topdir, cfg)
971 oldpath = os.path.abspath(os.getcwd())
973 bb = data.init_db(self.cache,bbfile, True, self.configuration.data)
975 parse.handle(bbfile, bb) # read .bb data
976 if not self.cache in [None, '']:
977 bb.commit(parse.cached_mtime(bbfile)) # write cache
983 def collect_bbfiles( self, progressCallback ):
984 """Collect all available .bb build files"""
985 self.cb = progressCallback
986 parsed, cached, skipped, masked = 0, 0, 0, 0
987 self.cache = bb.data.getVar( "CACHE", self.configuration.data, 1 )
988 self.pkgdata = data.pkgdata( not self.cache in [None, ''], self.cache, self.configuration.data )
990 if not self.cache in [None, '']:
991 if self.cb is not None:
992 print "NOTE: Using cache in '%s'" % self.cache
994 os.stat( self.cache )
996 bb.mkdirhier( self.cache )
998 if self.cb is not None:
999 print "NOTE: Not using a cache. Set CACHE = <directory> to enable."
1000 files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
1001 data.setVar("BBFILES", " ".join(files), self.configuration.data)
1004 files = self.get_bbfiles()
1007 bb.error("no files to build.")
1011 if os.path.isdir(f):
1012 dirfiles = self.find_bbfiles(f)
1014 newfiles += dirfiles
1016 newfiles += glob.glob(f) or [ f ]
1018 bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1) or ""
1020 bbmask_compiled = re.compile(bbmask)
1021 except sre_constants.error:
1022 bb.fatal("BBMASK is not a valid regular expression.")
1024 for i in xrange( len( newfiles ) ):
1026 if bbmask and bbmask_compiled.search(f):
1027 bb.debug(1, "bbmake: skipping %s" % f)
1030 debug(1, "bbmake: parsing %s" % f)
1032 # read a file's metadata
1034 bb_data, fromCache = self.load_bbfile(f)
1035 if fromCache: cached += 1
1038 if bb_data is not None:
1039 # allow metadata files to add items to BBFILES
1040 #data.update_data(self.pkgdata[f])
1041 addbbfiles = data.getVar('BBFILES', bb_data) or None
1043 for aof in addbbfiles.split():
1044 if not files.count(aof):
1045 if not os.path.isabs(aof):
1046 aof = os.path.join(os.path.dirname(f),aof)
1048 for var in bb_data.keys():
1049 if data.getVarFlag(var, "handler", bb_data) and data.getVar(var, bb_data):
1050 event.register(data.getVar(var, bb_data))
1051 self.pkgdata[f] = bb_data
1053 # now inform the caller
1054 if self.cb is not None:
1055 self.cb( i + 1, len( newfiles ), f, bb_data, fromCache )
1058 bb.error("opening %s: %s" % (f, e))
1060 except bb.parse.SkipPackage:
1063 except KeyboardInterrupt:
1065 except Exception, e:
1066 bb.error("%s while parsing %s" % (e, f))
1068 if self.cb is not None:
1069 print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ),
1071 #============================================================================#
1073 #============================================================================#
1075 if __name__ == "__main__":
1077 parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
1078 usage = """%prog [options] [package ...]
1080 Executes the specified task (default is 'build') for a given set of BitBake files.
1081 It expects that BBFILES is defined, which is a space seperated list of files to
1082 be executed. BBFILES does support wildcards.
1083 Default BBFILES are the .bb files in the current directory.""" )
1085 parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
1086 action = "store", dest = "buildfile", default = None )
1088 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.",
1089 action = "store_false", dest = "abort", default = True )
1091 parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
1092 action = "store_true", dest = "force", default = False )
1094 parser.add_option( "-i", "--interactive", help = "drop into the interactive mode.",
1095 action = "store_true", dest = "interactive", default = False )
1097 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)",
1098 action = "store", dest = "cmd", default = "build" )
1100 parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
1101 action = "append", dest = "file", default = [] )
1103 parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
1104 action = "store_true", dest = "verbose", default = False )
1106 parser.add_option( "-D", "--debug", help = "Increase the debug level",
1107 action = "count", dest="debug", default = 0)
1109 parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
1110 action = "store_true", dest = "dry_run", default = False )
1112 parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
1113 action = "store_true", dest = "parse_only", default = False )
1115 parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
1116 action = "store_true", dest = "disable_psyco", default = False )
1118 parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
1119 action = "store_true", dest = "show_versions", default = False )
1121 parser.add_option( "-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
1122 action = "store_true", dest = "show_environment", default = False )
1124 options, args = parser.parse_args( sys.argv )
1127 cooker.cook( BBConfiguration( options ), args[1:] )