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 # Add the handlers we inherited by INHERITS
783 # FIXME: This assumes that we included at least one .inc file
784 for var in bb.data.keys(self.configuration.data):
785 if bb.data.getVarFlag(var, 'handler', self.configuration.data):
786 bb.event.register(var,bb.data.getVar(var,self.configuration.data))
789 bb.fatal( "Unable to open %s" % afile )
790 except bb.parse.ParseError, details:
791 bb.fatal( "Unable to parse %s (%s)" % (afile, details) )
793 def handleCollections( self, collections ):
794 """Handle collections"""
796 collection_list = collections.split()
797 for c in collection_list:
798 regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1)
800 bb.error("BBFILE_PATTERN_%s not defined" % c)
802 priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1)
804 bb.error("BBFILE_PRIORITY_%s not defined" % c)
807 cre = re.compile(regex)
809 bb.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
813 self.status.bbfile_config_priorities.append((cre, pri))
815 bb.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
818 def cook( self, configuration, args ):
819 self.configuration = configuration
821 if not self.configuration.cmd:
822 self.configuration.cmd = "build"
824 if self.configuration.debug:
825 bb.debug_level = self.configuration.debug
827 self.configuration.data = bb.data.init()
829 for f in self.configuration.file:
830 self.parseConfigurationFile( f )
832 self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
834 if self.configuration.show_environment:
835 self.showEnvironment()
838 # inject custom variables
839 if not bb.data.getVar("BUILDNAME", self.configuration.data):
840 bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
841 bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data)
843 buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
845 if self.configuration.interactive:
846 self.interactiveMode()
848 if self.configuration.buildfile is not None:
849 bf = os.path.abspath( self.configuration.buildfile )
851 bbfile_data = bb.parse.handle(bf, self.configuration.data)
853 bb.fatal("Unable to open %s" % bf)
855 item = bb.data.getVar('PN', bbfile_data, 1)
857 self.tryBuildPackage( bf, item, bbfile_data )
858 except bb.build.EventException:
859 bb.error( "Build of '%s' failed" % item )
861 sys.exit( self.stats.show() )
863 # initialise the parsing status now we know we will need deps
864 self.status = BBParsingStatus()
866 ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
867 self.status.ignored_dependencies = Set( ignore.split() )
869 self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
873 if not pkgs_to_build:
875 pkgs_to_build.extend(args)
876 if not pkgs_to_build:
877 bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
879 pkgs_to_build = bbpkgs.split()
880 if not pkgs_to_build and not self.configuration.show_versions \
881 and not self.configuration.interactive \
882 and not self.configuration.show_environment:
883 print "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help'"
884 print "for usage information."
887 # Import Psyco if available and not disabled
888 if not self.configuration.disable_psyco:
893 bb.note("Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
895 psyco.bind( self.collect_bbfiles )
897 bb.note("You have disabled Psyco. This decreases performance.")
900 bb.debug(1, "collecting .bb files")
901 self.collect_bbfiles( self.myProgressCallback )
902 bb.debug(1, "parsing complete")
905 if self.configuration.parse_only:
906 print "Requested parsing .bb files only. Exiting."
909 bb.data.update_data( self.configuration.data )
912 if self.configuration.show_versions:
915 if 'world' in pkgs_to_build:
916 self.buildWorldTargetList()
917 pkgs_to_build.remove('world')
918 for t in self.status.world_target:
919 pkgs_to_build.append(t)
921 bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.data))
924 for k in pkgs_to_build:
927 if self.buildProvider( k , False ) == 0:
930 except bb.build.EventException:
931 bb.error("Build of " + k + " failed")
936 if self.configuration.abort:
939 bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.data, failures))
941 sys.exit( self.stats.show() )
943 except KeyboardInterrupt:
944 print "\nNOTE: KeyboardInterrupt - Build not completed."
947 def get_bbfiles( self, path = os.getcwd() ):
948 """Get list of default .bb files by reading out the current directory"""
949 contents = os.listdir(path)
952 (root, ext) = os.path.splitext(f)
954 bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
957 def find_bbfiles( self, path ):
958 """Find all the .bb files in a directory (uses find)"""
959 findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
961 finddata = os.popen(findcmd)
964 return finddata.readlines()
966 def collect_bbfiles( self, progressCallback ):
967 """Collect all available .bb build files"""
968 self.cb = progressCallback
969 parsed, cached, skipped, masked = 0, 0, 0, 0
970 self.bb_cache = bb.cache.init(self)
972 files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
973 data.setVar("BBFILES", " ".join(files), self.configuration.data)
976 files = self.get_bbfiles()
979 bb.error("no files to build.")
984 dirfiles = self.find_bbfiles(f)
988 newfiles += glob.glob(f) or [ f ]
990 bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1) or ""
992 bbmask_compiled = re.compile(bbmask)
993 except sre_constants.error:
994 bb.fatal("BBMASK is not a valid regular expression.")
996 for i in xrange( len( newfiles ) ):
998 if bbmask and bbmask_compiled.search(f):
999 bb.debug(1, "bbmake: skipping %s" % f)
1002 debug(1, "bbmake: parsing %s" % f)
1004 # read a file's metadata
1006 fromCache, skip = self.bb_cache.loadData(f, self)
1009 #bb.note("Skipping %s" % f)
1010 self.bb_cache.skip(f)
1012 elif fromCache: cached += 1
1016 # allow metadata files to add items to BBFILES
1017 #data.update_data(self.pkgdata[f])
1018 addbbfiles = self.bb_cache.getVar('BBFILES', f, False) or None
1020 for aof in addbbfiles.split():
1021 if not files.count(aof):
1022 if not os.path.isabs(aof):
1023 aof = os.path.join(os.path.dirname(f),aof)
1026 # now inform the caller
1027 if self.cb is not None:
1028 self.cb( i + 1, len( newfiles ), f, self.bb_cache, fromCache )
1031 self.bb_cache.remove(f)
1032 bb.error("opening %s: %s" % (f, e))
1034 except KeyboardInterrupt:
1035 self.bb_cache.sync()
1037 except Exception, e:
1038 self.bb_cache.remove(f)
1039 bb.error("%s while parsing %s" % (e, f))
1041 self.bb_cache.remove(f)
1044 if self.cb is not None:
1045 print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ),
1047 self.bb_cache.sync()
1049 #============================================================================#
1051 #============================================================================#
1054 parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
1055 usage = """%prog [options] [package ...]
1057 Executes the specified task (default is 'build') for a given set of BitBake files.
1058 It expects that BBFILES is defined, which is a space seperated list of files to
1059 be executed. BBFILES does support wildcards.
1060 Default BBFILES are the .bb files in the current directory.""" )
1062 parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
1063 action = "store", dest = "buildfile", default = None )
1065 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.",
1066 action = "store_false", dest = "abort", default = True )
1068 parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
1069 action = "store_true", dest = "force", default = False )
1071 parser.add_option( "-i", "--interactive", help = "drop into the interactive mode.",
1072 action = "store_true", dest = "interactive", default = False )
1074 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)",
1075 action = "store", dest = "cmd", default = "build" )
1077 parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
1078 action = "append", dest = "file", default = [] )
1080 parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
1081 action = "store_true", dest = "verbose", default = False )
1083 parser.add_option( "-D", "--debug", help = "Increase the debug level",
1084 action = "count", dest="debug", default = 0)
1086 parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
1087 action = "store_true", dest = "dry_run", default = False )
1089 parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
1090 action = "store_true", dest = "parse_only", default = False )
1092 parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
1093 action = "store_true", dest = "disable_psyco", default = False )
1095 parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
1096 action = "store_true", dest = "show_versions", default = False )
1098 parser.add_option( "-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
1099 action = "store_true", dest = "show_environment", default = False )
1101 options, args = parser.parse_args( sys.argv )
1104 cooker.cook( BBConfiguration( options ), args[1:] )
1108 if __name__ == "__main__":