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 )
192 self.data = data.init()
194 #============================================================================#
196 #============================================================================#
199 Manages one bitbake build run
202 ParsingStatus = BBParsingStatus # make it visible from the shell
203 Statistics = BBStatistics # make it visible from the shell
205 def __init__( self ):
206 self.build_cache_fail = []
207 self.build_cache = []
208 self.rbuild_cache = []
209 self.building_list = []
211 self.consider_msgs_cache = []
213 self.stats = BBStatistics()
219 def tryBuildPackage( self, fn, item, the_data ):
220 """Build one package"""
221 bb.event.fire(bb.event.PkgStarted(item, the_data))
223 self.stats.attempt += 1
224 if self.configuration.force:
225 bb.data.setVarFlag('do_%s' % self.configuration.cmd, 'force', 1, the_data)
226 if not self.configuration.dry_run:
227 bb.build.exec_task('do_%s' % self.configuration.cmd, the_data)
228 bb.event.fire(bb.event.PkgSucceeded(item, the_data))
229 self.build_cache.append(fn)
231 except bb.build.FuncFailed:
233 bb.error("task stack execution failed")
234 bb.event.fire(bb.event.PkgFailed(item, the_data))
235 self.build_cache_fail.append(fn)
237 except bb.build.EventException, e:
240 bb.error("%s event exception, aborting" % bb.event.getName(event))
241 bb.event.fire(bb.event.PkgFailed(item, the_data))
242 self.build_cache_fail.append(fn)
245 def tryBuild( self, fn, virtual , buildAllDeps , build_depends = []):
247 Build a provider and its dependencies.
248 build_depends is a list of previous build dependencies (not runtime)
249 If build_depends is empty, we're dealing with a runtime depends
252 the_data = self.bb_cache.loadDataFull(fn, self)
254 # Only follow all (runtime) dependencies if doing a build
255 if not buildAllDeps and self.configuration.cmd is "build":
256 buildAllDeps = self.status.build_all[fn]
258 # Error on build time dependency loops
259 if build_depends and build_depends.count(fn) > 1:
260 bb.error("%s depends on itself (eventually)" % fn)
261 bb.error("upwards chain is: %s" % (" -> ".join(self.build_path)))
264 # See if this is a runtime dependency we've already built
265 # Or a build dependency being handled in a different build chain
266 if fn in self.building_list:
267 return self.addRunDeps(fn, virtual , buildAllDeps)
269 item = self.status.pkg_fn[fn]
271 self.building_list.append(fn)
273 pathstr = "%s (%s)" % (item, virtual)
274 self.build_path.append(pathstr)
276 depends_list = (bb.data.getVar('DEPENDS', the_data, True) or "").split()
278 if self.configuration.verbose:
279 bb.note("current path: %s" % (" -> ".join(self.build_path)))
280 bb.note("dependencies for %s are: %s" % (item, " ".join(depends_list)))
285 depcmd = self.configuration.cmd
286 bbdepcmd = bb.data.getVarFlag('do_%s' % self.configuration.cmd, 'bbdepcmd', the_data)
287 if bbdepcmd is not None:
294 oldcmd = self.configuration.cmd
295 self.configuration.cmd = depcmd
297 for dependency in depends_list:
298 if dependency in self.status.ignored_dependencies:
302 if self.buildProvider( dependency , buildAllDeps , build_depends ) == 0:
303 bb.error("dependency %s (for %s) not satisfied" % (dependency,item))
305 if self.configuration.abort:
309 self.configuration.cmd = oldcmd
315 if not self.addRunDeps(fn, virtual , buildAllDeps):
318 if bb.build.stamp_is_current('do_%s' % self.configuration.cmd, the_data):
319 self.build_cache.append(fn)
322 return self.tryBuildPackage( fn, item, the_data )
325 self.building_list.remove(fn)
326 self.build_path.remove(pathstr)
328 def findBestProvider( self, pn, pkg_pn = None):
330 If there is a PREFERRED_VERSION, find the highest-priority bbfile
331 providing that version. If not, find the latest version provided by
332 an bbfile in the highest-priority set.
335 pkg_pn = self.status.pkg_pn
340 priority = self.status.bbfile_priority[f]
341 if priority not in priorities:
342 priorities[priority] = []
343 priorities[priority].append(f)
344 p_list = priorities.keys()
345 p_list.sort(lambda a, b: a - b)
348 tmp_pn = [priorities[p]] + tmp_pn
350 preferred_file = None
352 localdata = data.createCopy(self.configuration.data)
353 bb.data.setVar('OVERRIDES', "%s:%s" % (pn, data.getVar('OVERRIDES', localdata)), localdata)
354 bb.data.update_data(localdata)
356 preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, localdata, True)
358 m = re.match('(.*)_(.*)', preferred_v)
360 preferred_v = m.group(1)
361 preferred_r = m.group(2)
365 for file_set in tmp_pn:
367 pv,pr = self.status.pkg_pvpr[f]
368 if preferred_v == pv and (preferred_r == pr or preferred_r == None):
370 preferred_ver = (pv, pr)
375 pv_str = '%s-%s' % (preferred_v, preferred_r)
378 if preferred_file is None:
379 bb.note("preferred version %s of %s not available" % (pv_str, pn))
381 bb.debug(1, "selecting %s as PREFERRED_VERSION %s of package %s" % (preferred_file, pv_str, pn))
385 # get highest priority file set
390 for file_name in files:
391 pv,pr = self.status.pkg_pvpr[file_name]
392 dp = self.status.pkg_dp[file_name]
394 if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pv, pr)) < 0)) or (dp > latest_p):
398 if preferred_file is None:
399 preferred_file = latest_f
400 preferred_ver = latest
402 return (latest,latest_f,preferred_ver, preferred_file)
404 def showVersions( self ):
405 pkg_pn = self.status.pkg_pn
406 preferred_versions = {}
410 for pn in pkg_pn.keys():
411 (last_ver,last_file,pref_ver,pref_file) = self.findBestProvider(pn)
412 preferred_versions[pn] = (pref_ver, pref_file)
413 latest_versions[pn] = (last_ver, last_file)
415 pkg_list = pkg_pn.keys()
419 pref = preferred_versions[p]
420 latest = latest_versions[p]
423 prefstr = pref[0][0] + "-" + pref[0][1]
427 print "%-30s %20s %20s" % (p, latest[0][0] + "-" + latest[0][1],
431 def showEnvironment( self ):
432 """Show the outer or per-package environment"""
433 if self.configuration.buildfile:
435 self.bb_cache = bb.cache.init(self)
437 self.configuration.data = self.bb_cache.loadDataFull(self.configuration.buildfile, self)
439 fatal("Unable to read %s: %s" % ( self.configuration.buildfile, e ))
442 # emit variables and shell functions
444 data.update_data( self.configuration.data )
445 data.emit_env(sys.__stdout__, self.configuration.data, True)
448 # emit the metadata which isnt valid shell
449 for e in self.configuration.data.keys():
450 if data.getVarFlag( e, 'python', self.configuration.data ):
451 sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, self.configuration.data, 1)))
453 def filterProviders(self, providers, item):
455 Take a list of providers and filter/reorder according to the
456 environment variables and previous build results
459 preferred_versions = {}
461 # Collate providers by PN
464 pn = self.status.pkg_fn[p]
469 bb.debug(1, "providers for %s are: %s" % (item, pkg_pn.keys()))
471 for pn in pkg_pn.keys():
472 preferred_versions[pn] = self.findBestProvider(pn, pkg_pn)[2:4]
473 eligible.append(preferred_versions[pn][1])
476 if p in self.build_cache_fail:
477 bb.debug(1, "rejecting already-failed %s" % p)
480 if len(eligible) == 0:
481 bb.error("no eligible providers for %s" % item)
484 # look to see if one of them is already staged, or marked as preferred.
485 # if so, bump it to the head of the queue
487 pn = self.status.pkg_fn[p]
488 pv, pr = self.status.pkg_pvpr[p]
490 stamp = '%s.do_populate_staging' % self.status.stamp[p]
491 if os.path.exists(stamp):
492 (newvers, fn) = preferred_versions[pn]
493 if not fn in eligible:
494 # package was made ineligible by already-failed check
496 oldver = "%s-%s" % (pv, pr)
497 newver = '-'.join(newvers)
498 if (newver != oldver):
499 extra_chat = "%s (%s) already staged but upgrading to %s to satisfy %s" % (pn, oldver, newver, item)
501 extra_chat = "Selecting already-staged %s (%s) to satisfy %s" % (pn, oldver, item)
502 if self.configuration.verbose:
503 bb.note("%s" % extra_chat)
505 eligible = [fn] + eligible
511 def buildProvider( self, item , buildAllDeps , build_depends = [] ):
513 Build something to provide a named build requirement
514 (takes item names from DEPENDS namespace)
518 discriminated = False
520 if not item in self.status.providers:
521 bb.error("Nothing provides dependency %s" % item)
522 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
525 all_p = self.status.providers[item]
528 if p in self.build_cache:
529 bb.debug(1, "already built %s in this run\n" % p)
532 eligible = self.filterProviders(all_p, item)
537 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
539 self.preferred[item] = prefervar
541 if item in self.preferred:
543 pn = self.status.pkg_fn[p]
544 if self.preferred[item] == pn:
545 if self.configuration.verbose:
546 bb.note("selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
548 eligible = [p] + eligible
552 if len(eligible) > 1 and discriminated == False:
553 if item not in self.consider_msgs_cache:
556 providers_list.append(self.status.pkg_fn[fn])
557 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
558 bb.note("consider defining PREFERRED_PROVIDER_%s" % item)
559 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data))
560 self.consider_msgs_cache.append(item)
563 # run through the list until we find one that we can build
565 bb.debug(2, "selecting %s to satisfy %s" % (fn, item))
566 if self.tryBuild(fn, item, buildAllDeps, build_depends + [fn]):
569 bb.note("no buildable providers for %s" % item)
570 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
573 def buildRProvider( self, item , buildAllDeps ):
575 Build something to provide a named runtime requirement
576 (takes item names from RDEPENDS/PACKAGES namespace)
581 discriminated = False
586 all_p = self.getProvidersRun(item)
589 bb.error("Nothing provides runtime dependency %s" % (item))
590 bb.event.fire(bb.event.NoProvider(item,self.configuration.data,runtime=True))
594 if p in self.rbuild_cache:
595 bb.debug(2, "Already built %s providing runtime %s\n" % (p,item))
597 if p in self.build_cache:
598 bb.debug(2, "Already built %s but adding any further RDEPENDS for %s\n" % (p, item))
599 return self.addRunDeps(p, item , buildAllDeps)
601 eligible = self.filterProviders(all_p, item)
607 pn = self.status.pkg_fn[p]
608 provides = self.status.pn_provides[pn]
609 for provide in provides:
610 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, self.configuration.data, 1)
612 if self.configuration.verbose:
613 bb.note("selecting %s to satisfy runtime %s due to PREFERRED_PROVIDERS" % (pn, item))
615 eligible = [p] + eligible
618 if len(eligible) > 1 and len(preferred) == 0:
619 if item not in self.consider_msgs_cache:
622 providers_list.append(self.status.pkg_fn[fn])
623 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
624 bb.note("consider defining a PREFERRED_PROVIDER to match runtime %s" % item)
625 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
626 self.consider_msgs_cache.append(item)
628 if len(preferred) > 1:
629 if item not in self.consider_msgs_cache:
632 providers_list.append(self.status.pkg_fn[fn])
633 bb.note("multiple preferred providers are available (%s);" % ", ".join(providers_list))
634 bb.note("consider defining only one PREFERRED_PROVIDER to match runtime %s" % item)
635 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
636 self.consider_msgs_cache.append(item)
638 # run through the list until we find one that we can build
640 bb.debug(2, "selecting %s to satisfy runtime %s" % (fn, item))
641 if self.tryBuild(fn, item, buildAllDeps):
644 bb.error("No buildable providers for runtime %s" % item)
645 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
648 def getProvidersRun(self, rdepend):
650 Return any potential providers of runtime rdepend
654 if rdepend in self.status.rproviders:
655 rproviders += self.status.rproviders[rdepend]
657 if rdepend in self.status.packages:
658 rproviders += self.status.packages[rdepend]
663 # Only search dynamic packages if we can't find anything in other variables
664 for pattern in self.status.packages_dynamic:
665 regexp = re.compile(pattern)
666 if regexp.match(rdepend):
667 rproviders += self.status.packages_dynamic[pattern]
671 def addRunDeps(self , fn, item , buildAllDeps):
673 Add any runtime dependencies of runtime item provided by fn
674 as long as item has't previously been processed by this function.
677 if item in self.rbuild_cache:
684 self.rbuild_cache.append(item)
686 if fn in self.status.rundeps and item in self.status.rundeps[fn]:
687 rdepends += self.status.rundeps[fn][item].keys()
688 if fn in self.status.runrecs and item in self.status.runrecs[fn]:
689 rdepends += self.status.runrecs[fn][item].keys()
691 bb.debug(2, "Additional runtime dependencies for %s are: %s" % (item, " ".join(rdepends)))
693 for rdepend in rdepends:
694 if rdepend in self.status.ignored_dependencies:
696 if not self.buildRProvider(rdepend, buildAllDeps):
700 def buildDepgraph( self ):
701 all_depends = self.status.all_depends
702 pn_provides = self.status.pn_provides
704 def calc_bbfile_priority(filename):
705 for (regex, pri) in self.status.bbfile_config_priorities:
706 if regex.match(filename):
710 # Handle PREFERRED_PROVIDERS
711 for p in (bb.data.getVar('PREFERRED_PROVIDERS', self.configuration.data, 1) or "").split():
712 (providee, provider) = p.split(':')
713 if providee in self.preferred and self.preferred[providee] != provider:
714 bb.error("conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.preferred[providee]))
715 self.preferred[providee] = provider
717 # Calculate priorities for each file
718 for p in self.status.pkg_fn.keys():
719 self.status.bbfile_priority[p] = calc_bbfile_priority(p)
721 def buildWorldTargetList(self):
723 Build package list for "bitbake world"
725 all_depends = self.status.all_depends
726 pn_provides = self.status.pn_provides
727 bb.debug(1, "collating packages for \"world\"")
728 for f in self.status.possible_world:
730 pn = self.status.pkg_fn[f]
732 for p in pn_provides[pn]:
733 if p.startswith('virtual/'):
734 bb.debug(2, "skipping %s due to %s provider starting with virtual/" % (f, p))
737 for pf in self.status.providers[p]:
738 if self.status.pkg_fn[pf] != pn:
739 bb.debug(2, "skipping %s due to both us and %s providing %s" % (f, pf, p))
743 self.status.world_target.add(pn)
745 # drop reference count now
746 self.status.possible_world = None
747 self.status.all_depends = None
749 def myProgressCallback( self, x, y, f, bb_cache, from_cache ):
750 # feed the status with new input
752 self.status.handle_bb_data(f, bb_cache, from_cache)
756 if os.isatty(sys.stdout.fileno()):
757 sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
761 sys.stdout.write("Parsing .bb files, please wait...")
764 sys.stdout.write("done.")
767 def interactiveMode( self ):
768 """Drop off into a shell"""
771 except ImportError, details:
772 bb.fatal("Sorry, shell not available (%s)" % details )
774 bb.data.update_data( self.configuration.data )
778 def parseConfigurationFile( self, afile ):
780 self.configuration.data = bb.parse.handle( afile, self.configuration.data )
782 bb.fatal( "Unable to open %s" % afile )
783 except bb.parse.ParseError, details:
784 bb.fatal( "Unable to parse %s (%s)" % (afile, details) )
786 def handleCollections( self, collections ):
787 """Handle collections"""
789 collection_list = collections.split()
790 for c in collection_list:
791 regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1)
793 bb.error("BBFILE_PATTERN_%s not defined" % c)
795 priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1)
797 bb.error("BBFILE_PRIORITY_%s not defined" % c)
800 cre = re.compile(regex)
802 bb.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
806 self.status.bbfile_config_priorities.append((cre, pri))
808 bb.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
811 def cook( self, configuration, args ):
812 self.configuration = configuration
814 if not self.configuration.cmd:
815 self.configuration.cmd = "build"
817 if self.configuration.debug:
818 bb.debug_level = self.configuration.debug
820 self.configuration.data = bb.data.init()
822 for f in self.configuration.file:
823 self.parseConfigurationFile( f )
825 self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
827 if self.configuration.show_environment:
828 self.showEnvironment()
831 # inject custom variables
832 if not bb.data.getVar("BUILDNAME", self.configuration.data):
833 bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
834 bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data)
836 buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
838 if self.configuration.interactive:
839 self.interactiveMode()
841 if self.configuration.buildfile is not None:
842 bf = os.path.abspath( self.configuration.buildfile )
844 bbfile_data = bb.parse.handle(bf, self.configuration.data)
846 bb.fatal("Unable to open %s" % bf)
848 item = bb.data.getVar('PN', bbfile_data, 1)
850 self.tryBuildPackage( bf, item, bbfile_data )
851 except bb.build.EventException:
852 bb.error( "Build of '%s' failed" % item )
854 sys.exit( self.stats.show() )
856 # initialise the parsing status now we know we will need deps
857 self.status = BBParsingStatus()
859 ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
860 self.status.ignored_dependencies = Set( ignore.split() )
862 self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
866 if not pkgs_to_build:
868 pkgs_to_build.extend(args)
869 if not pkgs_to_build:
870 bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
872 pkgs_to_build = bbpkgs.split()
873 if not pkgs_to_build and not self.configuration.show_versions \
874 and not self.configuration.interactive \
875 and not self.configuration.show_environment:
876 print "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help'"
877 print "for usage information."
880 # Import Psyco if available and not disabled
881 if not self.configuration.disable_psyco:
886 bb.note("Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
888 psyco.bind( self.collect_bbfiles )
890 bb.note("You have disabled Psyco. This decreases performance.")
893 bb.debug(1, "collecting .bb files")
894 self.collect_bbfiles( self.myProgressCallback )
895 bb.debug(1, "parsing complete")
898 if self.configuration.parse_only:
899 print "Requested parsing .bb files only. Exiting."
902 bb.data.update_data( self.configuration.data )
905 if self.configuration.show_versions:
908 if 'world' in pkgs_to_build:
909 self.buildWorldTargetList()
910 pkgs_to_build.remove('world')
911 for t in self.status.world_target:
912 pkgs_to_build.append(t)
914 bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.data))
917 for k in pkgs_to_build:
920 if self.buildProvider( k , False ) == 0:
923 except bb.build.EventException:
924 bb.error("Build of " + k + " failed")
929 if self.configuration.abort:
932 bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.data, failures))
934 sys.exit( self.stats.show() )
936 except KeyboardInterrupt:
937 print "\nNOTE: KeyboardInterrupt - Build not completed."
940 def get_bbfiles( self, path = os.getcwd() ):
941 """Get list of default .bb files by reading out the current directory"""
942 contents = os.listdir(path)
945 (root, ext) = os.path.splitext(f)
947 bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
950 def find_bbfiles( self, path ):
951 """Find all the .bb files in a directory (uses find)"""
952 findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
954 finddata = os.popen(findcmd)
957 return finddata.readlines()
959 def collect_bbfiles( self, progressCallback ):
960 """Collect all available .bb build files"""
961 self.cb = progressCallback
962 parsed, cached, skipped, masked = 0, 0, 0, 0
963 self.bb_cache = bb.cache.init(self)
965 files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
966 data.setVar("BBFILES", " ".join(files), self.configuration.data)
969 files = self.get_bbfiles()
972 bb.error("no files to build.")
977 dirfiles = self.find_bbfiles(f)
981 newfiles += glob.glob(f) or [ f ]
983 bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1) or ""
985 bbmask_compiled = re.compile(bbmask)
986 except sre_constants.error:
987 bb.fatal("BBMASK is not a valid regular expression.")
989 for i in xrange( len( newfiles ) ):
991 if bbmask and bbmask_compiled.search(f):
992 bb.debug(1, "bbmake: skipping %s" % f)
995 debug(1, "bbmake: parsing %s" % f)
997 # read a file's metadata
999 fromCache, skip = self.bb_cache.loadData(f, self)
1002 #bb.note("Skipping %s" % f)
1003 self.bb_cache.skip(f)
1005 elif fromCache: cached += 1
1009 # allow metadata files to add items to BBFILES
1010 #data.update_data(self.pkgdata[f])
1011 addbbfiles = self.bb_cache.getVar('BBFILES', f, False) or None
1013 for aof in addbbfiles.split():
1014 if not files.count(aof):
1015 if not os.path.isabs(aof):
1016 aof = os.path.join(os.path.dirname(f),aof)
1019 # now inform the caller
1020 if self.cb is not None:
1021 self.cb( i + 1, len( newfiles ), f, self.bb_cache, fromCache )
1024 self.bb_cache.remove(f)
1025 bb.error("opening %s: %s" % (f, e))
1027 except KeyboardInterrupt:
1028 self.bb_cache.sync()
1030 except Exception, e:
1031 self.bb_cache.remove(f)
1032 bb.error("%s while parsing %s" % (e, f))
1034 self.bb_cache.remove(f)
1037 if self.cb is not None:
1038 print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ),
1040 self.bb_cache.sync()
1042 #============================================================================#
1044 #============================================================================#
1047 parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
1048 usage = """%prog [options] [package ...]
1050 Executes the specified task (default is 'build') for a given set of BitBake files.
1051 It expects that BBFILES is defined, which is a space seperated list of files to
1052 be executed. BBFILES does support wildcards.
1053 Default BBFILES are the .bb files in the current directory.""" )
1055 parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
1056 action = "store", dest = "buildfile", default = None )
1058 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.",
1059 action = "store_false", dest = "abort", default = True )
1061 parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
1062 action = "store_true", dest = "force", default = False )
1064 parser.add_option( "-i", "--interactive", help = "drop into the interactive mode.",
1065 action = "store_true", dest = "interactive", default = False )
1067 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)",
1068 action = "store", dest = "cmd", default = "build" )
1070 parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
1071 action = "append", dest = "file", default = [] )
1073 parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
1074 action = "store_true", dest = "verbose", default = False )
1076 parser.add_option( "-D", "--debug", help = "Increase the debug level",
1077 action = "count", dest="debug", default = 0)
1079 parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
1080 action = "store_true", dest = "dry_run", default = False )
1082 parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
1083 action = "store_true", dest = "parse_only", default = False )
1085 parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
1086 action = "store_true", dest = "disable_psyco", default = False )
1088 parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
1089 action = "store_true", dest = "show_versions", default = False )
1091 parser.add_option( "-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
1092 action = "store_true", dest = "show_environment", default = False )
1094 options, args = parser.parse_args( sys.argv )
1097 cooker.cook( BBConfiguration( options ), args[1:] )
1101 if __name__ == "__main__":