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
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)
495 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
498 all_p = self.status.providers[item]
501 if p in self.build_cache:
502 bb.debug(1, "already built %s in this run\n" % p)
505 eligible = self.filterProviders(all_p, item)
510 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
512 self.preferred[item] = prefervar
514 if item in self.preferred:
516 pn = self.status.pkg_fn[p]
517 if self.preferred[item] == pn:
518 if self.configuration.verbose:
519 bb.note("selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
521 eligible = [p] + eligible
525 if len(eligible) > 1 and discriminated == False:
526 if item not in self.consider_msgs_cache:
529 providers_list.append(self.status.pkg_fn[fn])
530 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
531 bb.note("consider defining PREFERRED_PROVIDER_%s" % item)
532 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data))
533 self.consider_msgs_cache.append(item)
536 # run through the list until we find one that we can build
538 bb.debug(2, "selecting %s to satisfy %s" % (fn, item))
539 if self.tryBuild(fn, item, buildAllDeps, build_depends + [fn]):
542 bb.note("no buildable providers for %s" % item)
543 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
546 def buildRProvider( self, item , buildAllDeps ):
548 Build something to provide a named runtime requirement
549 (takes item names from RDEPENDS/PACKAGES namespace)
554 discriminated = False
559 all_p = self.getProvidersRun(item)
562 bb.error("Nothing provides runtime dependency %s" % (item))
563 bb.event.fire(bb.event.NoProvider(item,self.configuration.data,runtime=True))
567 if p in self.rbuild_cache:
568 bb.debug(2, "Already built %s providing runtime %s\n" % (p,item))
570 if p in self.build_cache:
571 bb.debug(2, "Already built %s but adding any further RDEPENDS for %s\n" % (p, item))
572 return self.addRunDeps(p, item , buildAllDeps)
574 eligible = self.filterProviders(all_p, item)
580 pn = self.status.pkg_fn[p]
581 provides = self.status.pn_provides[pn]
582 for provide in provides:
583 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, self.configuration.data, 1)
585 if self.configuration.verbose:
586 bb.note("selecting %s to satisfy runtime %s due to PREFERRED_PROVIDERS" % (pn, item))
588 eligible = [p] + eligible
591 if len(eligible) > 1 and len(preferred) == 0:
592 if item not in self.consider_msgs_cache:
595 providers_list.append(self.status.pkg_fn[fn])
596 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
597 bb.note("consider defining a PREFERRED_PROVIDER to match runtime %s" % item)
598 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
599 self.consider_msgs_cache.append(item)
601 if len(preferred) > 1:
602 if item not in self.consider_msgs_cache:
605 providers_list.append(self.status.pkg_fn[fn])
606 bb.note("multiple preferred providers are available (%s);" % ", ".join(providers_list))
607 bb.note("consider defining only one PREFERRED_PROVIDER to match runtime %s" % item)
608 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
609 self.consider_msgs_cache.append(item)
611 # run through the list until we find one that we can build
613 bb.debug(2, "selecting %s to satisfy runtime %s" % (fn, item))
614 if self.tryBuild(fn, item, buildAllDeps):
617 bb.error("No buildable providers for runtime %s" % item)
618 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
621 def getProvidersRun(self, rdepend):
623 Return any potential providers of runtime rdepend
627 if rdepend in self.status.rproviders:
628 rproviders += self.status.rproviders[rdepend]
630 if rdepend in self.status.packages:
631 rproviders += self.status.packages[rdepend]
636 # Only search dynamic packages if we can't find anything in other variables
637 for pattern in self.status.packages_dynamic:
638 regexp = re.compile(pattern)
639 if regexp.match(rdepend):
640 rproviders += self.status.packages_dynamic[pattern]
644 def addRunDeps(self , fn, item , buildAllDeps):
646 Add any runtime dependencies of runtime item provided by fn
647 as long as item has't previously been processed by this function.
650 if item in self.rbuild_cache:
657 self.rbuild_cache.append(item)
658 the_data = self.pkgdata[fn]
659 pn = self.status.pkg_fn[fn]
662 rdepends += bb.utils.explode_deps(bb.data.getVar('RDEPENDS', the_data, True) or "")
663 rdepends += bb.utils.explode_deps(bb.data.getVar('RRECOMMENDS', the_data, True) or "")
664 rdepends += bb.utils.explode_deps(bb.data.getVar("RDEPENDS_%s" % pn, the_data, True) or "")
666 packages = (bb.data.getVar('PACKAGES', the_data, 1).split() or "")
667 for package in packages:
669 rdepends += bb.utils.explode_deps(bb.data.getVar("RDEPENDS_%s" % package, the_data, True) or "")
670 rdepends += bb.utils.explode_deps(bb.data.getVar("RRECOMMENDS_%s" % package, the_data, True) or "")
672 bb.debug(2, "Additional runtime dependencies for %s are: %s" % (item, " ".join(rdepends)))
674 for rdepend in rdepends:
675 if rdepend in self.status.ignored_dependencies:
677 if not self.buildRProvider(rdepend, buildAllDeps):
681 def buildDepgraph( self ):
682 all_depends = self.status.all_depends
683 pn_provides = self.status.pn_provides
685 def calc_bbfile_priority(filename):
686 for (regex, pri) in self.status.bbfile_config_priorities:
687 if regex.match(filename):
691 # Handle PREFERRED_PROVIDERS
692 for p in (bb.data.getVar('PREFERRED_PROVIDERS', self.configuration.data, 1) or "").split():
693 (providee, provider) = p.split(':')
694 if providee in self.preferred and self.preferred[providee] != provider:
695 bb.error("conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.preferred[providee]))
696 self.preferred[providee] = provider
698 # Calculate priorities for each file
699 for p in self.pkgdata.keys():
700 self.status.bbfile_priority[p] = calc_bbfile_priority(p)
702 # Build package list for "bitbake world"
703 bb.debug(1, "collating packages for \"world\"")
704 for f in self.status.possible_world:
706 pn = self.status.pkg_fn[f]
708 for p in pn_provides[pn]:
709 if p.startswith('virtual/'):
710 bb.debug(2, "skipping %s due to %s provider starting with virtual/" % (f, p))
713 for pf in self.status.providers[p]:
714 if self.status.pkg_fn[pf] != pn:
715 bb.debug(2, "skipping %s due to both us and %s providing %s" % (f, pf, p))
719 self.status.world_target.add(pn)
721 # drop reference count now
722 self.status.possible_world = None
723 self.status.all_depends = None
725 def myProgressCallback( self, x, y, f, file_data, from_cache ):
726 # feed the status with new input
727 self.status.handle_bb_data(f, file_data, from_cache)
731 if os.isatty(sys.stdout.fileno()):
732 sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
736 sys.stdout.write("Parsing .bb files, please wait...")
739 sys.stdout.write("done.")
742 def interactiveMode( self ):
743 """Drop off into a shell"""
746 except ImportError, details:
747 bb.fatal("Sorry, shell not available (%s)" % details )
749 bb.data.update_data( self.configuration.data )
753 def parseConfigurationFile( self, afile ):
755 self.configuration.data = bb.parse.handle( afile, self.configuration.data )
757 bb.fatal( "Unable to open %s" % afile )
758 except bb.parse.ParseError, details:
759 bb.fatal( "Unable to parse %s (%s)" % (afile, details) )
761 def handleCollections( self, collections ):
762 """Handle collections"""
764 collection_list = collections.split()
765 for c in collection_list:
766 regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1)
768 bb.error("BBFILE_PATTERN_%s not defined" % c)
770 priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1)
772 bb.error("BBFILE_PRIORITY_%s not defined" % c)
775 cre = re.compile(regex)
777 bb.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
781 self.status.bbfile_config_priorities.append((cre, pri))
783 bb.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
786 def cook( self, configuration, args ):
787 self.configuration = configuration
789 if not self.configuration.cmd:
790 self.configuration.cmd = "build"
792 if self.configuration.debug:
793 bb.debug_level = self.configuration.debug
795 self.configuration.data = bb.data.init()
797 for f in self.configuration.file:
798 self.parseConfigurationFile( f )
800 self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
802 if self.configuration.show_environment:
803 self.showEnvironment()
806 # inject custom variables
807 if not bb.data.getVar("BUILDNAME", self.configuration.data):
808 bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
809 bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data)
811 buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
813 if self.configuration.interactive:
814 self.interactiveMode()
816 if self.configuration.buildfile is not None:
817 bf = os.path.abspath( self.configuration.buildfile )
819 bbfile_data = bb.parse.handle(bf, self.configuration.data)
821 bb.fatal("Unable to open %s" % bf)
823 item = bb.data.getVar('PN', bbfile_data, 1)
825 self.tryBuildPackage( bf, item, bbfile_data )
826 except bb.build.EventException:
827 bb.error( "Build of '%s' failed" % item )
829 sys.exit( self.stats.show() )
831 # initialise the parsing status now we know we will need deps
832 self.status = BBParsingStatus()
834 ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
835 self.status.ignored_dependencies = Set( ignore.split() )
837 self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
841 if not pkgs_to_build:
843 pkgs_to_build.extend(args)
844 if not pkgs_to_build:
845 bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
847 pkgs_to_build = bbpkgs.split()
848 if not pkgs_to_build and not self.configuration.show_versions \
849 and not self.configuration.interactive \
850 and not self.configuration.show_environment:
851 print "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help'"
852 print "for usage information."
855 # Import Psyco if available and not disabled
856 if not self.configuration.disable_psyco:
861 bb.note("Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
863 psyco.bind( self.collect_bbfiles )
865 bb.note("You have disabled Psyco. This decreases performance.")
868 bb.debug(1, "collecting .bb files")
869 self.collect_bbfiles( self.myProgressCallback )
870 bb.debug(1, "parsing complete")
873 if self.configuration.parse_only:
874 print "Requested parsing .bb files only. Exiting."
877 bb.data.update_data( self.configuration.data )
880 if self.configuration.show_versions:
883 if 'world' in pkgs_to_build:
884 pkgs_to_build.remove('world')
885 for t in self.status.world_target:
886 pkgs_to_build.append(t)
888 bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.data))
891 for k in pkgs_to_build:
894 if self.buildProvider( k , False ) == 0:
897 except bb.build.EventException:
898 bb.error("Build of " + k + " failed")
903 if self.configuration.abort:
906 bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.data, failures))
908 sys.exit( self.stats.show() )
910 except KeyboardInterrupt:
911 print "\nNOTE: KeyboardInterrupt - Build not completed."
914 def get_bbfiles( self, path = os.getcwd() ):
915 """Get list of default .bb files by reading out the current directory"""
916 contents = os.listdir(path)
919 (root, ext) = os.path.splitext(f)
921 bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
924 def find_bbfiles( self, path ):
925 """Find all the .bb files in a directory (uses find)"""
926 findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
928 finddata = os.popen(findcmd)
931 return finddata.readlines()
933 def deps_clean(self, d):
934 depstr = data.getVar('__depends', d)
936 deps = depstr.split(" ")
938 (f,old_mtime_s) = dep.split("@")
939 old_mtime = int(old_mtime_s)
940 new_mtime = parse.cached_mtime(f)
941 if (new_mtime > old_mtime):
945 def load_bbfile( self, bbfile ):
946 """Load and parse one .bb build file"""
948 if not self.cache in [None, '']:
950 cache_mtime = data.init_db_mtime(self.cache, bbfile)
951 file_mtime = parse.cached_mtime(bbfile)
953 if file_mtime > cache_mtime:
954 #print " : '%s' dirty. reparsing..." % bbfile
957 #print " : '%s' clean. loading from cache..." % bbfile
958 cache_data = data.init_db( self.cache, bbfile, False )
959 if self.deps_clean(cache_data):
960 return cache_data, True
962 topdir = data.getVar('TOPDIR', self.configuration.data)
964 topdir = os.path.abspath(os.getcwd())
966 data.setVar('TOPDIR', topdir, self.configuration)
967 bbfile = os.path.abspath(bbfile)
968 bbfile_loc = os.path.abspath(os.path.dirname(bbfile))
969 # expand tmpdir to include this topdir
970 data.setVar('TMPDIR', data.getVar('TMPDIR', self.configuration.data, 1) or "", self.configuration.data)
971 # set topdir to location of .bb file
973 #data.setVar('TOPDIR', topdir, cfg)
975 oldpath = os.path.abspath(os.getcwd())
977 bb = data.init_db(self.cache,bbfile, True, self.configuration.data)
979 parse.handle(bbfile, bb) # read .bb data
980 if not self.cache in [None, '']:
981 bb.commit(parse.cached_mtime(bbfile)) # write cache
987 def collect_bbfiles( self, progressCallback ):
988 """Collect all available .bb build files"""
989 self.cb = progressCallback
990 parsed, cached, skipped, masked = 0, 0, 0, 0
991 self.cache = bb.data.getVar( "CACHE", self.configuration.data, 1 )
992 self.pkgdata = data.pkgdata( not self.cache in [None, ''], self.cache, self.configuration.data )
994 if not self.cache in [None, '']:
995 if self.cb is not None:
996 print "NOTE: Using cache in '%s'" % self.cache
998 os.stat( self.cache )
1000 bb.mkdirhier( self.cache )
1002 if self.cb is not None:
1003 print "NOTE: Not using a cache. Set CACHE = <directory> to enable."
1004 files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
1005 data.setVar("BBFILES", " ".join(files), self.configuration.data)
1008 files = self.get_bbfiles()
1011 bb.error("no files to build.")
1015 if os.path.isdir(f):
1016 dirfiles = self.find_bbfiles(f)
1018 newfiles += dirfiles
1020 newfiles += glob.glob(f) or [ f ]
1022 bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1) or ""
1024 bbmask_compiled = re.compile(bbmask)
1025 except sre_constants.error:
1026 bb.fatal("BBMASK is not a valid regular expression.")
1028 for i in xrange( len( newfiles ) ):
1030 if bbmask and bbmask_compiled.search(f):
1031 bb.debug(1, "bbmake: skipping %s" % f)
1034 debug(1, "bbmake: parsing %s" % f)
1036 # read a file's metadata
1038 bb_data, fromCache = self.load_bbfile(f)
1039 if fromCache: cached += 1
1042 if bb_data is not None:
1043 # allow metadata files to add items to BBFILES
1044 #data.update_data(self.pkgdata[f])
1045 addbbfiles = data.getVar('BBFILES', bb_data) or None
1047 for aof in addbbfiles.split():
1048 if not files.count(aof):
1049 if not os.path.isabs(aof):
1050 aof = os.path.join(os.path.dirname(f),aof)
1052 for var in bb_data.keys():
1053 if data.getVarFlag(var, "handler", bb_data) and data.getVar(var, bb_data):
1054 event.register(data.getVar(var, bb_data))
1055 self.pkgdata[f] = bb_data
1057 # now inform the caller
1058 if self.cb is not None:
1059 self.cb( i + 1, len( newfiles ), f, bb_data, fromCache )
1062 bb.error("opening %s: %s" % (f, e))
1064 except bb.parse.SkipPackage:
1067 except KeyboardInterrupt:
1069 except Exception, e:
1070 bb.error("%s while parsing %s" % (e, f))
1072 if self.cb is not None:
1073 print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ),
1075 #============================================================================#
1077 #============================================================================#
1079 if __name__ == "__main__":
1081 parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
1082 usage = """%prog [options] [package ...]
1084 Executes the specified task (default is 'build') for a given set of BitBake files.
1085 It expects that BBFILES is defined, which is a space seperated list of files to
1086 be executed. BBFILES does support wildcards.
1087 Default BBFILES are the .bb files in the current directory.""" )
1089 parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
1090 action = "store", dest = "buildfile", default = None )
1092 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.",
1093 action = "store_false", dest = "abort", default = True )
1095 parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
1096 action = "store_true", dest = "force", default = False )
1098 parser.add_option( "-i", "--interactive", help = "drop into the interactive mode.",
1099 action = "store_true", dest = "interactive", default = False )
1101 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)",
1102 action = "store", dest = "cmd", default = "build" )
1104 parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
1105 action = "append", dest = "file", default = [] )
1107 parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
1108 action = "store_true", dest = "verbose", default = False )
1110 parser.add_option( "-D", "--debug", help = "Increase the debug level",
1111 action = "count", dest="debug", default = 0)
1113 parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
1114 action = "store_true", dest = "dry_run", default = False )
1116 parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
1117 action = "store_true", dest = "parse_only", default = False )
1119 parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
1120 action = "store_true", dest = "disable_psyco", default = False )
1122 parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
1123 action = "store_true", dest = "show_versions", default = False )
1125 parser.add_option( "-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
1126 action = "store_true", dest = "show_environment", default = False )
1128 options, args = parser.parse_args( sys.argv )
1131 cooker.cook( BBConfiguration( options ), args[1:] )