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
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()
63 def handle_bb_data(self, file_name, bb_data, cached):
65 We will fill the dictionaries with the stuff we
66 need for building the tree more fast
72 self.cache_dirty = True
74 pn = bb.data.getVar('PN', bb_data, True)
75 pv = bb.data.getVar('PV', bb_data, True)
76 pr = bb.data.getVar('PR', bb_data, True)
77 dp = int(bb.data.getVar('DEFAULT_PREFERENCE', bb_data, True) or "0")
78 provides = Set([pn] + (bb.data.getVar("PROVIDES", bb_data, 1) or "").split())
79 depends = (bb.data.getVar("DEPENDS", bb_data, True) or "").split()
80 packages = (bb.data.getVar('PACKAGES', bb_data, True) or "").split()
81 packages_dynamic = (bb.data.getVar('PACKAGES_DYNAMIC', bb_data, True) or "").split()
84 # build PackageName to FileName lookup table
85 if pn not in self.pkg_pn:
87 self.pkg_pn[pn].append(file_name)
89 # build FileName to PackageName lookup table
90 self.pkg_fn[file_name] = pn
91 self.pkg_pvpr[file_name] = (pv,pr)
92 self.pkg_dp[file_name] = dp
94 # Build forward and reverse provider hashes
95 # Forward: virtual -> [filenames]
96 # Reverse: PN -> [virtuals]
97 if pn not in self.pn_provides:
98 self.pn_provides[pn] = Set()
99 self.pn_provides[pn] |= provides
101 for provide in provides:
102 if provide not in self.providers:
103 self.providers[provide] = []
104 self.providers[provide].append(file_name)
107 self.all_depends.add(dep)
109 # Build reverse hash for PACKAGES, so runtime dependencies
110 # can be be resolved (RDEPENDS, RRECOMMENDS etc.)
112 for package in packages:
113 if not package in self.packages:
114 self.packages[package] = []
115 self.packages[package].append(file_name)
117 for package in packages_dynamic:
118 if not package in self.packages_dynamic:
119 self.packages_dynamic[package] = []
120 self.packages_dynamic[package].append(file_name)
122 # Collect files we may need for possible world-dep
124 if not bb.data.getVar('BROKEN', bb_data, True) and not bb.data.getVar('EXCLUDE_FROM_WORLD', bb_data, True):
125 self.possible_world.append(file_name)
128 #============================================================================#
130 #============================================================================#
133 Manage build statistics for one run
142 print "Build statistics:"
143 print " Attempted builds: %d" % self.attempt
145 print " Failed builds: %d" % self.fail
147 print " Dependencies not satisfied: %d" % self.deps
148 if self.fail or self.deps: return 1
152 #============================================================================#
154 #============================================================================#
155 class BBConfiguration( object ):
157 Manages build options and configurations for one run
159 def __init__( self, options ):
160 for key, val in options.__dict__.items():
161 setattr( self, key, val )
162 self.data = data.init()
164 #============================================================================#
166 #============================================================================#
169 Manages one bitbake build run
172 ParsingStatus = BBParsingStatus # make it visible from the shell
173 Statistics = BBStatistics # make it visible from the shell
175 def __init__( self ):
176 self.build_cache_fail = []
177 self.build_cache = []
178 self.building_list = []
180 self.consider_msgs_cache = []
182 self.stats = BBStatistics()
188 def tryBuildPackage( self, fn, item, the_data ):
189 """Build one package"""
190 bb.event.fire(bb.event.PkgStarted(item, the_data))
192 self.stats.attempt += 1
193 if self.configuration.force:
194 bb.data.setVarFlag('do_%s' % self.configuration.cmd, 'force', 1, the_data)
195 if not self.configuration.dry_run:
196 bb.build.exec_task('do_%s' % self.configuration.cmd, the_data)
197 bb.event.fire(bb.event.PkgSucceeded(item, the_data))
198 self.build_cache.append(fn)
200 except bb.build.FuncFailed:
202 bb.error("task stack execution failed")
203 bb.event.fire(bb.event.PkgFailed(item, the_data))
204 self.build_cache_fail.append(fn)
206 except bb.build.EventException, e:
209 bb.error("%s event exception, aborting" % bb.event.getName(event))
210 bb.event.fire(bb.event.PkgFailed(item, the_data))
211 self.build_cache_fail.append(fn)
214 def tryBuild( self, fn, virtual , buildAllDeps ):
215 """Build a provider and its dependencies"""
216 if fn in self.building_list:
217 bb.error("%s depends on itself (eventually)" % fn)
218 bb.error("upwards chain is: %s" % (" -> ".join(self.build_path)))
221 the_data = self.pkgdata[fn]
222 item = self.status.pkg_fn[fn]
224 self.building_list.append(fn)
226 pathstr = "%s (%s)" % (item, virtual)
227 self.build_path.append(pathstr)
229 depends_list = (bb.data.getVar('DEPENDS', the_data, 1) or "")
231 buildAllDeps = bb.data.getVar('BUILD_ALL_DEPS', the_data, 1) or False
234 depends_list = "%s %s %s" % (depends_list, (bb.data.getVar('RDEPENDS', the_data, 1) or ""), (bb.data.getVar('RRECOMMENDS', the_data, 1) or ""))
236 if self.configuration.verbose:
237 bb.note("current path: %s" % (" -> ".join(self.build_path)))
238 bb.note("dependencies for %s are: %s" % (item, depends_list))
240 depends_list = depends_list.split()
245 depcmd = self.configuration.cmd
246 bbdepcmd = bb.data.getVarFlag('do_%s' % self.configuration.cmd, 'bbdepcmd', the_data)
247 if bbdepcmd is not None:
254 oldcmd = self.configuration.cmd
255 self.configuration.cmd = depcmd
257 for dependency in depends_list:
258 if dependency in self.status.ignored_dependencies:
262 if self.buildProvider( dependency , buildAllDeps ) == 0:
263 bb.error("dependency %s (for %s) not satisfied" % (dependency,item))
265 if self.configuration.abort:
269 self.configuration.cmd = oldcmd
275 if bb.build.stamp_is_current('do_%s' % self.configuration.cmd, the_data):
276 self.build_cache.append(fn)
279 return self.tryBuildPackage( fn, item, the_data )
282 self.building_list.remove(fn)
283 self.build_path.remove(pathstr)
285 def findBestProvider( self, pn, pkg_pn = None):
287 If there is a PREFERRED_VERSION, find the highest-priority bbfile
288 providing that version. If not, find the latest version provided by
289 an bbfile in the highest-priority set.
292 pkg_pn = self.status.pkg_pn
297 priority = self.status.bbfile_priority[f]
298 if priority not in priorities:
299 priorities[priority] = []
300 priorities[priority].append(f)
301 p_list = priorities.keys()
302 p_list.sort(lambda a, b: a - b)
305 tmp_pn = [priorities[p]] + tmp_pn
307 preferred_file = None
309 localdata = data.createCopy(self.configuration.data)
310 bb.data.setVar('OVERRIDES', "%s:%s" % (pn, data.getVar('OVERRIDES', localdata)), localdata)
311 bb.data.update_data(localdata)
313 preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, localdata, 1)
315 m = re.match('(.*)_(.*)', preferred_v)
317 preferred_v = m.group(1)
318 preferred_r = m.group(2)
322 for file_set in tmp_pn:
324 pv,pr = self.status.pkg_pvpr[f]
325 if preferred_v == pv and (preferred_r == pr or preferred_r == None):
327 preferred_ver = (pv, pr)
332 pv_str = '%s-%s' % (preferred_v, preferred_r)
335 if preferred_file is None:
336 bb.note("preferred version %s of %s not available" % (pv_str, pn))
338 bb.debug(1, "selecting %s as PREFERRED_VERSION %s of package %s" % (preferred_file, pv_str, pn))
342 # get highest priority file set
347 for file_name in files:
348 pv,pr = self.status.pkg_pvpr[file_name]
349 dp = self.status.pkg_dp[file_name]
351 if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pv, pr)) < 0)) or (dp > latest_p):
355 if preferred_file is None:
356 preferred_file = latest_f
357 preferred_ver = latest
359 return (latest,latest_f,preferred_ver, preferred_file)
361 def showVersions( self ):
362 pkg_pn = self.status.pkg_pn
363 preferred_versions = {}
367 for pn in pkg_pn.keys():
368 (last_ver,last_file,pref_ver,pref_file) = self.findBestProvider(pn)
369 preferred_versions[pn] = (pref_ver, pref_file)
370 latest_versions[pn] = (last_ver, last_file)
372 pkg_list = pkg_pn.keys()
376 pref = preferred_versions[p]
377 latest = latest_versions[p]
380 prefstr = pref[0][0] + "-" + pref[0][1]
384 print "%-30s %20s %20s" % (p, latest[0][0] + "-" + latest[0][1],
387 def showEnvironment( self ):
388 """Show the outer or per-package environment"""
389 if self.configuration.buildfile:
391 self.configuration.data, fromCache = self.load_bbfile( self.configuration.buildfile )
393 fatal("Unable to read %s: %s" % ( self.configuration.buildfile, e ))
396 # emit variables and shell functions
398 data.update_data( self.configuration.data )
399 data.emit_env(sys.__stdout__, self.configuration.data, True)
402 # emit the metadata which isnt valid shell
403 for e in self.configuration.data.keys():
404 if data.getVarFlag( e, 'python', self.configuration.data ):
405 sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, self.configuration.data, 1)))
407 def getProviders(self, item, buildAllDeps):
409 if item in self.status.providers:
410 return self.status.providers[item]
415 if item in self.status.packages:
416 return self.status.packages[item]
419 for pattern in self.status.packages_dynamic:
420 regexp = re.compile(pattern)
421 if regexp.match(item):
422 for fn in self.status.packages_dynamic[pattern]:
430 def buildProvider( self, item , buildAllDeps ):
433 discriminated = False
435 all_p = self.getProviders(item, buildAllDeps)
438 bb.error("Nothing provides %s" % item)
442 if p in self.build_cache:
443 bb.debug(1, "already built %s in this run\n" % p)
447 preferred_versions = {}
449 # Collate providers by PN
452 pn = self.status.pkg_fn[p]
457 bb.debug(1, "providers for %s are: %s" % (item, pkg_pn.keys()))
459 for pn in pkg_pn.keys():
460 preferred_versions[pn] = self.findBestProvider(pn, pkg_pn)[2:4]
461 eligible.append(preferred_versions[pn][1])
464 if p in self.build_cache_fail:
465 bb.debug(1, "rejecting already-failed %s" % p)
468 if len(eligible) == 0:
469 bb.error("no eligible providers for %s" % item)
472 # look to see if one of them is already staged, or marked as preferred.
473 # if so, bump it to the head of the queue
475 the_data = self.pkgdata[p]
476 pn = bb.data.getVar('PN', the_data, 1)
477 pv = bb.data.getVar('PV', the_data, 1)
478 pr = bb.data.getVar('PR', the_data, 1)
479 tmpdir = bb.data.getVar('TMPDIR', the_data, 1)
480 stamp = '%s/stamps/%s-%s-%s.do_populate_staging' % (tmpdir, pn, pv, pr)
481 if os.path.exists(stamp):
482 (newvers, fn) = preferred_versions[pn]
483 if not fn in eligible:
484 # package was made ineligible by already-failed check
486 oldver = "%s-%s" % (pv, pr)
487 newver = '-'.join(newvers)
488 if (newver != oldver):
489 extra_chat = "; upgrading from %s to %s" % (oldver, newver)
492 if self.configuration.verbose:
493 bb.note("selecting already-staged %s to satisfy %s%s" % (pn, item, extra_chat))
495 eligible = [fn] + eligible
499 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
501 self.preferred[item] = prefervar
503 if item in self.preferred:
505 pn = self.status.pkg_fn[p]
506 if self.preferred[item] == pn:
507 if self.configuration.verbose:
508 bb.note("selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
510 eligible = [p] + eligible
514 if len(eligible) > 1 and discriminated == False:
515 if item not in self.consider_msgs_cache:
518 providers_list.append(self.status.pkg_fn[fn])
519 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
520 bb.note("consider defining PREFERRED_PROVIDER_%s" % item)
521 self.consider_msgs_cache.append(item)
524 # run through the list until we find one that we can build
526 bb.debug(2, "selecting %s to satisfy %s" % (fn, item))
527 if self.tryBuild(fn, item, buildAllDeps):
530 bb.note("no buildable providers for %s" % item)
533 def buildDepgraph( self ):
534 all_depends = self.status.all_depends
535 pn_provides = self.status.pn_provides
537 def calc_bbfile_priority(filename):
538 for (regex, pri) in self.status.bbfile_config_priorities:
539 if regex.match(filename):
543 # Handle PREFERRED_PROVIDERS
544 for p in (bb.data.getVar('PREFERRED_PROVIDERS', self.configuration.data, 1) or "").split():
545 (providee, provider) = p.split(':')
546 if providee in self.preferred and self.preferred[providee] != provider:
547 bb.error("conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.preferred[providee]))
548 self.preferred[providee] = provider
550 # Calculate priorities for each file
551 for p in self.pkgdata.keys():
552 self.status.bbfile_priority[p] = calc_bbfile_priority(p)
554 # Build package list for "bitbake world"
555 bb.debug(1, "collating packages for \"world\"")
556 for f in self.status.possible_world:
558 pn = self.status.pkg_fn[f]
560 for p in pn_provides[pn]:
561 if p.startswith('virtual/'):
562 bb.debug(2, "skipping %s due to %s provider starting with virtual/" % (f, p))
565 for pf in self.status.providers[p]:
566 if self.status.pkg_fn[pf] != pn:
567 bb.debug(2, "skipping %s due to both us and %s providing %s" % (f, pf, p))
571 self.status.world_target.add(pn)
573 # drop reference count now
574 self.status.possible_world = None
575 self.status.all_depends = None
577 def myProgressCallback( self, x, y, f, file_data, from_cache ):
578 # feed the status with new input
579 self.status.handle_bb_data(f, file_data, from_cache)
583 if os.isatty(sys.stdout.fileno()):
584 sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
588 sys.stdout.write("Parsing .bb files, please wait...")
591 sys.stdout.write("done.")
594 def interactiveMode( self ):
595 """Drop off into a shell"""
598 except ImportError, details:
599 bb.fatal("Sorry, shell not available (%s)" % details )
601 bb.data.update_data( self.configuration.data )
605 def parseConfigurationFile( self, afile ):
607 self.configuration.data = bb.parse.handle( afile, self.configuration.data )
609 bb.fatal( "Unable to open %s" % afile )
610 except bb.parse.ParseError, details:
611 bb.fatal( "Unable to parse %s (%s)" % (afile, details) )
613 def handleCollections( self, collections ):
614 """Handle collections"""
616 collection_list = collections.split()
617 for c in collection_list:
618 regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1)
620 bb.error("BBFILE_PATTERN_%s not defined" % c)
622 priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1)
624 bb.error("BBFILE_PRIORITY_%s not defined" % c)
627 cre = re.compile(regex)
629 bb.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
633 self.status.bbfile_config_priorities.append((cre, pri))
635 bb.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
638 def cook( self, configuration, args ):
639 self.configuration = configuration
641 if not self.configuration.cmd:
642 self.configuration.cmd = "build"
644 if self.configuration.debug:
645 bb.debug_level = self.configuration.debug
647 self.configuration.data = bb.data.init()
649 for f in self.configuration.file:
650 self.parseConfigurationFile( f )
652 self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
654 if self.configuration.show_environment:
655 self.showEnvironment()
658 # inject custom variables
659 if not bb.data.getVar("BUILDNAME", self.configuration.data):
660 bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
661 bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data)
663 buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
665 if self.configuration.interactive:
666 self.interactiveMode()
668 if self.configuration.buildfile is not None:
669 bf = os.path.abspath( self.configuration.buildfile )
671 bbfile_data = bb.parse.handle(bf, self.configuration.data)
673 bb.fatal("Unable to open %s" % bf)
675 item = bb.data.getVar('PN', bbfile_data, 1)
677 self.tryBuildPackage( bf, item, bbfile_data )
678 except bb.build.EventException:
679 bb.error( "Build of '%s' failed" % item )
681 sys.exit( self.stats.show() )
683 # initialise the parsing status now we know we will need deps
684 self.status = BBParsingStatus()
686 ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
687 self.status.ignored_dependencies = Set( ignore.split() )
689 self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
693 if not pkgs_to_build:
695 pkgs_to_build.extend(args)
696 if not pkgs_to_build:
697 bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
699 pkgs_to_build = bbpkgs.split()
700 if not pkgs_to_build and not self.configuration.show_versions \
701 and not self.configuration.interactive \
702 and not self.configuration.show_environment:
703 print "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help'"
704 print "for usage information."
707 # Import Psyco if available and not disabled
708 if not self.configuration.disable_psyco:
713 bb.note("Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
715 psyco.bind( self.collect_bbfiles )
717 bb.note("You have disabled Psyco. This decreases performance.")
720 bb.debug(1, "collecting .bb files")
721 self.collect_bbfiles( self.myProgressCallback )
722 bb.debug(1, "parsing complete")
725 if self.configuration.parse_only:
726 print "Requested parsing .bb files only. Exiting."
729 bb.data.update_data( self.configuration.data )
732 if self.configuration.show_versions:
735 if 'world' in pkgs_to_build:
736 pkgs_to_build.remove('world')
737 for t in self.status.world_target:
738 pkgs_to_build.append(t)
740 bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.data))
742 for k in pkgs_to_build:
745 if self.buildProvider( k , False ) == 0:
748 except bb.build.EventException:
749 bb.error("Build of " + k + " failed")
753 if self.configuration.abort:
756 bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.data))
758 sys.exit( self.stats.show() )
760 except KeyboardInterrupt:
761 print "\nNOTE: KeyboardInterrupt - Build not completed."
764 def get_bbfiles( self, path = os.getcwd() ):
765 """Get list of default .bb files by reading out the current directory"""
766 contents = os.listdir(path)
769 (root, ext) = os.path.splitext(f)
771 bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
774 def find_bbfiles( self, path ):
775 """Find all the .bb files in a directory (uses find)"""
776 findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
778 finddata = os.popen(findcmd)
781 return finddata.readlines()
783 def deps_clean(self, d):
784 depstr = data.getVar('__depends', d)
786 deps = depstr.split(" ")
788 (f,old_mtime_s) = dep.split("@")
789 old_mtime = int(old_mtime_s)
790 new_mtime = parse.cached_mtime(f)
791 if (new_mtime > old_mtime):
795 def load_bbfile( self, bbfile ):
796 """Load and parse one .bb build file"""
798 if not self.cache in [None, '']:
800 cache_mtime = data.init_db_mtime(self.cache, bbfile)
801 file_mtime = parse.cached_mtime(bbfile)
803 if file_mtime > cache_mtime:
804 #print " : '%s' dirty. reparsing..." % bbfile
807 #print " : '%s' clean. loading from cache..." % bbfile
808 cache_data = data.init_db( self.cache, bbfile, False )
809 if self.deps_clean(cache_data):
810 return cache_data, True
812 topdir = data.getVar('TOPDIR', self.configuration.data)
814 topdir = os.path.abspath(os.getcwd())
816 data.setVar('TOPDIR', topdir, self.configuration)
817 bbfile = os.path.abspath(bbfile)
818 bbfile_loc = os.path.abspath(os.path.dirname(bbfile))
819 # expand tmpdir to include this topdir
820 data.setVar('TMPDIR', data.getVar('TMPDIR', self.configuration.data, 1) or "", self.configuration.data)
821 # set topdir to location of .bb file
823 #data.setVar('TOPDIR', topdir, cfg)
825 oldpath = os.path.abspath(os.getcwd())
827 bb = data.init_db(self.cache,bbfile, True, self.configuration.data)
829 parse.handle(bbfile, bb) # read .bb data
830 if not self.cache in [None, '']:
831 bb.commit(parse.cached_mtime(bbfile)) # write cache
837 def collect_bbfiles( self, progressCallback ):
838 """Collect all available .bb build files"""
839 self.cb = progressCallback
840 parsed, cached, skipped, masked = 0, 0, 0, 0
841 self.cache = bb.data.getVar( "CACHE", self.configuration.data, 1 )
842 self.pkgdata = data.pkgdata( not self.cache in [None, ''], self.cache, self.configuration.data )
844 if not self.cache in [None, '']:
845 if self.cb is not None:
846 print "NOTE: Using cache in '%s'" % self.cache
848 os.stat( self.cache )
850 bb.mkdirhier( self.cache )
852 if self.cb is not None:
853 print "NOTE: Not using a cache. Set CACHE = <directory> to enable."
854 files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
855 data.setVar("BBFILES", " ".join(files), self.configuration.data)
858 files = self.get_bbfiles()
861 bb.error("no files to build.")
866 dirfiles = self.find_bbfiles(f)
870 newfiles += glob.glob(f) or [ f ]
872 bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1) or ""
874 bbmask_compiled = re.compile(bbmask)
875 except sre_constants.error:
876 bb.fatal("BBMASK is not a valid regular expression.")
878 for i in xrange( len( newfiles ) ):
880 if bbmask and bbmask_compiled.search(f):
881 bb.debug(1, "bbmake: skipping %s" % f)
884 debug(1, "bbmake: parsing %s" % f)
886 # read a file's metadata
888 bb_data, fromCache = self.load_bbfile(f)
889 if fromCache: cached += 1
892 if bb_data is not None:
893 # allow metadata files to add items to BBFILES
894 #data.update_data(self.pkgdata[f])
895 addbbfiles = data.getVar('BBFILES', bb_data) or None
897 for aof in addbbfiles.split():
898 if not files.count(aof):
899 if not os.path.isabs(aof):
900 aof = os.path.join(os.path.dirname(f),aof)
902 for var in bb_data.keys():
903 if data.getVarFlag(var, "handler", bb_data) and data.getVar(var, bb_data):
904 event.register(data.getVar(var, bb_data))
905 self.pkgdata[f] = bb_data
907 # now inform the caller
908 if self.cb is not None:
909 self.cb( i + 1, len( newfiles ), f, bb_data, fromCache )
912 bb.error("opening %s: %s" % (f, e))
914 except bb.parse.SkipPackage:
917 except KeyboardInterrupt:
920 bb.error("%s while parsing %s" % (e, f))
922 if self.cb is not None:
923 print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ),
925 #============================================================================#
927 #============================================================================#
929 if __name__ == "__main__":
931 parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
932 usage = """%prog [options] [package ...]
934 Executes the specified task (default is 'build') for a given set of BitBake files.
935 It expects that BBFILES is defined, which is a space seperated list of files to
936 be executed. BBFILES does support wildcards.
937 Default BBFILES are the .bb files in the current directory.""" )
939 parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
940 action = "store", dest = "buildfile", default = None )
942 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.",
943 action = "store_false", dest = "abort", default = True )
945 parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
946 action = "store_true", dest = "force", default = False )
948 parser.add_option( "-i", "--interactive", help = "drop into the interactive mode.",
949 action = "store_true", dest = "interactive", default = False )
951 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)",
952 action = "store", dest = "cmd", default = "build" )
954 parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
955 action = "append", dest = "file", default = [] )
957 parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
958 action = "store_true", dest = "verbose", default = False )
960 parser.add_option( "-D", "--debug", help = "Increase the debug level",
961 action = "count", dest="debug", default = 0)
963 parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
964 action = "store_true", dest = "dry_run", default = False )
966 parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
967 action = "store_true", dest = "parse_only", default = False )
969 parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
970 action = "store_true", dest = "disable_psyco", default = False )
972 parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
973 action = "store_true", dest = "show_versions", default = False )
975 parser.add_option( "-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
976 action = "store_true", dest = "show_environment", default = False )
978 options, args = parser.parse_args( sys.argv )
981 cooker.cook( BBConfiguration( options ), args[1:] )