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'|/-\\' )
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
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)
255 buildAllDeps = self.status.build_all[fn]
257 # Error on build time dependency loops
258 if build_depends and build_depends.count(fn) > 1:
259 bb.error("%s depends on itself (eventually)" % fn)
260 bb.error("upwards chain is: %s" % (" -> ".join(self.build_path)))
263 # See if this is a runtime dependency we've already built
264 # Or a build dependency being handled in a different build chain
265 if fn in self.building_list:
266 return self.addRunDeps(fn, virtual , buildAllDeps)
268 item = self.status.pkg_fn[fn]
270 self.building_list.append(fn)
272 pathstr = "%s (%s)" % (item, virtual)
273 self.build_path.append(pathstr)
275 depends_list = (bb.data.getVar('DEPENDS', the_data, True) or "").split()
277 if self.configuration.verbose:
278 bb.note("current path: %s" % (" -> ".join(self.build_path)))
279 bb.note("dependencies for %s are: %s" % (item, " ".join(depends_list)))
284 depcmd = self.configuration.cmd
285 bbdepcmd = bb.data.getVarFlag('do_%s' % self.configuration.cmd, 'bbdepcmd', the_data)
286 if bbdepcmd is not None:
293 oldcmd = self.configuration.cmd
294 self.configuration.cmd = depcmd
296 for dependency in depends_list:
297 if dependency in self.status.ignored_dependencies:
301 if self.buildProvider( dependency , buildAllDeps , build_depends ) == 0:
302 bb.error("dependency %s (for %s) not satisfied" % (dependency,item))
304 if self.configuration.abort:
308 self.configuration.cmd = oldcmd
314 if not self.addRunDeps(fn, virtual , buildAllDeps):
317 if bb.build.stamp_is_current('do_%s' % self.configuration.cmd, the_data):
318 self.build_cache.append(fn)
321 return self.tryBuildPackage( fn, item, the_data )
324 self.building_list.remove(fn)
325 self.build_path.remove(pathstr)
327 def findBestProvider( self, pn, pkg_pn = None):
329 If there is a PREFERRED_VERSION, find the highest-priority bbfile
330 providing that version. If not, find the latest version provided by
331 an bbfile in the highest-priority set.
334 pkg_pn = self.status.pkg_pn
339 priority = self.status.bbfile_priority[f]
340 if priority not in priorities:
341 priorities[priority] = []
342 priorities[priority].append(f)
343 p_list = priorities.keys()
344 p_list.sort(lambda a, b: a - b)
347 tmp_pn = [priorities[p]] + tmp_pn
349 preferred_file = None
351 localdata = data.createCopy(self.configuration.data)
352 bb.data.setVar('OVERRIDES', "%s:%s" % (pn, data.getVar('OVERRIDES', localdata)), localdata)
353 bb.data.update_data(localdata)
355 preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, localdata, True)
357 m = re.match('(.*)_(.*)', preferred_v)
359 preferred_v = m.group(1)
360 preferred_r = m.group(2)
364 for file_set in tmp_pn:
366 pv,pr = self.status.pkg_pvpr[f]
367 if preferred_v == pv and (preferred_r == pr or preferred_r == None):
369 preferred_ver = (pv, pr)
374 pv_str = '%s-%s' % (preferred_v, preferred_r)
377 if preferred_file is None:
378 bb.note("preferred version %s of %s not available" % (pv_str, pn))
380 bb.debug(1, "selecting %s as PREFERRED_VERSION %s of package %s" % (preferred_file, pv_str, pn))
384 # get highest priority file set
389 for file_name in files:
390 pv,pr = self.status.pkg_pvpr[file_name]
391 dp = self.status.pkg_dp[file_name]
393 if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pv, pr)) < 0)) or (dp > latest_p):
397 if preferred_file is None:
398 preferred_file = latest_f
399 preferred_ver = latest
401 return (latest,latest_f,preferred_ver, preferred_file)
403 def showVersions( self ):
404 pkg_pn = self.status.pkg_pn
405 preferred_versions = {}
409 for pn in pkg_pn.keys():
410 (last_ver,last_file,pref_ver,pref_file) = self.findBestProvider(pn)
411 preferred_versions[pn] = (pref_ver, pref_file)
412 latest_versions[pn] = (last_ver, last_file)
414 pkg_list = pkg_pn.keys()
418 pref = preferred_versions[p]
419 latest = latest_versions[p]
422 prefstr = pref[0][0] + "-" + pref[0][1]
426 print "%-30s %20s %20s" % (p, latest[0][0] + "-" + latest[0][1],
430 def showEnvironment( self ):
431 """Show the outer or per-package environment"""
432 if self.configuration.buildfile:
433 self.bb_cache = bb.cache.init(self)
435 self.configuration.data, fromCache = self.bb_cache.loadDataFull(self.configuration.buildfile, self)
437 fatal("Unable to read %s: %s" % ( self.configuration.buildfile, e ))
440 # emit variables and shell functions
442 data.update_data( self.configuration.data )
443 data.emit_env(sys.__stdout__, self.configuration.data, True)
446 # emit the metadata which isnt valid shell
447 for e in self.configuration.data.keys():
448 if data.getVarFlag( e, 'python', self.configuration.data ):
449 sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, self.configuration.data, 1)))
451 def filterProviders(self, providers, item):
453 Take a list of providers and filter/reorder according to the
454 environment variables and previous build results
457 preferred_versions = {}
459 # Collate providers by PN
462 pn = self.status.pkg_fn[p]
467 bb.debug(1, "providers for %s are: %s" % (item, pkg_pn.keys()))
469 for pn in pkg_pn.keys():
470 preferred_versions[pn] = self.findBestProvider(pn, pkg_pn)[2:4]
471 eligible.append(preferred_versions[pn][1])
474 if p in self.build_cache_fail:
475 bb.debug(1, "rejecting already-failed %s" % p)
478 if len(eligible) == 0:
479 bb.error("no eligible providers for %s" % item)
482 # look to see if one of them is already staged, or marked as preferred.
483 # if so, bump it to the head of the queue
485 pn = self.status.pkg_fn[p]
486 pv, pr = self.status.pkg_pvpr[p]
488 stamp = '%s.do_populate_staging' % self.status.stamp[p]
489 if os.path.exists(stamp):
490 (newvers, fn) = preferred_versions[pn]
491 if not fn in eligible:
492 # package was made ineligible by already-failed check
494 oldver = "%s-%s" % (pv, pr)
495 newver = '-'.join(newvers)
496 if (newver != oldver):
497 extra_chat = "%s (%s) already staged but upgrading to %s to satisfy %s" % (pn, oldver, newver, item)
499 extra_chat = "Selecting already-staged %s (%s) to satisfy %s" % (pn, oldver, item)
500 if self.configuration.verbose:
501 bb.note("%s" % extra_chat)
503 eligible = [fn] + eligible
509 def buildProvider( self, item , buildAllDeps , build_depends = [] ):
511 Build something to provide a named build requirement
512 (takes item names from DEPENDS namespace)
516 discriminated = False
518 if not item in self.status.providers:
519 bb.error("Nothing provides dependency %s" % item)
520 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
523 all_p = self.status.providers[item]
526 if p in self.build_cache:
527 bb.debug(1, "already built %s in this run\n" % p)
530 eligible = self.filterProviders(all_p, item)
535 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
537 self.preferred[item] = prefervar
539 if item in self.preferred:
541 pn = self.status.pkg_fn[p]
542 if self.preferred[item] == pn:
543 if self.configuration.verbose:
544 bb.note("selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
546 eligible = [p] + eligible
550 if len(eligible) > 1 and discriminated == False:
551 if item not in self.consider_msgs_cache:
554 providers_list.append(self.status.pkg_fn[fn])
555 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
556 bb.note("consider defining PREFERRED_PROVIDER_%s" % item)
557 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data))
558 self.consider_msgs_cache.append(item)
561 # run through the list until we find one that we can build
563 bb.debug(2, "selecting %s to satisfy %s" % (fn, item))
564 if self.tryBuild(fn, item, buildAllDeps, build_depends + [fn]):
567 bb.note("no buildable providers for %s" % item)
568 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
571 def buildRProvider( self, item , buildAllDeps ):
573 Build something to provide a named runtime requirement
574 (takes item names from RDEPENDS/PACKAGES namespace)
579 discriminated = False
584 all_p = self.getProvidersRun(item)
587 bb.error("Nothing provides runtime dependency %s" % (item))
588 bb.event.fire(bb.event.NoProvider(item,self.configuration.data,runtime=True))
592 if p in self.rbuild_cache:
593 bb.debug(2, "Already built %s providing runtime %s\n" % (p,item))
595 if p in self.build_cache:
596 bb.debug(2, "Already built %s but adding any further RDEPENDS for %s\n" % (p, item))
597 return self.addRunDeps(p, item , buildAllDeps)
599 eligible = self.filterProviders(all_p, item)
605 pn = self.status.pkg_fn[p]
606 provides = self.status.pn_provides[pn]
607 for provide in provides:
608 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, self.configuration.data, 1)
610 if self.configuration.verbose:
611 bb.note("selecting %s to satisfy runtime %s due to PREFERRED_PROVIDERS" % (pn, item))
613 eligible = [p] + eligible
616 if len(eligible) > 1 and len(preferred) == 0:
617 if item not in self.consider_msgs_cache:
620 providers_list.append(self.status.pkg_fn[fn])
621 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
622 bb.note("consider defining a PREFERRED_PROVIDER to match runtime %s" % item)
623 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
624 self.consider_msgs_cache.append(item)
626 if len(preferred) > 1:
627 if item not in self.consider_msgs_cache:
630 providers_list.append(self.status.pkg_fn[fn])
631 bb.note("multiple preferred providers are available (%s);" % ", ".join(providers_list))
632 bb.note("consider defining only one PREFERRED_PROVIDER to match runtime %s" % item)
633 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
634 self.consider_msgs_cache.append(item)
636 # run through the list until we find one that we can build
638 bb.debug(2, "selecting %s to satisfy runtime %s" % (fn, item))
639 if self.tryBuild(fn, item, buildAllDeps):
642 bb.error("No buildable providers for runtime %s" % item)
643 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
646 def getProvidersRun(self, rdepend):
648 Return any potential providers of runtime rdepend
652 if rdepend in self.status.rproviders:
653 rproviders += self.status.rproviders[rdepend]
655 if rdepend in self.status.packages:
656 rproviders += self.status.packages[rdepend]
661 # Only search dynamic packages if we can't find anything in other variables
662 for pattern in self.status.packages_dynamic:
663 regexp = re.compile(pattern)
664 if regexp.match(rdepend):
665 rproviders += self.status.packages_dynamic[pattern]
669 def addRunDeps(self , fn, item , buildAllDeps):
671 Add any runtime dependencies of runtime item provided by fn
672 as long as item has't previously been processed by this function.
675 if item in self.rbuild_cache:
682 self.rbuild_cache.append(item)
684 if fn in self.status.rundeps and item in self.status.rundeps[fn]:
685 rdepends += self.status.rundeps[fn][item].keys()
686 if fn in self.status.runrecs and item in self.status.runrecs[fn]:
687 rdepends += self.status.runrecs[fn][item].keys()
689 bb.debug(2, "Additional runtime dependencies for %s are: %s" % (item, " ".join(rdepends)))
691 for rdepend in rdepends:
692 if rdepend in self.status.ignored_dependencies:
694 if not self.buildRProvider(rdepend, buildAllDeps):
698 def buildDepgraph( self ):
699 all_depends = self.status.all_depends
700 pn_provides = self.status.pn_provides
702 def calc_bbfile_priority(filename):
703 for (regex, pri) in self.status.bbfile_config_priorities:
704 if regex.match(filename):
708 # Handle PREFERRED_PROVIDERS
709 for p in (bb.data.getVar('PREFERRED_PROVIDERS', self.configuration.data, 1) or "").split():
710 (providee, provider) = p.split(':')
711 if providee in self.preferred and self.preferred[providee] != provider:
712 bb.error("conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.preferred[providee]))
713 self.preferred[providee] = provider
715 # Calculate priorities for each file
716 for p in self.status.pkg_fn.keys():
717 self.status.bbfile_priority[p] = calc_bbfile_priority(p)
719 def buildWorldTargetList(self):
721 Build package list for "bitbake world"
723 all_depends = self.status.all_depends
724 pn_provides = self.status.pn_provides
725 bb.debug(1, "collating packages for \"world\"")
726 for f in self.status.possible_world:
728 pn = self.status.pkg_fn[f]
730 for p in pn_provides[pn]:
731 if p.startswith('virtual/'):
732 bb.debug(2, "skipping %s due to %s provider starting with virtual/" % (f, p))
735 for pf in self.status.providers[p]:
736 if self.status.pkg_fn[pf] != pn:
737 bb.debug(2, "skipping %s due to both us and %s providing %s" % (f, pf, p))
741 self.status.world_target.add(pn)
743 # drop reference count now
744 self.status.possible_world = None
745 self.status.all_depends = None
747 def myProgressCallback( self, x, y, f, bb_cache, from_cache ):
748 # feed the status with new input
750 self.status.handle_bb_data(f, bb_cache, from_cache)
754 if os.isatty(sys.stdout.fileno()):
755 sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
759 sys.stdout.write("Parsing .bb files, please wait...")
762 sys.stdout.write("done.")
765 def interactiveMode( self ):
766 """Drop off into a shell"""
769 except ImportError, details:
770 bb.fatal("Sorry, shell not available (%s)" % details )
772 bb.data.update_data( self.configuration.data )
776 def parseConfigurationFile( self, afile ):
778 self.configuration.data = bb.parse.handle( afile, self.configuration.data )
780 bb.fatal( "Unable to open %s" % afile )
781 except bb.parse.ParseError, details:
782 bb.fatal( "Unable to parse %s (%s)" % (afile, details) )
784 def handleCollections( self, collections ):
785 """Handle collections"""
787 collection_list = collections.split()
788 for c in collection_list:
789 regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1)
791 bb.error("BBFILE_PATTERN_%s not defined" % c)
793 priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1)
795 bb.error("BBFILE_PRIORITY_%s not defined" % c)
798 cre = re.compile(regex)
800 bb.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
804 self.status.bbfile_config_priorities.append((cre, pri))
806 bb.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
809 def cook( self, configuration, args ):
810 self.configuration = configuration
812 if not self.configuration.cmd:
813 self.configuration.cmd = "build"
815 if self.configuration.debug:
816 bb.debug_level = self.configuration.debug
818 self.configuration.data = bb.data.init()
820 for f in self.configuration.file:
821 self.parseConfigurationFile( f )
823 self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
825 if self.configuration.show_environment:
826 self.showEnvironment()
829 # inject custom variables
830 if not bb.data.getVar("BUILDNAME", self.configuration.data):
831 bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
832 bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data)
834 buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
836 if self.configuration.interactive:
837 self.interactiveMode()
839 if self.configuration.buildfile is not None:
840 bf = os.path.abspath( self.configuration.buildfile )
842 bbfile_data = bb.parse.handle(bf, self.configuration.data)
844 bb.fatal("Unable to open %s" % bf)
846 item = bb.data.getVar('PN', bbfile_data, 1)
848 self.tryBuildPackage( bf, item, bbfile_data )
849 except bb.build.EventException:
850 bb.error( "Build of '%s' failed" % item )
852 sys.exit( self.stats.show() )
854 # initialise the parsing status now we know we will need deps
855 self.status = BBParsingStatus()
857 ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
858 self.status.ignored_dependencies = Set( ignore.split() )
860 self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
864 if not pkgs_to_build:
866 pkgs_to_build.extend(args)
867 if not pkgs_to_build:
868 bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
870 pkgs_to_build = bbpkgs.split()
871 if not pkgs_to_build and not self.configuration.show_versions \
872 and not self.configuration.interactive \
873 and not self.configuration.show_environment:
874 print "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help'"
875 print "for usage information."
878 # Import Psyco if available and not disabled
879 if not self.configuration.disable_psyco:
884 bb.note("Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
886 psyco.bind( self.collect_bbfiles )
888 bb.note("You have disabled Psyco. This decreases performance.")
891 bb.debug(1, "collecting .bb files")
892 self.collect_bbfiles( self.myProgressCallback )
893 bb.debug(1, "parsing complete")
896 if self.configuration.parse_only:
897 print "Requested parsing .bb files only. Exiting."
900 bb.data.update_data( self.configuration.data )
903 if self.configuration.show_versions:
906 if 'world' in pkgs_to_build:
907 self.buildWorldTargetList()
908 pkgs_to_build.remove('world')
909 for t in self.status.world_target:
910 pkgs_to_build.append(t)
912 bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.data))
915 for k in pkgs_to_build:
918 if self.buildProvider( k , False ) == 0:
921 except bb.build.EventException:
922 bb.error("Build of " + k + " failed")
927 if self.configuration.abort:
930 bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.data, failures))
932 sys.exit( self.stats.show() )
934 except KeyboardInterrupt:
935 print "\nNOTE: KeyboardInterrupt - Build not completed."
938 def get_bbfiles( self, path = os.getcwd() ):
939 """Get list of default .bb files by reading out the current directory"""
940 contents = os.listdir(path)
943 (root, ext) = os.path.splitext(f)
945 bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
948 def find_bbfiles( self, path ):
949 """Find all the .bb files in a directory (uses find)"""
950 findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
952 finddata = os.popen(findcmd)
955 return finddata.readlines()
957 def collect_bbfiles( self, progressCallback ):
958 """Collect all available .bb build files"""
959 self.cb = progressCallback
960 parsed, cached, skipped, masked = 0, 0, 0, 0
961 self.bb_cache = bb.cache.init(self)
963 files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
964 data.setVar("BBFILES", " ".join(files), self.configuration.data)
967 files = self.get_bbfiles()
970 bb.error("no files to build.")
975 dirfiles = self.find_bbfiles(f)
979 newfiles += glob.glob(f) or [ f ]
981 bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1) or ""
983 bbmask_compiled = re.compile(bbmask)
984 except sre_constants.error:
985 bb.fatal("BBMASK is not a valid regular expression.")
987 for i in xrange( len( newfiles ) ):
989 if bbmask and bbmask_compiled.search(f):
990 bb.debug(1, "bbmake: skipping %s" % f)
993 debug(1, "bbmake: parsing %s" % f)
995 # read a file's metadata
997 fromCache, skip = self.bb_cache.loadData(f, self)
1000 #bb.note("Skipping %s" % f)
1001 self.bb_cache.skip(f)
1003 elif fromCache: cached += 1
1007 # allow metadata files to add items to BBFILES
1008 #data.update_data(self.pkgdata[f])
1009 addbbfiles = self.bb_cache.getVar('BBFILES', f, False) or None
1011 for aof in addbbfiles.split():
1012 if not files.count(aof):
1013 if not os.path.isabs(aof):
1014 aof = os.path.join(os.path.dirname(f),aof)
1017 # now inform the caller
1018 if self.cb is not None:
1019 self.cb( i + 1, len( newfiles ), f, self.bb_cache, fromCache )
1022 self.bb_cache.remove(f)
1023 bb.error("opening %s: %s" % (f, e))
1025 except KeyboardInterrupt:
1026 self.bb_cache.sync()
1028 except Exception, e:
1029 self.bb_cache.remove(f)
1030 bb.error("%s while parsing %s" % (e, f))
1032 self.bb_cache.remove(f)
1035 if self.cb is not None:
1036 print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ),
1038 self.bb_cache.sync()
1040 #============================================================================#
1042 #============================================================================#
1045 parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
1046 usage = """%prog [options] [package ...]
1048 Executes the specified task (default is 'build') for a given set of BitBake files.
1049 It expects that BBFILES is defined, which is a space seperated list of files to
1050 be executed. BBFILES does support wildcards.
1051 Default BBFILES are the .bb files in the current directory.""" )
1053 parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
1054 action = "store", dest = "buildfile", default = None )
1056 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.",
1057 action = "store_false", dest = "abort", default = True )
1059 parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
1060 action = "store_true", dest = "force", default = False )
1062 parser.add_option( "-i", "--interactive", help = "drop into the interactive mode.",
1063 action = "store_true", dest = "interactive", default = False )
1065 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)",
1066 action = "store", dest = "cmd", default = "build" )
1068 parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
1069 action = "append", dest = "file", default = [] )
1071 parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
1072 action = "store_true", dest = "verbose", default = False )
1074 parser.add_option( "-D", "--debug", help = "Increase the debug level",
1075 action = "count", dest="debug", default = 0)
1077 parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
1078 action = "store_true", dest = "dry_run", default = False )
1080 parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
1081 action = "store_true", dest = "parse_only", default = False )
1083 parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
1084 action = "store_true", dest = "disable_psyco", default = False )
1086 parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
1087 action = "store_true", dest = "show_versions", default = False )
1089 parser.add_option( "-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
1090 action = "store_true", dest = "show_environment", default = False )
1092 options, args = parser.parse_args( sys.argv )
1095 cooker.cook( BBConfiguration( options ), args[1:] )
1099 if __name__ == "__main__":