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.append(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'|/-\\' )
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 rprovides = (bb.data.getVar("RPROVIDES", bb_data, 1) or "").split()
81 depends = (bb.data.getVar("DEPENDS", bb_data, True) or "").split()
82 packages = (bb.data.getVar('PACKAGES', bb_data, True) or "").split()
83 packages_dynamic = (bb.data.getVar('PACKAGES_DYNAMIC', bb_data, True) 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.)
114 for package in packages:
115 if not package in self.packages:
116 self.packages[package] = []
117 self.packages[package].append(file_name)
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 tmpdir = bb.data.getVar('TMPDIR', the_data, 1)
465 stamp = '%s/stamps/%s-%s-%s.do_populate_staging' % (tmpdir, pn, pv, pr)
466 if os.path.exists(stamp):
467 (newvers, fn) = preferred_versions[pn]
468 if not fn in eligible:
469 # package was made ineligible by already-failed check
471 oldver = "%s-%s" % (pv, pr)
472 newver = '-'.join(newvers)
473 if (newver != oldver):
474 extra_chat = "; upgrading from %s to %s" % (oldver, newver)
477 if self.configuration.verbose:
478 bb.note("selecting already-staged %s to satisfy %s%s" % (pn, item, extra_chat))
480 eligible = [fn] + eligible
486 def buildProvider( self, item , buildAllDeps , build_depends = [] ):
488 Build something to provide a named build requirement
489 (takes item names from DEPENDS namespace)
493 discriminated = False
495 if not item in self.status.providers:
496 bb.error("Nothing provides dependency %s" % item)
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)
508 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
510 self.preferred[item] = prefervar
512 if item in self.preferred:
514 pn = self.status.pkg_fn[p]
515 if self.preferred[item] == pn:
516 if self.configuration.verbose:
517 bb.note("selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
519 eligible = [p] + eligible
523 if len(eligible) > 1 and discriminated == False:
524 if item not in self.consider_msgs_cache:
527 providers_list.append(self.status.pkg_fn[fn])
528 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
529 bb.note("consider defining PREFERRED_PROVIDER_%s" % item)
530 self.consider_msgs_cache.append(item)
533 # run through the list until we find one that we can build
535 bb.debug(2, "selecting %s to satisfy %s" % (fn, item))
536 if self.tryBuild(fn, item, buildAllDeps, build_depends + [fn]):
539 bb.note("no buildable providers for %s" % item)
542 def buildRProvider( self, item , buildAllDeps ):
544 Build something to provide a named runtime requirement
545 (takes item names from RDEPENDS/PACKAGES namespace)
550 discriminated = False
555 all_p = self.getProvidersRun(item)
558 bb.error("Nothing provides runtime dependency %s" % (item))
562 if p in self.rbuild_cache:
563 bb.debug(2, "Already built %s providing runtime %s\n" % (p,item))
565 if p in self.build_cache:
566 bb.debug(2, "Already built %s but adding any further RDEPENDS for %s\n" % (p, item))
567 return self.addRunDeps(p, item , buildAllDeps)
569 eligible = self.filterProviders(all_p, item)
572 pn = self.status.pkg_fn[p]
573 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % pn, self.configuration.data, 1)
575 if self.configuration.verbose:
576 bb.note("selecting %s to satisfy runtime %s due to PREFERRED_PROVIDERS" % (pn, item))
578 eligible = [p] + eligible
582 if len(eligible) > 1 and discriminated == False:
583 if item not in self.consider_msgs_cache:
586 providers_list.append(self.status.pkg_fn[fn])
587 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
588 bb.note("consider defining a PREFERRED_PROVIDER to match runtime %s" % item)
589 self.consider_msgs_cache.append(item)
591 # run through the list until we find one that we can build
593 bb.debug(2, "selecting %s to satisfy runtime %s" % (fn, item))
594 if self.tryBuild(fn, item, buildAllDeps):
597 bb.error("No buildable providers for runtime %s" % item)
600 def getProvidersRun(self, rdepend):
602 Return any potential providers of runtime rdepend
606 if rdepend in self.status.rproviders:
607 rproviders += self.status.rproviders[rdepend]
609 if rdepend in self.status.packages:
610 rproviders += self.status.packages[rdepend]
615 # Only search dynamic packages if we can't find anything in other variables
616 for pattern in self.status.packages_dynamic:
617 regexp = re.compile(pattern)
618 if regexp.match(rdepend):
619 rproviders += self.status.packages_dynamic[pattern]
623 def addRunDeps(self , fn, item , buildAllDeps):
625 Add any runtime dependencies of runtime item provided by fn
626 as long as item has't previously been processed by this function.
629 if item in self.rbuild_cache:
636 self.rbuild_cache.append(item)
637 the_data = self.pkgdata[fn]
638 pn = self.status.pkg_fn[fn]
641 rdepends += bb.utils.explode_deps(bb.data.getVar('RDEPENDS', the_data, True) or "")
642 rdepends += bb.utils.explode_deps(bb.data.getVar('RRECOMMENDS', the_data, True) or "")
644 packages = (bb.data.getVar('PACKAGES', the_data, 1).split() or "")
645 for package in packages:
647 rdepends += bb.utils.explode_deps(bb.data.getVar("RDEPENDS_%s" % package, the_data, True) or "")
648 rdepends += bb.utils.explode_deps(bb.data.getVar("RRECOMMENDS_%s" % package, the_data, True) or "")
650 bb.debug(2, "Additional runtime dependencies for %s are: %s" % (item, " ".join(rdepends)))
652 for rdepend in rdepends:
653 if not self.buildRProvider(rdepend, buildAllDeps):
657 def buildDepgraph( self ):
658 all_depends = self.status.all_depends
659 pn_provides = self.status.pn_provides
661 def calc_bbfile_priority(filename):
662 for (regex, pri) in self.status.bbfile_config_priorities:
663 if regex.match(filename):
667 # Handle PREFERRED_PROVIDERS
668 for p in (bb.data.getVar('PREFERRED_PROVIDERS', self.configuration.data, 1) or "").split():
669 (providee, provider) = p.split(':')
670 if providee in self.preferred and self.preferred[providee] != provider:
671 bb.error("conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.preferred[providee]))
672 self.preferred[providee] = provider
674 # Calculate priorities for each file
675 for p in self.pkgdata.keys():
676 self.status.bbfile_priority[p] = calc_bbfile_priority(p)
678 # Build package list for "bitbake world"
679 bb.debug(1, "collating packages for \"world\"")
680 for f in self.status.possible_world:
682 pn = self.status.pkg_fn[f]
684 for p in pn_provides[pn]:
685 if p.startswith('virtual/'):
686 bb.debug(2, "skipping %s due to %s provider starting with virtual/" % (f, p))
689 for pf in self.status.providers[p]:
690 if self.status.pkg_fn[pf] != pn:
691 bb.debug(2, "skipping %s due to both us and %s providing %s" % (f, pf, p))
695 self.status.world_target.add(pn)
697 # drop reference count now
698 self.status.possible_world = None
699 self.status.all_depends = None
701 def myProgressCallback( self, x, y, f, file_data, from_cache ):
702 # feed the status with new input
703 self.status.handle_bb_data(f, file_data, from_cache)
707 if os.isatty(sys.stdout.fileno()):
708 sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
712 sys.stdout.write("Parsing .bb files, please wait...")
715 sys.stdout.write("done.")
718 def interactiveMode( self ):
719 """Drop off into a shell"""
722 except ImportError, details:
723 bb.fatal("Sorry, shell not available (%s)" % details )
725 bb.data.update_data( self.configuration.data )
729 def parseConfigurationFile( self, afile ):
731 self.configuration.data = bb.parse.handle( afile, self.configuration.data )
733 bb.fatal( "Unable to open %s" % afile )
734 except bb.parse.ParseError, details:
735 bb.fatal( "Unable to parse %s (%s)" % (afile, details) )
737 def handleCollections( self, collections ):
738 """Handle collections"""
740 collection_list = collections.split()
741 for c in collection_list:
742 regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1)
744 bb.error("BBFILE_PATTERN_%s not defined" % c)
746 priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1)
748 bb.error("BBFILE_PRIORITY_%s not defined" % c)
751 cre = re.compile(regex)
753 bb.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
757 self.status.bbfile_config_priorities.append((cre, pri))
759 bb.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
762 def cook( self, configuration, args ):
763 self.configuration = configuration
765 if not self.configuration.cmd:
766 self.configuration.cmd = "build"
768 if self.configuration.debug:
769 bb.debug_level = self.configuration.debug
771 self.configuration.data = bb.data.init()
773 for f in self.configuration.file:
774 self.parseConfigurationFile( f )
776 self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
778 if self.configuration.show_environment:
779 self.showEnvironment()
782 # inject custom variables
783 if not bb.data.getVar("BUILDNAME", self.configuration.data):
784 bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
785 bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data)
787 buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
789 if self.configuration.interactive:
790 self.interactiveMode()
792 if self.configuration.buildfile is not None:
793 bf = os.path.abspath( self.configuration.buildfile )
795 bbfile_data = bb.parse.handle(bf, self.configuration.data)
797 bb.fatal("Unable to open %s" % bf)
799 item = bb.data.getVar('PN', bbfile_data, 1)
801 self.tryBuildPackage( bf, item, bbfile_data )
802 except bb.build.EventException:
803 bb.error( "Build of '%s' failed" % item )
805 sys.exit( self.stats.show() )
807 # initialise the parsing status now we know we will need deps
808 self.status = BBParsingStatus()
810 ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
811 self.status.ignored_dependencies = Set( ignore.split() )
813 self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
817 if not pkgs_to_build:
819 pkgs_to_build.extend(args)
820 if not pkgs_to_build:
821 bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
823 pkgs_to_build = bbpkgs.split()
824 if not pkgs_to_build and not self.configuration.show_versions \
825 and not self.configuration.interactive \
826 and not self.configuration.show_environment:
827 print "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help'"
828 print "for usage information."
831 # Import Psyco if available and not disabled
832 if not self.configuration.disable_psyco:
837 bb.note("Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
839 psyco.bind( self.collect_bbfiles )
841 bb.note("You have disabled Psyco. This decreases performance.")
844 bb.debug(1, "collecting .bb files")
845 self.collect_bbfiles( self.myProgressCallback )
846 bb.debug(1, "parsing complete")
849 if self.configuration.parse_only:
850 print "Requested parsing .bb files only. Exiting."
853 bb.data.update_data( self.configuration.data )
856 if self.configuration.show_versions:
859 if 'world' in pkgs_to_build:
860 pkgs_to_build.remove('world')
861 for t in self.status.world_target:
862 pkgs_to_build.append(t)
864 bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.data))
866 for k in pkgs_to_build:
869 if self.buildProvider( k , False ) == 0:
872 except bb.build.EventException:
873 bb.error("Build of " + k + " failed")
877 if self.configuration.abort:
880 bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.data))
882 sys.exit( self.stats.show() )
884 except KeyboardInterrupt:
885 print "\nNOTE: KeyboardInterrupt - Build not completed."
888 def get_bbfiles( self, path = os.getcwd() ):
889 """Get list of default .bb files by reading out the current directory"""
890 contents = os.listdir(path)
893 (root, ext) = os.path.splitext(f)
895 bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
898 def find_bbfiles( self, path ):
899 """Find all the .bb files in a directory (uses find)"""
900 findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
902 finddata = os.popen(findcmd)
905 return finddata.readlines()
907 def deps_clean(self, d):
908 depstr = data.getVar('__depends', d)
910 deps = depstr.split(" ")
912 (f,old_mtime_s) = dep.split("@")
913 old_mtime = int(old_mtime_s)
914 new_mtime = parse.cached_mtime(f)
915 if (new_mtime > old_mtime):
919 def load_bbfile( self, bbfile ):
920 """Load and parse one .bb build file"""
922 if not self.cache in [None, '']:
924 cache_mtime = data.init_db_mtime(self.cache, bbfile)
925 file_mtime = parse.cached_mtime(bbfile)
927 if file_mtime > cache_mtime:
928 #print " : '%s' dirty. reparsing..." % bbfile
931 #print " : '%s' clean. loading from cache..." % bbfile
932 cache_data = data.init_db( self.cache, bbfile, False )
933 if self.deps_clean(cache_data):
934 return cache_data, True
936 topdir = data.getVar('TOPDIR', self.configuration.data)
938 topdir = os.path.abspath(os.getcwd())
940 data.setVar('TOPDIR', topdir, self.configuration)
941 bbfile = os.path.abspath(bbfile)
942 bbfile_loc = os.path.abspath(os.path.dirname(bbfile))
943 # expand tmpdir to include this topdir
944 data.setVar('TMPDIR', data.getVar('TMPDIR', self.configuration.data, 1) or "", self.configuration.data)
945 # set topdir to location of .bb file
947 #data.setVar('TOPDIR', topdir, cfg)
949 oldpath = os.path.abspath(os.getcwd())
951 bb = data.init_db(self.cache,bbfile, True, self.configuration.data)
953 parse.handle(bbfile, bb) # read .bb data
954 if not self.cache in [None, '']:
955 bb.commit(parse.cached_mtime(bbfile)) # write cache
961 def collect_bbfiles( self, progressCallback ):
962 """Collect all available .bb build files"""
963 self.cb = progressCallback
964 parsed, cached, skipped, masked = 0, 0, 0, 0
965 self.cache = bb.data.getVar( "CACHE", self.configuration.data, 1 )
966 self.pkgdata = data.pkgdata( not self.cache in [None, ''], self.cache, self.configuration.data )
968 if not self.cache in [None, '']:
969 if self.cb is not None:
970 print "NOTE: Using cache in '%s'" % self.cache
972 os.stat( self.cache )
974 bb.mkdirhier( self.cache )
976 if self.cb is not None:
977 print "NOTE: Not using a cache. Set CACHE = <directory> to enable."
978 files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
979 data.setVar("BBFILES", " ".join(files), self.configuration.data)
982 files = self.get_bbfiles()
985 bb.error("no files to build.")
990 dirfiles = self.find_bbfiles(f)
994 newfiles += glob.glob(f) or [ f ]
996 bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1) or ""
998 bbmask_compiled = re.compile(bbmask)
999 except sre_constants.error:
1000 bb.fatal("BBMASK is not a valid regular expression.")
1002 for i in xrange( len( newfiles ) ):
1004 if bbmask and bbmask_compiled.search(f):
1005 bb.debug(1, "bbmake: skipping %s" % f)
1008 debug(1, "bbmake: parsing %s" % f)
1010 # read a file's metadata
1012 bb_data, fromCache = self.load_bbfile(f)
1013 if fromCache: cached += 1
1016 if bb_data is not None:
1017 # allow metadata files to add items to BBFILES
1018 #data.update_data(self.pkgdata[f])
1019 addbbfiles = data.getVar('BBFILES', bb_data) or None
1021 for aof in addbbfiles.split():
1022 if not files.count(aof):
1023 if not os.path.isabs(aof):
1024 aof = os.path.join(os.path.dirname(f),aof)
1026 for var in bb_data.keys():
1027 if data.getVarFlag(var, "handler", bb_data) and data.getVar(var, bb_data):
1028 event.register(data.getVar(var, bb_data))
1029 self.pkgdata[f] = bb_data
1031 # now inform the caller
1032 if self.cb is not None:
1033 self.cb( i + 1, len( newfiles ), f, bb_data, fromCache )
1036 bb.error("opening %s: %s" % (f, e))
1038 except bb.parse.SkipPackage:
1041 except KeyboardInterrupt:
1043 except Exception, e:
1044 bb.error("%s while parsing %s" % (e, f))
1046 if self.cb is not None:
1047 print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ),
1049 #============================================================================#
1051 #============================================================================#
1053 if __name__ == "__main__":
1055 parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
1056 usage = """%prog [options] [package ...]
1058 Executes the specified task (default is 'build') for a given set of BitBake files.
1059 It expects that BBFILES is defined, which is a space seperated list of files to
1060 be executed. BBFILES does support wildcards.
1061 Default BBFILES are the .bb files in the current directory.""" )
1063 parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
1064 action = "store", dest = "buildfile", default = None )
1066 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.",
1067 action = "store_false", dest = "abort", default = True )
1069 parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
1070 action = "store_true", dest = "force", default = False )
1072 parser.add_option( "-i", "--interactive", help = "drop into the interactive mode.",
1073 action = "store_true", dest = "interactive", default = False )
1075 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)",
1076 action = "store", dest = "cmd", default = "build" )
1078 parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
1079 action = "append", dest = "file", default = [] )
1081 parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
1082 action = "store_true", dest = "verbose", default = False )
1084 parser.add_option( "-D", "--debug", help = "Increase the debug level",
1085 action = "count", dest="debug", default = 0)
1087 parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
1088 action = "store_true", dest = "dry_run", default = False )
1090 parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
1091 action = "store_true", dest = "parse_only", default = False )
1093 parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
1094 action = "store_true", dest = "disable_psyco", default = False )
1096 parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
1097 action = "store_true", dest = "show_versions", default = False )
1099 parser.add_option( "-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
1100 action = "store_true", dest = "show_environment", default = False )
1102 options, args = parser.parse_args( sys.argv )
1105 cooker.cook( BBConfiguration( options ), args[1:] )