2 # ex:ts=4:sw=4:sts=4:et
3 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
5 # Copyright (C) 2003, 2004 Chris Larson
6 # Copyright (C) 2003, 2004 Phil Blundell
7 # Copyright (C) 2003 - 2005 Michael 'Mickey' Lauer
8 # Copyright (C) 2005 Holger Hans Peter Freyther
9 # Copyright (C) 2005 ROAD GmbH
11 # This program is free software; you can redistribute it and/or modify it under
12 # the terms of the GNU General Public License as published by the Free Software
13 # Foundation; either version 2 of the License, or (at your option) any later
16 # This program is distributed in the hope that it will be useful, but WITHOUT
17 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License along with
21 # this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22 # Place, Suite 330, Boston, MA 02111-1307 USA.
24 import sys, os, getopt, glob, copy, os.path, re, time
25 sys.path.insert(0,os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
27 from bb import utils, data, parse, debug, event, fatal
29 import itertools, optparse
31 parsespin = itertools.cycle( r'|/-\\' )
34 __version__ = "1.3.3.2"
36 #============================================================================#
38 #============================================================================#
39 class BBParsingStatus:
41 The initial idea for this status class is to use the data when it is
42 already loaded instead of loading it from various place over and over
47 self.cache_dirty = False
51 self.packages_dynamic = {}
52 self.bbfile_priority = {}
53 self.bbfile_config_priorities = []
54 self.ignored_dependencies = None
55 self.possible_world = []
56 self.world_target = Set()
62 self.all_depends = Set()
64 def handle_bb_data(self, file_name, bb_data, cached):
66 We will fill the dictionaries with the stuff we
67 need for building the tree more fast
73 self.cache_dirty = True
75 pn = bb.data.getVar('PN', bb_data, True)
76 pv = bb.data.getVar('PV', bb_data, True)
77 pr = bb.data.getVar('PR', bb_data, True)
78 dp = int(bb.data.getVar('DEFAULT_PREFERENCE', bb_data, True) or "0")
79 provides = Set([pn] + (bb.data.getVar("PROVIDES", bb_data, 1) or "").split())
80 depends = (bb.data.getVar("DEPENDS", bb_data, True) or "").split()
81 packages = (bb.data.getVar('PACKAGES', bb_data, True) or "").split()
82 packages_dynamic = (bb.data.getVar('PACKAGES_DYNAMIC', bb_data, True) or "").split()
83 rprovides = (bb.data.getVar("RPROVIDES", bb_data, 1) or "").split()
86 # build PackageName to FileName lookup table
87 if pn not in self.pkg_pn:
89 self.pkg_pn[pn].append(file_name)
91 # build FileName to PackageName lookup table
92 self.pkg_fn[file_name] = pn
93 self.pkg_pvpr[file_name] = (pv,pr)
94 self.pkg_dp[file_name] = dp
96 # Build forward and reverse provider hashes
97 # Forward: virtual -> [filenames]
98 # Reverse: PN -> [virtuals]
99 if pn not in self.pn_provides:
100 self.pn_provides[pn] = Set()
101 self.pn_provides[pn] |= provides
103 for provide in provides:
104 if provide not in self.providers:
105 self.providers[provide] = []
106 self.providers[provide].append(file_name)
109 self.all_depends.add(dep)
111 # Build reverse hash for PACKAGES, so runtime dependencies
112 # can be be resolved (RDEPENDS, RRECOMMENDS etc.)
113 for package in packages:
114 if not package in self.packages:
115 self.packages[package] = []
116 self.packages[package].append(file_name)
117 rprovides += (bb.data.getVar("RPROVIDES_%s" % package, bb_data, 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 # Collect files we may need for possible world-dep
131 if not bb.data.getVar('BROKEN', bb_data, True) and not bb.data.getVar('EXCLUDE_FROM_WORLD', bb_data, True):
132 self.possible_world.append(file_name)
135 #============================================================================#
137 #============================================================================#
140 Manage build statistics for one run
149 print "Build statistics:"
150 print " Attempted builds: %d" % self.attempt
152 print " Failed builds: %d" % self.fail
154 print " Dependencies not satisfied: %d" % self.deps
155 if self.fail or self.deps: return 1
159 #============================================================================#
161 #============================================================================#
162 class BBConfiguration( object ):
164 Manages build options and configurations for one run
166 def __init__( self, options ):
167 for key, val in options.__dict__.items():
168 setattr( self, key, val )
169 self.data = data.init()
171 #============================================================================#
173 #============================================================================#
176 Manages one bitbake build run
179 ParsingStatus = BBParsingStatus # make it visible from the shell
180 Statistics = BBStatistics # make it visible from the shell
182 def __init__( self ):
183 self.build_cache_fail = []
184 self.build_cache = []
185 self.rbuild_cache = []
186 self.building_list = []
188 self.consider_msgs_cache = []
190 self.stats = BBStatistics()
196 def tryBuildPackage( self, fn, item, the_data ):
197 """Build one package"""
198 bb.event.fire(bb.event.PkgStarted(item, the_data))
200 self.stats.attempt += 1
201 if self.configuration.force:
202 bb.data.setVarFlag('do_%s' % self.configuration.cmd, 'force', 1, the_data)
203 if not self.configuration.dry_run:
204 bb.build.exec_task('do_%s' % self.configuration.cmd, the_data)
205 bb.event.fire(bb.event.PkgSucceeded(item, the_data))
206 self.build_cache.append(fn)
208 except bb.build.FuncFailed:
210 bb.error("task stack execution failed")
211 bb.event.fire(bb.event.PkgFailed(item, the_data))
212 self.build_cache_fail.append(fn)
214 except bb.build.EventException, e:
217 bb.error("%s event exception, aborting" % bb.event.getName(event))
218 bb.event.fire(bb.event.PkgFailed(item, the_data))
219 self.build_cache_fail.append(fn)
222 def tryBuild( self, fn, virtual , buildAllDeps , build_depends = []):
224 Build a provider and its dependencies.
225 build_depends is a list of previous build dependencies (not runtime)
226 If build_depends is empty, we're dealing with a runtime depends
229 the_data = self.pkgdata[fn]
232 buildAllDeps = bb.data.getVar('BUILD_ALL_DEPS', the_data, True) or False
234 # Error on build time dependency loops
235 if build_depends and build_depends.count(fn) > 1:
236 bb.error("%s depends on itself (eventually)" % fn)
237 bb.error("upwards chain is: %s" % (" -> ".join(self.build_path)))
240 # See if this is a runtime dependency we've already built
241 # Or a build dependency being handled in a different build chain
242 if fn in self.building_list:
243 return self.addRunDeps(fn, virtual , buildAllDeps)
245 item = self.status.pkg_fn[fn]
247 self.building_list.append(fn)
249 pathstr = "%s (%s)" % (item, virtual)
250 self.build_path.append(pathstr)
252 depends_list = (bb.data.getVar('DEPENDS', the_data, True) or "").split()
254 if self.configuration.verbose:
255 bb.note("current path: %s" % (" -> ".join(self.build_path)))
256 bb.note("dependencies for %s are: %s" % (item, " ".join(depends_list)))
261 depcmd = self.configuration.cmd
262 bbdepcmd = bb.data.getVarFlag('do_%s' % self.configuration.cmd, 'bbdepcmd', the_data)
263 if bbdepcmd is not None:
270 oldcmd = self.configuration.cmd
271 self.configuration.cmd = depcmd
273 for dependency in depends_list:
274 if dependency in self.status.ignored_dependencies:
278 if self.buildProvider( dependency , buildAllDeps , build_depends ) == 0:
279 bb.error("dependency %s (for %s) not satisfied" % (dependency,item))
281 if self.configuration.abort:
285 self.configuration.cmd = oldcmd
291 if not self.addRunDeps(fn, virtual , buildAllDeps):
294 if bb.build.stamp_is_current('do_%s' % self.configuration.cmd, the_data):
295 self.build_cache.append(fn)
298 return self.tryBuildPackage( fn, item, the_data )
301 self.building_list.remove(fn)
302 self.build_path.remove(pathstr)
304 def findBestProvider( self, pn, pkg_pn = None):
306 If there is a PREFERRED_VERSION, find the highest-priority bbfile
307 providing that version. If not, find the latest version provided by
308 an bbfile in the highest-priority set.
311 pkg_pn = self.status.pkg_pn
316 priority = self.status.bbfile_priority[f]
317 if priority not in priorities:
318 priorities[priority] = []
319 priorities[priority].append(f)
320 p_list = priorities.keys()
321 p_list.sort(lambda a, b: a - b)
324 tmp_pn = [priorities[p]] + tmp_pn
326 preferred_file = None
328 localdata = data.createCopy(self.configuration.data)
329 bb.data.setVar('OVERRIDES', "%s:%s" % (pn, data.getVar('OVERRIDES', localdata)), localdata)
330 bb.data.update_data(localdata)
332 preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, localdata, True)
334 m = re.match('(.*)_(.*)', preferred_v)
336 preferred_v = m.group(1)
337 preferred_r = m.group(2)
341 for file_set in tmp_pn:
343 pv,pr = self.status.pkg_pvpr[f]
344 if preferred_v == pv and (preferred_r == pr or preferred_r == None):
346 preferred_ver = (pv, pr)
351 pv_str = '%s-%s' % (preferred_v, preferred_r)
354 if preferred_file is None:
355 bb.note("preferred version %s of %s not available" % (pv_str, pn))
357 bb.debug(1, "selecting %s as PREFERRED_VERSION %s of package %s" % (preferred_file, pv_str, pn))
361 # get highest priority file set
366 for file_name in files:
367 pv,pr = self.status.pkg_pvpr[file_name]
368 dp = self.status.pkg_dp[file_name]
370 if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pv, pr)) < 0)) or (dp > latest_p):
374 if preferred_file is None:
375 preferred_file = latest_f
376 preferred_ver = latest
378 return (latest,latest_f,preferred_ver, preferred_file)
380 def showVersions( self ):
381 pkg_pn = self.status.pkg_pn
382 preferred_versions = {}
386 for pn in pkg_pn.keys():
387 (last_ver,last_file,pref_ver,pref_file) = self.findBestProvider(pn)
388 preferred_versions[pn] = (pref_ver, pref_file)
389 latest_versions[pn] = (last_ver, last_file)
391 pkg_list = pkg_pn.keys()
395 pref = preferred_versions[p]
396 latest = latest_versions[p]
399 prefstr = pref[0][0] + "-" + pref[0][1]
403 print "%-30s %20s %20s" % (p, latest[0][0] + "-" + latest[0][1],
406 def showEnvironment( self ):
407 """Show the outer or per-package environment"""
408 if self.configuration.buildfile:
410 self.configuration.data, fromCache = self.load_bbfile( self.configuration.buildfile )
412 fatal("Unable to read %s: %s" % ( self.configuration.buildfile, e ))
415 # emit variables and shell functions
417 data.update_data( self.configuration.data )
418 data.emit_env(sys.__stdout__, self.configuration.data, True)
421 # emit the metadata which isnt valid shell
422 for e in self.configuration.data.keys():
423 if data.getVarFlag( e, 'python', self.configuration.data ):
424 sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, self.configuration.data, 1)))
426 def filterProviders(self, providers, item):
428 Take a list of providers and filter/reorder according to the
429 environment variables and previous build results
432 preferred_versions = {}
434 # Collate providers by PN
437 pn = self.status.pkg_fn[p]
442 bb.debug(1, "providers for %s are: %s" % (item, pkg_pn.keys()))
444 for pn in pkg_pn.keys():
445 preferred_versions[pn] = self.findBestProvider(pn, pkg_pn)[2:4]
446 eligible.append(preferred_versions[pn][1])
449 if p in self.build_cache_fail:
450 bb.debug(1, "rejecting already-failed %s" % p)
453 if len(eligible) == 0:
454 bb.error("no eligible providers for %s" % item)
457 # look to see if one of them is already staged, or marked as preferred.
458 # if so, bump it to the head of the queue
460 the_data = self.pkgdata[p]
461 pn = bb.data.getVar('PN', the_data, 1)
462 pv = bb.data.getVar('PV', the_data, 1)
463 pr = bb.data.getVar('PR', the_data, 1)
464 stamp = '%s.do_populate_staging' % bb.data.getVar('STAMP', the_data, 1)
465 if os.path.exists(stamp):
466 (newvers, fn) = preferred_versions[pn]
467 if not fn in eligible:
468 # package was made ineligible by already-failed check
470 oldver = "%s-%s" % (pv, pr)
471 newver = '-'.join(newvers)
472 if (newver != oldver):
473 extra_chat = "; upgrading from %s to %s" % (oldver, newver)
476 if self.configuration.verbose:
477 bb.note("selecting already-staged %s to satisfy %s%s" % (pn, item, extra_chat))
479 eligible = [fn] + eligible
485 def buildProvider( self, item , buildAllDeps , build_depends = [] ):
487 Build something to provide a named build requirement
488 (takes item names from DEPENDS namespace)
492 discriminated = False
494 if not item in self.status.providers:
495 bb.error("Nothing provides dependency %s" % item)
496 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
499 all_p = self.status.providers[item]
502 if p in self.build_cache:
503 bb.debug(1, "already built %s in this run\n" % p)
506 eligible = self.filterProviders(all_p, item)
511 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
513 self.preferred[item] = prefervar
515 if item in self.preferred:
517 pn = self.status.pkg_fn[p]
518 if self.preferred[item] == pn:
519 if self.configuration.verbose:
520 bb.note("selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
522 eligible = [p] + eligible
526 if len(eligible) > 1 and discriminated == False:
527 if item not in self.consider_msgs_cache:
530 providers_list.append(self.status.pkg_fn[fn])
531 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
532 bb.note("consider defining PREFERRED_PROVIDER_%s" % item)
533 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data))
534 self.consider_msgs_cache.append(item)
537 # run through the list until we find one that we can build
539 bb.debug(2, "selecting %s to satisfy %s" % (fn, item))
540 if self.tryBuild(fn, item, buildAllDeps, build_depends + [fn]):
543 bb.note("no buildable providers for %s" % item)
544 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
547 def buildRProvider( self, item , buildAllDeps ):
549 Build something to provide a named runtime requirement
550 (takes item names from RDEPENDS/PACKAGES namespace)
555 discriminated = False
560 all_p = self.getProvidersRun(item)
563 bb.error("Nothing provides runtime dependency %s" % (item))
564 bb.event.fire(bb.event.NoProvider(item,self.configuration.data,runtime=True))
568 if p in self.rbuild_cache:
569 bb.debug(2, "Already built %s providing runtime %s\n" % (p,item))
571 if p in self.build_cache:
572 bb.debug(2, "Already built %s but adding any further RDEPENDS for %s\n" % (p, item))
573 return self.addRunDeps(p, item , buildAllDeps)
575 eligible = self.filterProviders(all_p, item)
581 pn = self.status.pkg_fn[p]
582 provides = self.status.pn_provides[pn]
583 for provide in provides:
584 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, self.configuration.data, 1)
586 if self.configuration.verbose:
587 bb.note("selecting %s to satisfy runtime %s due to PREFERRED_PROVIDERS" % (pn, item))
589 eligible = [p] + eligible
592 if len(eligible) > 1 and len(preferred) == 0:
593 if item not in self.consider_msgs_cache:
596 providers_list.append(self.status.pkg_fn[fn])
597 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
598 bb.note("consider defining a PREFERRED_PROVIDER to match runtime %s" % item)
599 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
600 self.consider_msgs_cache.append(item)
602 if len(preferred) > 1:
603 if item not in self.consider_msgs_cache:
606 providers_list.append(self.status.pkg_fn[fn])
607 bb.note("multiple preferred providers are available (%s);" % ", ".join(providers_list))
608 bb.note("consider defining only one PREFERRED_PROVIDER to match runtime %s" % item)
609 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
610 self.consider_msgs_cache.append(item)
612 # run through the list until we find one that we can build
614 bb.debug(2, "selecting %s to satisfy runtime %s" % (fn, item))
615 if self.tryBuild(fn, item, buildAllDeps):
618 bb.error("No buildable providers for runtime %s" % item)
619 bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
622 def getProvidersRun(self, rdepend):
624 Return any potential providers of runtime rdepend
628 if rdepend in self.status.rproviders:
629 rproviders += self.status.rproviders[rdepend]
631 if rdepend in self.status.packages:
632 rproviders += self.status.packages[rdepend]
637 # Only search dynamic packages if we can't find anything in other variables
638 for pattern in self.status.packages_dynamic:
639 regexp = re.compile(pattern)
640 if regexp.match(rdepend):
641 rproviders += self.status.packages_dynamic[pattern]
645 def addRunDeps(self , fn, item , buildAllDeps):
647 Add any runtime dependencies of runtime item provided by fn
648 as long as item has't previously been processed by this function.
651 if item in self.rbuild_cache:
658 self.rbuild_cache.append(item)
659 the_data = self.pkgdata[fn]
660 pn = self.status.pkg_fn[fn]
663 rdepends += bb.utils.explode_deps(bb.data.getVar('RDEPENDS', the_data, True) or "")
664 rdepends += bb.utils.explode_deps(bb.data.getVar('RRECOMMENDS', the_data, True) or "")
665 rdepends += bb.utils.explode_deps(bb.data.getVar("RDEPENDS_%s" % pn, the_data, True) or "")
666 rdepends += bb.utils.explode_deps(bb.data.getVar('RRECOMMENDS_%s' % pn, the_data, True) or "")
668 packages = (bb.data.getVar('PACKAGES', the_data, 1).split() or "")
669 for package in packages:
671 rdepends += bb.utils.explode_deps(bb.data.getVar("RDEPENDS_%s" % package, the_data, True) or "")
672 rdepends += bb.utils.explode_deps(bb.data.getVar("RRECOMMENDS_%s" % package, the_data, True) or "")
674 bb.debug(2, "Additional runtime dependencies for %s are: %s" % (item, " ".join(rdepends)))
676 for rdepend in rdepends:
677 if rdepend in self.status.ignored_dependencies:
679 if not self.buildRProvider(rdepend, buildAllDeps):
683 def buildDepgraph( self ):
684 all_depends = self.status.all_depends
685 pn_provides = self.status.pn_provides
687 def calc_bbfile_priority(filename):
688 for (regex, pri) in self.status.bbfile_config_priorities:
689 if regex.match(filename):
693 # Handle PREFERRED_PROVIDERS
694 for p in (bb.data.getVar('PREFERRED_PROVIDERS', self.configuration.data, 1) or "").split():
695 (providee, provider) = p.split(':')
696 if providee in self.preferred and self.preferred[providee] != provider:
697 bb.error("conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.preferred[providee]))
698 self.preferred[providee] = provider
700 # Calculate priorities for each file
701 for p in self.pkgdata.keys():
702 self.status.bbfile_priority[p] = calc_bbfile_priority(p)
704 def buildWorldTargetList(self):
706 Build package list for "bitbake world"
708 all_depends = self.status.all_depends
709 pn_provides = self.status.pn_provides
710 bb.debug(1, "collating packages for \"world\"")
711 for f in self.status.possible_world:
713 pn = self.status.pkg_fn[f]
715 for p in pn_provides[pn]:
716 if p.startswith('virtual/'):
717 bb.debug(2, "skipping %s due to %s provider starting with virtual/" % (f, p))
720 for pf in self.status.providers[p]:
721 if self.status.pkg_fn[pf] != pn:
722 bb.debug(2, "skipping %s due to both us and %s providing %s" % (f, pf, p))
726 self.status.world_target.add(pn)
728 # drop reference count now
729 self.status.possible_world = None
730 self.status.all_depends = None
732 def myProgressCallback( self, x, y, f, file_data, from_cache ):
733 # feed the status with new input
734 self.status.handle_bb_data(f, file_data, from_cache)
738 if os.isatty(sys.stdout.fileno()):
739 sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
743 sys.stdout.write("Parsing .bb files, please wait...")
746 sys.stdout.write("done.")
749 def interactiveMode( self ):
750 """Drop off into a shell"""
753 except ImportError, details:
754 bb.fatal("Sorry, shell not available (%s)" % details )
756 bb.data.update_data( self.configuration.data )
760 def parseConfigurationFile( self, afile ):
762 self.configuration.data = bb.parse.handle( afile, self.configuration.data )
764 bb.fatal( "Unable to open %s" % afile )
765 except bb.parse.ParseError, details:
766 bb.fatal( "Unable to parse %s (%s)" % (afile, details) )
768 def handleCollections( self, collections ):
769 """Handle collections"""
771 collection_list = collections.split()
772 for c in collection_list:
773 regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1)
775 bb.error("BBFILE_PATTERN_%s not defined" % c)
777 priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1)
779 bb.error("BBFILE_PRIORITY_%s not defined" % c)
782 cre = re.compile(regex)
784 bb.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
788 self.status.bbfile_config_priorities.append((cre, pri))
790 bb.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
793 def cook( self, configuration, args ):
794 self.configuration = configuration
796 if not self.configuration.cmd:
797 self.configuration.cmd = "build"
799 if self.configuration.debug:
800 bb.debug_level = self.configuration.debug
802 self.configuration.data = bb.data.init()
804 for f in self.configuration.file:
805 self.parseConfigurationFile( f )
807 self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
809 if self.configuration.show_environment:
810 self.showEnvironment()
813 # inject custom variables
814 if not bb.data.getVar("BUILDNAME", self.configuration.data):
815 bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
816 bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data)
818 buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
820 if self.configuration.interactive:
821 self.interactiveMode()
823 if self.configuration.buildfile is not None:
824 bf = os.path.abspath( self.configuration.buildfile )
826 bbfile_data = bb.parse.handle(bf, self.configuration.data)
828 bb.fatal("Unable to open %s" % bf)
830 item = bb.data.getVar('PN', bbfile_data, 1)
832 self.tryBuildPackage( bf, item, bbfile_data )
833 except bb.build.EventException:
834 bb.error( "Build of '%s' failed" % item )
836 sys.exit( self.stats.show() )
838 # initialise the parsing status now we know we will need deps
839 self.status = BBParsingStatus()
841 ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
842 self.status.ignored_dependencies = Set( ignore.split() )
844 self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
848 if not pkgs_to_build:
850 pkgs_to_build.extend(args)
851 if not pkgs_to_build:
852 bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
854 pkgs_to_build = bbpkgs.split()
855 if not pkgs_to_build and not self.configuration.show_versions \
856 and not self.configuration.interactive \
857 and not self.configuration.show_environment:
858 print "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help'"
859 print "for usage information."
862 # Import Psyco if available and not disabled
863 if not self.configuration.disable_psyco:
868 bb.note("Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
870 psyco.bind( self.collect_bbfiles )
872 bb.note("You have disabled Psyco. This decreases performance.")
875 bb.debug(1, "collecting .bb files")
876 self.collect_bbfiles( self.myProgressCallback )
877 bb.debug(1, "parsing complete")
880 if self.configuration.parse_only:
881 print "Requested parsing .bb files only. Exiting."
884 bb.data.update_data( self.configuration.data )
887 if self.configuration.show_versions:
890 if 'world' in pkgs_to_build:
891 self.buildWorldTargetList()
892 pkgs_to_build.remove('world')
893 for t in self.status.world_target:
894 pkgs_to_build.append(t)
896 bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.data))
899 for k in pkgs_to_build:
902 if self.buildProvider( k , False ) == 0:
905 except bb.build.EventException:
906 bb.error("Build of " + k + " failed")
911 if self.configuration.abort:
914 bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.data, failures))
916 sys.exit( self.stats.show() )
918 except KeyboardInterrupt:
919 print "\nNOTE: KeyboardInterrupt - Build not completed."
922 def get_bbfiles( self, path = os.getcwd() ):
923 """Get list of default .bb files by reading out the current directory"""
924 contents = os.listdir(path)
927 (root, ext) = os.path.splitext(f)
929 bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
932 def find_bbfiles( self, path ):
933 """Find all the .bb files in a directory (uses find)"""
934 findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
936 finddata = os.popen(findcmd)
939 return finddata.readlines()
941 def deps_clean(self, d):
942 depstr = data.getVar('__depends', d)
944 deps = depstr.split(" ")
946 (f,old_mtime_s) = dep.split("@")
947 old_mtime = int(old_mtime_s)
948 new_mtime = parse.cached_mtime(f)
949 if (new_mtime > old_mtime):
953 def load_bbfile( self, bbfile ):
954 """Load and parse one .bb build file"""
956 if not self.cache in [None, '']:
958 cache_mtime = data.init_db_mtime(self.cache, bbfile)
959 file_mtime = parse.cached_mtime(bbfile)
961 if file_mtime > cache_mtime:
962 #print " : '%s' dirty. reparsing..." % bbfile
965 #print " : '%s' clean. loading from cache..." % bbfile
966 cache_data = data.init_db( self.cache, bbfile, False )
967 if self.deps_clean(cache_data):
968 return cache_data, True
970 topdir = data.getVar('TOPDIR', self.configuration.data)
972 topdir = os.path.abspath(os.getcwd())
974 data.setVar('TOPDIR', topdir, self.configuration)
975 bbfile = os.path.abspath(bbfile)
976 bbfile_loc = os.path.abspath(os.path.dirname(bbfile))
977 # expand tmpdir to include this topdir
978 data.setVar('TMPDIR', data.getVar('TMPDIR', self.configuration.data, 1) or "", self.configuration.data)
979 # set topdir to location of .bb file
981 #data.setVar('TOPDIR', topdir, cfg)
983 oldpath = os.path.abspath(os.getcwd())
985 bb = data.init_db(self.cache,bbfile, True, self.configuration.data)
987 parse.handle(bbfile, bb) # read .bb data
988 if not self.cache in [None, '']:
989 bb.commit(parse.cached_mtime(bbfile)) # write cache
995 def collect_bbfiles( self, progressCallback ):
996 """Collect all available .bb build files"""
997 self.cb = progressCallback
998 parsed, cached, skipped, masked = 0, 0, 0, 0
999 self.cache = bb.data.getVar( "CACHE", self.configuration.data, 1 )
1000 self.pkgdata = data.pkgdata( not self.cache in [None, ''], self.cache, self.configuration.data )
1002 if not self.cache in [None, '']:
1003 if self.cb is not None:
1004 print "NOTE: Using cache in '%s'" % self.cache
1006 os.stat( self.cache )
1008 bb.mkdirhier( self.cache )
1010 if self.cb is not None:
1011 print "NOTE: Not using a cache. Set CACHE = <directory> to enable."
1012 files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
1013 data.setVar("BBFILES", " ".join(files), self.configuration.data)
1016 files = self.get_bbfiles()
1019 bb.error("no files to build.")
1023 if os.path.isdir(f):
1024 dirfiles = self.find_bbfiles(f)
1026 newfiles += dirfiles
1028 newfiles += glob.glob(f) or [ f ]
1030 bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1) or ""
1032 bbmask_compiled = re.compile(bbmask)
1033 except sre_constants.error:
1034 bb.fatal("BBMASK is not a valid regular expression.")
1036 for i in xrange( len( newfiles ) ):
1038 if bbmask and bbmask_compiled.search(f):
1039 bb.debug(1, "bbmake: skipping %s" % f)
1042 debug(1, "bbmake: parsing %s" % f)
1044 # read a file's metadata
1046 bb_data, fromCache = self.load_bbfile(f)
1047 if fromCache: cached += 1
1050 if bb_data is not None:
1051 # allow metadata files to add items to BBFILES
1052 #data.update_data(self.pkgdata[f])
1053 addbbfiles = data.getVar('BBFILES', bb_data) or None
1055 for aof in addbbfiles.split():
1056 if not files.count(aof):
1057 if not os.path.isabs(aof):
1058 aof = os.path.join(os.path.dirname(f),aof)
1060 self.pkgdata[f] = bb_data
1062 # now inform the caller
1063 if self.cb is not None:
1064 self.cb( i + 1, len( newfiles ), f, bb_data, fromCache )
1067 bb.error("opening %s: %s" % (f, e))
1069 except bb.parse.SkipPackage:
1072 except KeyboardInterrupt:
1074 except Exception, e:
1075 bb.error("%s while parsing %s" % (e, f))
1077 if self.cb is not None:
1078 print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ),
1080 #============================================================================#
1082 #============================================================================#
1085 parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
1086 usage = """%prog [options] [package ...]
1088 Executes the specified task (default is 'build') for a given set of BitBake files.
1089 It expects that BBFILES is defined, which is a space seperated list of files to
1090 be executed. BBFILES does support wildcards.
1091 Default BBFILES are the .bb files in the current directory.""" )
1093 parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
1094 action = "store", dest = "buildfile", default = None )
1096 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.",
1097 action = "store_false", dest = "abort", default = True )
1099 parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
1100 action = "store_true", dest = "force", default = False )
1102 parser.add_option( "-i", "--interactive", help = "drop into the interactive mode.",
1103 action = "store_true", dest = "interactive", default = False )
1105 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)",
1106 action = "store", dest = "cmd", default = "build" )
1108 parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
1109 action = "append", dest = "file", default = [] )
1111 parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
1112 action = "store_true", dest = "verbose", default = False )
1114 parser.add_option( "-D", "--debug", help = "Increase the debug level",
1115 action = "count", dest="debug", default = 0)
1117 parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
1118 action = "store_true", dest = "dry_run", default = False )
1120 parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
1121 action = "store_true", dest = "parse_only", default = False )
1123 parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
1124 action = "store_true", dest = "disable_psyco", default = False )
1126 parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
1127 action = "store_true", dest = "show_versions", default = False )
1129 parser.add_option( "-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
1130 action = "store_true", dest = "show_environment", default = False )
1132 options, args = parser.parse_args( sys.argv )
1135 cooker.cook( BBConfiguration( options ), args[1:] )
1139 if __name__ == "__main__":