2 # ex:ts=4:sw=4:sts=4:et
3 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
5 # Copyright (C) 2003, 2004 Chris Larson
6 # Copyright (C) 2003, 2004 Phil Blundell
7 # Copyright (C) 2003 - 2005 Michael 'Mickey' Lauer
8 # Copyright (C) 2005 Holger Hans Peter Freyther
9 # Copyright (C) 2005 ROAD GmbH
11 # This program is free software; you can redistribute it and/or modify it under
12 # the terms of the GNU General Public License as published by the Free Software
13 # Foundation; either version 2 of the License, or (at your option) any later
16 # This program is distributed in the hope that it will be useful, but WITHOUT
17 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License along with
21 # this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22 # Place, Suite 330, Boston, MA 02111-1307 USA.
24 import sys, os, getopt, glob, copy, os.path, re, time
25 sys.path.insert(0,os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
27 from bb import utils, data, parse, debug, event, fatal, cache
29 import itertools, optparse
31 parsespin = itertools.cycle( r'|/-\\' )
36 #============================================================================#
38 #============================================================================#
39 class BBParsingStatus:
41 The initial idea for this status class is to use the data when it is
42 already loaded instead of loading it from various place over and over
50 self.packages_dynamic = {}
51 self.bbfile_priority = {}
52 self.bbfile_config_priorities = []
53 self.ignored_dependencies = None
54 self.possible_world = []
55 self.world_target = Set()
61 self.all_depends = Set()
67 def handle_bb_data(self, file_name, bb_cache, cached):
69 We will fill the dictionaries with the stuff we
70 need for building the tree more fast
73 pn = bb_cache.getVar('PN', file_name, True)
74 pv = bb_cache.getVar('PV', file_name, True)
75 pr = bb_cache.getVar('PR', file_name, True)
76 dp = int(bb_cache.getVar('DEFAULT_PREFERENCE', file_name, True) or "0")
77 provides = Set([pn] + (bb_cache.getVar("PROVIDES", file_name, True) or "").split())
78 depends = (bb_cache.getVar("DEPENDS", file_name, True) or "").split()
79 packages = (bb_cache.getVar('PACKAGES', file_name, True) or "").split()
80 packages_dynamic = (bb_cache.getVar('PACKAGES_DYNAMIC', file_name, True) or "").split()
81 rprovides = (bb_cache.getVar("RPROVIDES", file_name, True) or "").split()
83 # build PackageName to FileName lookup table
84 if pn not in self.pkg_pn:
86 self.pkg_pn[pn].append(file_name)
88 self.build_all[file_name] = int(bb_cache.getVar('BUILD_ALL_DEPS', file_name, True) or "0")
89 self.stamp[file_name] = bb_cache.getVar('STAMP', file_name, True)
91 # build FileName to PackageName lookup table
92 self.pkg_fn[file_name] = pn
93 self.pkg_pvpr[file_name] = (pv,pr)
94 self.pkg_dp[file_name] = dp
96 # Build forward and reverse provider hashes
97 # Forward: virtual -> [filenames]
98 # Reverse: PN -> [virtuals]
99 if pn not in self.pn_provides:
100 self.pn_provides[pn] = Set()
101 self.pn_provides[pn] |= provides
103 for provide in provides:
104 if provide not in self.providers:
105 self.providers[provide] = []
106 self.providers[provide].append(file_name)
109 self.all_depends.add(dep)
111 # Build reverse hash for PACKAGES, so runtime dependencies
112 # can be be resolved (RDEPENDS, RRECOMMENDS etc.)
113 for package in packages:
114 if not package in self.packages:
115 self.packages[package] = []
116 self.packages[package].append(file_name)
117 rprovides += (bb_cache.getVar("RPROVIDES_%s" % package, file_name, 1) or "").split()
119 for package in packages_dynamic:
120 if not package in self.packages_dynamic:
121 self.packages_dynamic[package] = []
122 self.packages_dynamic[package].append(file_name)
124 for rprovide in rprovides:
125 if not rprovide in self.rproviders:
126 self.rproviders[rprovide] = []
127 self.rproviders[rprovide].append(file_name)
129 # Build hash of runtime depeneds and rececommends
131 def add_dep(deplist, deps):
133 if not dep in deplist:
136 if not file_name in self.rundeps:
137 self.rundeps[file_name] = {}
138 if not file_name in self.runrecs:
139 self.runrecs[file_name] = {}
141 for package in packages + [pn]:
142 if not package in self.rundeps[file_name]:
143 self.rundeps[file_name][package] = {}
144 if not package in self.runrecs[file_name]:
145 self.runrecs[file_name][package] = {}
147 add_dep(self.rundeps[file_name][package], bb.utils.explode_deps(bb_cache.getVar('RDEPENDS', file_name, True) or ""))
148 add_dep(self.runrecs[file_name][package], bb.utils.explode_deps(bb_cache.getVar('RRECOMMENDS', file_name, True) or ""))
149 add_dep(self.rundeps[file_name][package], bb.utils.explode_deps(bb_cache.getVar("RDEPENDS_%s" % package, file_name, True) or ""))
150 add_dep(self.runrecs[file_name][package], bb.utils.explode_deps(bb_cache.getVar("RRECOMMENDS_%s" % package, file_name, True) or ""))
152 # Collect files we may need for possible world-dep
154 if not bb_cache.getVar('BROKEN', file_name, True) and not bb_cache.getVar('EXCLUDE_FROM_WORLD', file_name, True):
155 self.possible_world.append(file_name)
158 #============================================================================#
160 #============================================================================#
163 Manage build statistics for one run
172 print "Build statistics:"
173 print " Attempted builds: %d" % self.attempt
175 print " Failed builds: %d" % self.fail
177 print " Dependencies not satisfied: %d" % self.deps
178 if self.fail or self.deps: return 1
182 #============================================================================#
184 #============================================================================#
185 class BBConfiguration( object ):
187 Manages build options and configurations for one run
189 def __init__( self, options ):
190 for key, val in options.__dict__.items():
191 setattr( self, key, val )
193 #============================================================================#
195 #============================================================================#
198 Manages one bitbake build run
201 ParsingStatus = BBParsingStatus # make it visible from the shell
202 Statistics = BBStatistics # make it visible from the shell
204 def __init__( self ):
205 self.build_cache_fail = []
206 self.build_cache = []
207 self.rbuild_cache = []
208 self.building_list = []
210 self.consider_msgs_cache = []
212 self.stats = BBStatistics()
218 def tryBuildPackage( self, fn, item, the_data ):
219 """Build one package"""
220 bb.event.fire(bb.event.PkgStarted(item, the_data))
222 self.stats.attempt += 1
223 if self.configuration.force:
224 bb.data.setVarFlag('do_%s' % self.configuration.cmd, 'force', 1, the_data)
225 if not self.configuration.dry_run:
226 bb.build.exec_task('do_%s' % self.configuration.cmd, the_data)
227 bb.event.fire(bb.event.PkgSucceeded(item, the_data))
228 self.build_cache.append(fn)
230 except bb.build.FuncFailed:
232 bb.error("task stack execution failed")
233 bb.event.fire(bb.event.PkgFailed(item, the_data))
234 self.build_cache_fail.append(fn)
236 except bb.build.EventException, e:
239 bb.error("%s event exception, aborting" % bb.event.getName(event))
240 bb.event.fire(bb.event.PkgFailed(item, the_data))
241 self.build_cache_fail.append(fn)
244 def tryBuild( self, fn, virtual , buildAllDeps , build_depends = []):
246 Build a provider and its dependencies.
247 build_depends is a list of previous build dependencies (not runtime)
248 If build_depends is empty, we're dealing with a runtime depends
251 the_data = self.bb_cache.loadDataFull(fn, self)
253 # Only follow all (runtime) dependencies if doing a build
254 if not buildAllDeps and self.configuration.cmd is "build":
255 buildAllDeps = self.status.build_all[fn]
257 # Error on build time dependency loops
258 if build_depends and build_depends.count(fn) > 1:
259 bb.error("%s depends on itself (eventually)" % fn)
260 bb.error("upwards chain is: %s" % (" -> ".join(self.build_path)))
263 # See if this is a runtime dependency we've already built
264 # Or a build dependency being handled in a different build chain
265 if fn in self.building_list:
266 return self.addRunDeps(fn, virtual , buildAllDeps)
268 item = self.status.pkg_fn[fn]
270 self.building_list.append(fn)
272 pathstr = "%s (%s)" % (item, virtual)
273 self.build_path.append(pathstr)
275 depends_list = (bb.data.getVar('DEPENDS', the_data, True) or "").split()
277 if self.configuration.verbose:
278 bb.note("current path: %s" % (" -> ".join(self.build_path)))
279 bb.note("dependencies for %s are: %s" % (item, " ".join(depends_list)))
284 depcmd = self.configuration.cmd
285 bbdepcmd = bb.data.getVarFlag('do_%s' % self.configuration.cmd, 'bbdepcmd', the_data)
286 if bbdepcmd is not None:
293 oldcmd = self.configuration.cmd
294 self.configuration.cmd = depcmd
296 for dependency in depends_list:
297 if dependency in self.status.ignored_dependencies:
301 if self.buildProvider( dependency , buildAllDeps , build_depends ) == 0:
302 bb.error("dependency %s (for %s) not satisfied" % (dependency,item))
304 if self.configuration.abort:
308 self.configuration.cmd = oldcmd
314 if not self.addRunDeps(fn, virtual , buildAllDeps):
317 if bb.build.stamp_is_current('do_%s' % self.configuration.cmd, the_data):
318 self.build_cache.append(fn)
321 return self.tryBuildPackage( fn, item, the_data )
324 self.building_list.remove(fn)
325 self.build_path.remove(pathstr)
327 def findBestProvider( self, pn, pkg_pn = None):
329 If there is a PREFERRED_VERSION, find the highest-priority bbfile
330 providing that version. If not, find the latest version provided by
331 an bbfile in the highest-priority set.
334 pkg_pn = self.status.pkg_pn
339 priority = self.status.bbfile_priority[f]
340 if priority not in priorities:
341 priorities[priority] = []
342 priorities[priority].append(f)
343 p_list = priorities.keys()
344 p_list.sort(lambda a, b: a - b)
347 tmp_pn = [priorities[p]] + tmp_pn
349 preferred_file = None
351 localdata = data.createCopy(self.configuration.data)
352 bb.data.setVar('OVERRIDES', "%s:%s" % (pn, data.getVar('OVERRIDES', localdata)), localdata)
353 bb.data.update_data(localdata)
355 preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, localdata, True)
357 m = re.match('(.*)_(.*)', preferred_v)
359 preferred_v = m.group(1)
360 preferred_r = m.group(2)
364 for file_set in tmp_pn:
366 pv,pr = self.status.pkg_pvpr[f]
367 if preferred_v == pv and (preferred_r == pr or preferred_r == None):
369 preferred_ver = (pv, pr)
374 pv_str = '%s-%s' % (preferred_v, preferred_r)
377 if preferred_file is None:
378 bb.note("preferred version %s of %s not available" % (pv_str, pn))
380 bb.debug(1, "selecting %s as PREFERRED_VERSION %s of package %s" % (preferred_file, pv_str, pn))
384 # get highest priority file set
389 for file_name in files:
390 pv,pr = self.status.pkg_pvpr[file_name]
391 dp = self.status.pkg_dp[file_name]
393 if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pv, pr)) < 0)) or (dp > latest_p):
397 if preferred_file is None:
398 preferred_file = latest_f
399 preferred_ver = latest
401 return (latest,latest_f,preferred_ver, preferred_file)
403 def showVersions( self ):
404 pkg_pn = self.status.pkg_pn
405 preferred_versions = {}
409 for pn in pkg_pn.keys():
410 (last_ver,last_file,pref_ver,pref_file) = self.findBestProvider(pn)
411 preferred_versions[pn] = (pref_ver, pref_file)
412 latest_versions[pn] = (last_ver, last_file)
414 pkg_list = pkg_pn.keys()
418 pref = preferred_versions[p]
419 latest = latest_versions[p]
422 prefstr = pref[0][0] + "-" + pref[0][1]
426 print "%-30s %20s %20s" % (p, latest[0][0] + "-" + latest[0][1],
430 def showEnvironment( self ):
431 """Show the outer or per-package environment"""
432 if self.configuration.buildfile:
434 self.bb_cache = bb.cache.init(self)
436 self.configuration.data = self.bb_cache.loadDataFull(self.configuration.buildfile, self)
438 fatal("Unable to read %s: %s" % ( self.configuration.buildfile, e ))
441 # emit variables and shell functions
443 data.update_data( self.configuration.data )
444 data.emit_env(sys.__stdout__, self.configuration.data, True)
447 # emit the metadata which isnt valid shell
448 for e in self.configuration.data.keys():
449 if data.getVarFlag( e, 'python', self.configuration.data ):
450 sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, self.configuration.data, 1)))
452 def filterProviders(self, providers, item):
454 Take a list of providers and filter/reorder according to the
455 environment variables and previous build results
458 preferred_versions = {}
460 # Collate providers by PN
463 pn = self.status.pkg_fn[p]
468 bb.debug(1, "providers for %s are: %s" % (item, pkg_pn.keys()))
470 for pn in pkg_pn.keys():
471 preferred_versions[pn] = self.findBestProvider(pn, pkg_pn)[2:4]
472 eligible.append(preferred_versions[pn][1])
475 if p in self.build_cache_fail:
476 bb.debug(1, "rejecting already-failed %s" % p)
479 if len(eligible) == 0:
480 bb.error("no eligible providers for %s" % item)
483 # look to see if one of them is already staged, or marked as preferred.
484 # if so, bump it to the head of the queue
486 pn = self.status.pkg_fn[p]
487 pv, pr = self.status.pkg_pvpr[p]
489 stamp = '%s.do_populate_staging' % self.status.stamp[p]
490 if os.path.exists(stamp):
491 (newvers, fn) = preferred_versions[pn]
492 if not fn in eligible:
493 # package was made ineligible by already-failed check
495 oldver = "%s-%s" % (pv, pr)
496 newver = '-'.join(newvers)
497 if (newver != oldver):
498 extra_chat = "%s (%s) already staged but upgrading to %s to satisfy %s" % (pn, oldver, newver, item)
500 extra_chat = "Selecting already-staged %s (%s) to satisfy %s" % (pn, oldver, item)
501 if self.configuration.verbose:
502 bb.note("%s" % extra_chat)
504 eligible = [fn] + eligible
510 def buildProvider( self, item , buildAllDeps , build_depends = [] ):
512 Build something to provide a named build requirement
513 (takes item names from DEPENDS namespace)
517 discriminated = False
519 if not item in self.status.providers:
520 bb.error("Nothing provides dependency %s" % item)
521 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
524 all_p = self.status.providers[item]
527 if p in self.build_cache:
528 bb.debug(1, "already built %s in this run\n" % p)
531 eligible = self.filterProviders(all_p, item)
536 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
538 self.preferred[item] = prefervar
540 if item in self.preferred:
542 pn = self.status.pkg_fn[p]
543 if self.preferred[item] == pn:
544 if self.configuration.verbose:
545 bb.note("selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
547 eligible = [p] + eligible
551 if len(eligible) > 1 and discriminated == False:
552 if item not in self.consider_msgs_cache:
555 providers_list.append(self.status.pkg_fn[fn])
556 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
557 bb.note("consider defining PREFERRED_PROVIDER_%s" % item)
558 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data))
559 self.consider_msgs_cache.append(item)
562 # run through the list until we find one that we can build
564 bb.debug(2, "selecting %s to satisfy %s" % (fn, item))
565 if self.tryBuild(fn, item, buildAllDeps, build_depends + [fn]):
568 bb.note("no buildable providers for %s" % item)
569 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
572 def buildRProvider( self, item , buildAllDeps ):
574 Build something to provide a named runtime requirement
575 (takes item names from RDEPENDS/PACKAGES namespace)
580 discriminated = False
585 all_p = self.getProvidersRun(item)
588 bb.error("Nothing provides runtime dependency %s" % (item))
589 bb.event.fire(bb.event.NoProvider(item,self.configuration.data,runtime=True))
593 if p in self.rbuild_cache:
594 bb.debug(2, "Already built %s providing runtime %s\n" % (p,item))
596 if p in self.build_cache:
597 bb.debug(2, "Already built %s but adding any further RDEPENDS for %s\n" % (p, item))
598 return self.addRunDeps(p, item , buildAllDeps)
600 eligible = self.filterProviders(all_p, item)
606 pn = self.status.pkg_fn[p]
607 provides = self.status.pn_provides[pn]
608 for provide in provides:
609 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, self.configuration.data, 1)
611 if self.configuration.verbose:
612 bb.note("selecting %s to satisfy runtime %s due to PREFERRED_PROVIDERS" % (pn, item))
614 eligible = [p] + eligible
617 if len(eligible) > 1 and len(preferred) == 0:
618 if item not in self.consider_msgs_cache:
621 providers_list.append(self.status.pkg_fn[fn])
622 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
623 bb.note("consider defining a PREFERRED_PROVIDER to match runtime %s" % item)
624 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
625 self.consider_msgs_cache.append(item)
627 if len(preferred) > 1:
628 if item not in self.consider_msgs_cache:
631 providers_list.append(self.status.pkg_fn[fn])
632 bb.note("multiple preferred providers are available (%s);" % ", ".join(providers_list))
633 bb.note("consider defining only one PREFERRED_PROVIDER to match runtime %s" % item)
634 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
635 self.consider_msgs_cache.append(item)
637 # run through the list until we find one that we can build
639 bb.debug(2, "selecting %s to satisfy runtime %s" % (fn, item))
640 if self.tryBuild(fn, item, buildAllDeps):
643 bb.error("No buildable providers for runtime %s" % item)
644 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
647 def getProvidersRun(self, rdepend):
649 Return any potential providers of runtime rdepend
653 if rdepend in self.status.rproviders:
654 rproviders += self.status.rproviders[rdepend]
656 if rdepend in self.status.packages:
657 rproviders += self.status.packages[rdepend]
662 # Only search dynamic packages if we can't find anything in other variables
663 for pattern in self.status.packages_dynamic:
664 regexp = re.compile(pattern)
665 if regexp.match(rdepend):
666 rproviders += self.status.packages_dynamic[pattern]
670 def addRunDeps(self , fn, item , buildAllDeps):
672 Add any runtime dependencies of runtime item provided by fn
673 as long as item has't previously been processed by this function.
676 if item in self.rbuild_cache:
683 self.rbuild_cache.append(item)
685 if fn in self.status.rundeps and item in self.status.rundeps[fn]:
686 rdepends += self.status.rundeps[fn][item].keys()
687 if fn in self.status.runrecs and item in self.status.runrecs[fn]:
688 rdepends += self.status.runrecs[fn][item].keys()
690 bb.debug(2, "Additional runtime dependencies for %s are: %s" % (item, " ".join(rdepends)))
692 for rdepend in rdepends:
693 if rdepend in self.status.ignored_dependencies:
695 if not self.buildRProvider(rdepend, buildAllDeps):
699 def buildDepgraph( self ):
700 all_depends = self.status.all_depends
701 pn_provides = self.status.pn_provides
703 localdata = data.createCopy(self.configuration.data)
704 bb.data.update_data(localdata)
706 def calc_bbfile_priority(filename):
707 for (regex, pri) in self.status.bbfile_config_priorities:
708 if regex.match(filename):
712 # Handle PREFERRED_PROVIDERS
713 for p in (bb.data.getVar('PREFERRED_PROVIDERS', localdata, 1) or "").split():
714 (providee, provider) = p.split(':')
715 if providee in self.preferred and self.preferred[providee] != provider:
716 bb.error("conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.preferred[providee]))
717 self.preferred[providee] = provider
719 # Calculate priorities for each file
720 for p in self.status.pkg_fn.keys():
721 self.status.bbfile_priority[p] = calc_bbfile_priority(p)
723 def buildWorldTargetList(self):
725 Build package list for "bitbake world"
727 all_depends = self.status.all_depends
728 pn_provides = self.status.pn_provides
729 bb.debug(1, "collating packages for \"world\"")
730 for f in self.status.possible_world:
732 pn = self.status.pkg_fn[f]
734 for p in pn_provides[pn]:
735 if p.startswith('virtual/'):
736 bb.debug(2, "skipping %s due to %s provider starting with virtual/" % (f, p))
739 for pf in self.status.providers[p]:
740 if self.status.pkg_fn[pf] != pn:
741 bb.debug(2, "skipping %s due to both us and %s providing %s" % (f, pf, p))
745 self.status.world_target.add(pn)
747 # drop reference count now
748 self.status.possible_world = None
749 self.status.all_depends = None
751 def myProgressCallback( self, x, y, f, bb_cache, from_cache ):
752 # feed the status with new input
754 self.status.handle_bb_data(f, bb_cache, from_cache)
758 if os.isatty(sys.stdout.fileno()):
759 sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
763 sys.stdout.write("Parsing .bb files, please wait...")
766 sys.stdout.write("done.")
769 def interactiveMode( self ):
770 """Drop off into a shell"""
773 except ImportError, details:
774 bb.fatal("Sorry, shell not available (%s)" % details )
776 bb.data.update_data( self.configuration.data )
780 def parseConfigurationFile( self, afile ):
782 self.configuration.data = bb.parse.handle( afile, self.configuration.data )
784 # Add the handlers we inherited by INHERITS
785 # FIXME: This assumes that we included at least one .inc file
786 for var in bb.data.keys(self.configuration.data):
787 if bb.data.getVarFlag(var, 'handler', self.configuration.data):
788 bb.event.register(var,bb.data.getVar(var,self.configuration.data))
791 bb.fatal( "Unable to open %s" % afile )
792 except bb.parse.ParseError, details:
793 bb.fatal( "Unable to parse %s (%s)" % (afile, details) )
795 def handleCollections( self, collections ):
796 """Handle collections"""
798 collection_list = collections.split()
799 for c in collection_list:
800 regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1)
802 bb.error("BBFILE_PATTERN_%s not defined" % c)
804 priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1)
806 bb.error("BBFILE_PRIORITY_%s not defined" % c)
809 cre = re.compile(regex)
811 bb.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
815 self.status.bbfile_config_priorities.append((cre, pri))
817 bb.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
820 def cook( self, configuration, args ):
822 We are building stuff here. We do the building
823 from here. By default we try to execute task
827 self.configuration = configuration
829 if not self.configuration.cmd:
830 self.configuration.cmd = "build"
832 if self.configuration.debug:
833 bb.debug_level = self.configuration.debug
835 self.configuration.data = bb.data.init()
837 for f in self.configuration.file:
838 self.parseConfigurationFile( f )
840 self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
844 # Special updated configuration we use for firing events
846 self.configuration.event_data = bb.data.createCopy(self.configuration.data)
847 bb.data.update_data(self.configuration.event_data)
849 if self.configuration.show_environment:
850 self.showEnvironment()
853 # inject custom variables
854 if not bb.data.getVar("BUILDNAME", self.configuration.data):
855 bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
856 bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data)
858 buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
860 if self.configuration.interactive:
861 self.interactiveMode()
863 if self.configuration.buildfile is not None:
864 bf = os.path.abspath( self.configuration.buildfile )
866 bbfile_data = bb.parse.handle(bf, self.configuration.data)
868 bb.fatal("Unable to open %s" % bf)
870 item = bb.data.getVar('PN', bbfile_data, 1)
872 self.tryBuildPackage( bf, item, bbfile_data )
873 except bb.build.EventException:
874 bb.error( "Build of '%s' failed" % item )
876 sys.exit( self.stats.show() )
878 # initialise the parsing status now we know we will need deps
879 self.status = BBParsingStatus()
881 ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
882 self.status.ignored_dependencies = Set( ignore.split() )
884 self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
888 if not pkgs_to_build:
890 pkgs_to_build.extend(args)
891 if not pkgs_to_build:
892 bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
894 pkgs_to_build = bbpkgs.split()
895 if not pkgs_to_build and not self.configuration.show_versions \
896 and not self.configuration.interactive \
897 and not self.configuration.show_environment:
898 print "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help'"
899 print "for usage information."
902 # Import Psyco if available and not disabled
903 if not self.configuration.disable_psyco:
908 bb.note("Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
910 psyco.bind( self.collect_bbfiles )
912 bb.note("You have disabled Psyco. This decreases performance.")
915 bb.debug(1, "collecting .bb files")
916 self.collect_bbfiles( self.myProgressCallback )
917 bb.debug(1, "parsing complete")
920 if self.configuration.parse_only:
921 print "Requested parsing .bb files only. Exiting."
926 if self.configuration.show_versions:
929 if 'world' in pkgs_to_build:
930 self.buildWorldTargetList()
931 pkgs_to_build.remove('world')
932 for t in self.status.world_target:
933 pkgs_to_build.append(t)
935 bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.event_data))
938 for k in pkgs_to_build:
941 if self.buildProvider( k , False ) == 0:
944 except bb.build.EventException:
945 bb.error("Build of " + k + " failed")
950 if self.configuration.abort:
953 bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.event_data, failures))
955 sys.exit( self.stats.show() )
957 except KeyboardInterrupt:
958 print "\nNOTE: KeyboardInterrupt - Build not completed."
961 def get_bbfiles( self, path = os.getcwd() ):
962 """Get list of default .bb files by reading out the current directory"""
963 contents = os.listdir(path)
966 (root, ext) = os.path.splitext(f)
968 bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
971 def find_bbfiles( self, path ):
972 """Find all the .bb files in a directory (uses find)"""
973 findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
975 finddata = os.popen(findcmd)
978 return finddata.readlines()
980 def collect_bbfiles( self, progressCallback ):
981 """Collect all available .bb build files"""
982 self.cb = progressCallback
983 parsed, cached, skipped, masked = 0, 0, 0, 0
984 self.bb_cache = bb.cache.init(self)
986 files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
987 data.setVar("BBFILES", " ".join(files), self.configuration.data)
990 files = self.get_bbfiles()
993 bb.error("no files to build.")
998 dirfiles = self.find_bbfiles(f)
1000 newfiles += dirfiles
1002 newfiles += glob.glob(f) or [ f ]
1004 bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1) or ""
1006 bbmask_compiled = re.compile(bbmask)
1007 except sre_constants.error:
1008 bb.fatal("BBMASK is not a valid regular expression.")
1010 for i in xrange( len( newfiles ) ):
1012 if bbmask and bbmask_compiled.search(f):
1013 bb.debug(1, "bbmake: skipping %s" % f)
1016 debug(1, "bbmake: parsing %s" % f)
1018 # read a file's metadata
1020 fromCache, skip = self.bb_cache.loadData(f, self)
1023 #bb.note("Skipping %s" % f)
1024 self.bb_cache.skip(f)
1026 elif fromCache: cached += 1
1030 # allow metadata files to add items to BBFILES
1031 #data.update_data(self.pkgdata[f])
1032 addbbfiles = self.bb_cache.getVar('BBFILES', f, False) or None
1034 for aof in addbbfiles.split():
1035 if not files.count(aof):
1036 if not os.path.isabs(aof):
1037 aof = os.path.join(os.path.dirname(f),aof)
1040 # now inform the caller
1041 if self.cb is not None:
1042 self.cb( i + 1, len( newfiles ), f, self.bb_cache, fromCache )
1045 self.bb_cache.remove(f)
1046 bb.error("opening %s: %s" % (f, e))
1048 except KeyboardInterrupt:
1049 self.bb_cache.sync()
1051 except Exception, e:
1052 self.bb_cache.remove(f)
1053 bb.error("%s while parsing %s" % (e, f))
1055 self.bb_cache.remove(f)
1058 if self.cb is not None:
1059 print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ),
1061 self.bb_cache.sync()
1063 #============================================================================#
1065 #============================================================================#
1068 parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
1069 usage = """%prog [options] [package ...]
1071 Executes the specified task (default is 'build') for a given set of BitBake files.
1072 It expects that BBFILES is defined, which is a space seperated list of files to
1073 be executed. BBFILES does support wildcards.
1074 Default BBFILES are the .bb files in the current directory.""" )
1076 parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
1077 action = "store", dest = "buildfile", default = None )
1079 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.",
1080 action = "store_false", dest = "abort", default = True )
1082 parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
1083 action = "store_true", dest = "force", default = False )
1085 parser.add_option( "-i", "--interactive", help = "drop into the interactive mode.",
1086 action = "store_true", dest = "interactive", default = False )
1088 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)",
1089 action = "store", dest = "cmd", default = "build" )
1091 parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
1092 action = "append", dest = "file", default = [] )
1094 parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
1095 action = "store_true", dest = "verbose", default = False )
1097 parser.add_option( "-D", "--debug", help = "Increase the debug level",
1098 action = "count", dest="debug", default = 0)
1100 parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
1101 action = "store_true", dest = "dry_run", default = False )
1103 parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
1104 action = "store_true", dest = "parse_only", default = False )
1106 parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
1107 action = "store_true", dest = "disable_psyco", default = False )
1109 parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
1110 action = "store_true", dest = "show_versions", default = False )
1112 parser.add_option( "-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
1113 action = "store_true", dest = "show_environment", default = False )
1115 options, args = parser.parse_args( sys.argv )
1118 cooker.cook( BBConfiguration( options ), args[1:] )
1122 if __name__ == "__main__":
1123 print """WARNING, WARNING, WARNING
1124 This is a Bitbake from the Unstable/Development Branch.
1125 You might want to use the bitbake-1.4 stable branch (if you are not a BitBake developer or tester). I'm going to sleep 5 seconds now to make sure you see that."""