misc. refactoring bits for bin/bitbake:
[bitbake.git] / bin / bitbake
1 #!/usr/bin/env python
2 # ex:ts=4:sw=4:sts=4:et
3 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4 #
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
10 #
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
14 # version.
15 #
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.
19 #
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.
23
24 import sys, os, getopt, glob, copy, os.path, re
25 sys.path.append(os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
26 import bb
27 from bb import make
28 from sets import Set
29 import itertools, optparse
30
31 parsespin = itertools.cycle( r'|/-\\' )
32 bbdebug = 0
33
34 __version__ = "1.3.1"
35
36 #============================================================================#
37 # BBParsingStatus
38 #============================================================================#
39 class BBParsingStatus:
40     """
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
43     again.
44     """
45
46     def __init__(self):
47         self.cache_dirty = False
48         self.providers   = {}
49         self.bbfile_priority = {}
50         self.bbfile_config_priorities = []
51         self.ignored_depedencies = None
52         self.possible_world = []
53         self.world_target = Set()
54         self.pkg_pn = {}
55         self.pkg_fn = {}
56         self.pkg_pvpr = {}
57         self.pkg_dp = {}
58         self.pn_provides = {}
59         self.all_depends = Set()
60
61     def handle_bb_data(self, file_name, bb_data, cached):
62         """
63         We will fill the dictionaries with the stuff we
64         need for building the tree more fast
65         """
66         if bb_data == None:
67             return
68
69         if not cached:
70             self.cache_dirty = True
71
72         pn       = bb.data.getVar('PN', bb_data, True)
73         pv       = bb.data.getVar('PV', bb_data, True)
74         pr       = bb.data.getVar('PR', bb_data, True)
75         dp       = int(bb.data.getVar('DEFAULT_PREFERENCE', bb_data, True) or "0")
76         provides = Set([pn] + (bb.data.getVar("PROVIDES", bb_data, 1) or "").split())
77         depends  = (bb.data.getVar("DEPENDS", bb_data, True) or "").split()
78
79
80         # build PackageName to FileName lookup table
81         if pn not in self.pkg_pn:
82             self.pkg_pn[pn] = []
83         self.pkg_pn[pn].append(file_name)
84
85         # build FileName to PackageName lookup table
86         self.pkg_fn[file_name] = pn
87         self.pkg_pvpr[file_name] = (pv,pr)
88         self.pkg_dp[file_name] = dp
89
90         # Build forward and reverse provider hashes
91         # Forward: virtual -> [filenames]
92         # Reverse: PN -> [virtuals]
93         if pn not in self.pn_provides:
94             self.pn_provides[pn] = Set()
95         self.pn_provides[pn] |= provides
96
97         for provide in provides:
98             if provide not in self.providers:
99                 self.providers[provide] = []
100             self.providers[provide].append(file_name)
101
102         for dep in depends:
103             self.all_depends.add(dep)
104
105         # Collect files we may need for possible world-dep
106         # calculations
107         if not bb.data.getVar('BROKEN', bb_data, True) and not bb.data.getVar('EXCLUDE_FROM_WORLD', bb_data, True):
108             self.possible_world.append(file_name)
109
110
111 #============================================================================#
112 # BBStatistics
113 #============================================================================#
114 class BBStatistics:
115     """
116     Manage build statistics for one run
117     """
118     def __init__(self ):
119         self.attempt = 0
120         self.success = 0
121         self.fail = 0
122         self.deps = 0
123
124     def show( self ):
125         print "Build statistics:"
126         print "  Attempted builds: %d" % self.attempt
127         if self.fail:
128             print "  Failed builds: %d" % self.fail
129         if self.deps:
130             print "  Dependencies not satisfied: %d" % self.deps
131         if self.fail or self.deps: return 1
132         else: return 0
133
134
135 #============================================================================#
136 # BBCooker
137 #============================================================================#
138 class BBCooker:
139     """
140     Manages one bitbake build run
141     """
142
143     ParsingStatus = BBParsingStatus     # make it visible from the shell
144     Statistics = BBStatistics           # make it visible from the shell
145
146     def __init__( self ):
147         self.build_cache_fail = []
148         self.build_cache = []
149         self.building_list = []
150         self.build_path = []
151         self.consider_msgs_cache = []
152         self.preferred = {}
153         self.stats = BBStatistics()
154         self.status = None
155
156     def tryBuildPackage( self, fn, item, the_data ):
157         print ">>>tryBuildPackage. fn = '%s', item = '%s', the_data = '%s'" % (fn, item, the_data )
158         """Build one package"""
159         bb.event.fire(bb.event.PkgStarted(item, the_data))
160         try:
161             self.stats.attempt += 1
162             if make.options.force:
163                 bb.data.setVarFlag('do_%s' % make.options.cmd, 'force', 1, d)
164             if not make.options.dry_run:
165                 bb.build.exec_task('do_%s' % make.options.cmd, the_data)
166             bb.event.fire(bb.event.PkgSucceeded(item, the_data))
167             self.build_cache.append(fn)
168             return True
169         except bb.build.FuncFailed:
170             self.stats.fail += 1
171             bb.error("task stack execution failed")
172             bb.event.fire(bb.event.PkgFailed(item, the_data))
173             self.build_cache_fail.append(fn)
174             raise
175         except bb.build.EventException:
176             self.stats.fail += 1
177             (type, value, traceback) = sys.exc_info()
178             e = value.event
179             bb.error("%s event exception, aborting" % bb.event.getName(e))
180             bb.event.fire(bb.event.PkgFailed(item, the_data))
181             self.build_cache_fail.append(fn)
182             raise
183
184     def tryBuild( self, fn, virtual ):
185         """Build a provider and its dependencies"""
186         if fn in self.building_list:
187             bb.error("%s depends on itself (eventually)" % fn)
188             bb.error("upwards chain is: %s" % (" -> ".join(self.build_path)))
189             return False
190
191         the_data = make.pkgdata[fn]
192         item = self.status.pkg_fn[fn]
193
194         self.building_list.append(fn)
195
196         pathstr = "%s (%s)" % (item, virtual)
197         self.build_path.append(pathstr)
198
199         depends_list = (bb.data.getVar('DEPENDS', the_data, 1) or "").split()
200         if make.options.verbose:
201             bb.note("current path: %s" % (" -> ".join(self.build_path)))
202             bb.note("dependencies for %s are: %s" % (item, " ".join(depends_list)))
203
204         try:
205             failed = False
206
207             depcmd = make.options.cmd
208             bbdepcmd = bb.data.getVarFlag('do_%s' % make.options.cmd, 'bbdepcmd', the_data)
209             if bbdepcmd is not None:
210                 if bbdepcmd == "":
211                     depcmd = None
212                 else:
213                     depcmd = bbdepcmd
214
215             if depcmd:
216                 oldcmd = make.options.cmd
217                 make.options.cmd = depcmd
218
219             for dependency in depends_list:
220                 if dependency in self.status.ignored_dependencies:
221                     continue
222                 if not depcmd:
223                     continue
224                 if self.buildProvider( dependency ) == 0:
225                     bb.error("dependency %s (for %s) not satisfied" % (dependency,item))
226                     failed = True
227                     if make.options.abort:
228                         break
229
230             if depcmd:
231                 make.options.cmd = oldcmd
232
233             if failed:
234                 self.stats.deps += 1
235                 return False
236
237             if bb.build.stamp_is_current('do_%s' % make.options.cmd, the_data):
238                 self.build_cache.append(fn)
239                 return True
240
241             return self.tryBuildPackage( fn, item, the_data )
242
243         finally:
244             self.building_list.remove(fn)
245             self.build_path.remove(pathstr)
246
247     def showVersions( self ):
248         pkg_pn = self.status.pkg_pn
249         preferred_versions = {}
250         latest_versions = {}
251
252         # Sort by priority
253         for pn in pkg_pn.keys():
254             files = pkg_pn[pn]
255             priorities = {}
256             for f in files:
257                 priority = self.status.bbfile_priority[f]
258                 if priority not in priorities:
259                     priorities[priority] = []
260                 priorities[priority].append(f)
261             p_list = priorities.keys()
262             p_list.sort(lambda a, b: a - b)
263             pkg_pn[pn] = []
264             for p in p_list:
265                 pkg_pn[pn] = [ priorities[p] ] + pkg_pn[pn]
266
267         for pn in pkg_pn.keys():
268             preferred_file = None
269             preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, make.cfg, 1)
270             if preferred_v:
271                 preferred_r = None
272                 m = re.match('(.*)_(.*)', preferred_v)
273                 if m:
274                     preferred_v = m.group(1)
275                     preferred_r = m.group(2)
276
277                 for file_set in pkg_pn[pn]:
278                     for f in file_set:
279                         pv,pr = self.status.pkg_pvpr[f]
280                         if preferred_v == pv and (preferred_r == pr or preferred_r == None):
281                             preferred_file = f
282                             preferred_ver = (pv, pr)
283                             break
284                     if preferred_file:
285                         break
286                 if preferred_r:
287                     pv_str = '%s-%s' % (preferred_v, preferred_r)
288                 else:
289                     pv_str = preferred_v
290                 if preferred_file is None:
291                     bb.note("preferred version %s of %s not available" % (pv_str, pn))
292                 else:
293                     bb.debug(1, "selecting %s as PREFERRED_VERSION %s of package %s" % (preferred_file, pv_str, pn))
294
295             # get highest priority file set
296             files = pkg_pn[pn][0]
297             latest = None
298             latest_p = 0
299             latest_f = None
300             for f in files:
301                 pv,pr = self.status.pkg_pvpr[f]
302                 dp = self.status.pkg_dp[f]
303
304                 if (latest is None) or ((latest_p == dp) and (make.vercmp(latest, (pv, pr)) < 0)) or (dp > latest_p):
305                     latest = (pv, pr)
306                     latest_f = f
307                     latest_p = dp
308             if preferred_file is None:
309                 preferred_file = latest_f
310                 preferred_ver = latest
311
312             preferred_versions[pn] = (preferred_ver, preferred_file)
313             latest_versions[pn] = (latest, latest_f)
314
315         pkg_list = pkg_pn.keys()
316         pkg_list.sort()
317
318         for p in pkg_list:
319             pref = preferred_versions[p]
320             latest = latest_versions[p]
321
322             if pref != latest:
323                 prefstr = pref[0][0] + "-" + pref[0][1]
324             else:
325                 prefstr = ""
326
327             print "%-30s %20s %20s" % (p, latest[0][0] + "-" + latest[0][1],
328                                         prefstr)
329
330     def buildProvider( self, item ):
331         fn = None
332
333         discriminated = False
334
335         if item not in self.status.providers:
336             bb.error("Nothing provides %s" % item)
337             return 0
338
339         all_p = self.status.providers[item]
340
341         for p in all_p:
342             if p in self.build_cache:
343                 bb.debug(1, "already built %s in this run\n" % p)
344                 return 1
345
346         eligible = []
347         preferred_versions = {}
348
349         # Collate providers by PN
350         pkg_pn = {}
351         for p in all_p:
352             pn = self.status.pkg_fn[p]
353             if pn not in pkg_pn:
354                 pkg_pn[pn] = []
355             pkg_pn[pn].append(p)
356
357         bb.debug(1, "providers for %s are: %s" % (item, pkg_pn.keys()))
358
359         # Sort by priority
360         for pn in pkg_pn.keys():
361             files = pkg_pn[pn]
362             priorities = {}
363             for f in files:
364                 priority = self.status.bbfile_priority[f]
365                 if priority not in priorities:
366                     priorities[priority] = []
367                 priorities[priority].append(f)
368             p_list = priorities.keys()
369             p_list.sort(lambda a, b: a - b)
370             pkg_pn[pn] = []
371             for p in p_list:
372                 pkg_pn[pn] = [ priorities[p] ] + pkg_pn[pn]
373
374         # If there is a PREFERRED_VERSION, find the highest-priority bbfile providing that
375         # version.  If not, find the latest version provided by an bbfile in the
376         # highest-priority set.
377         for pn in pkg_pn.keys():
378             preferred_file = None
379
380             preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, make.cfg, 1)
381             if preferred_v:
382                 preferred_r = None
383                 m = re.match('(.*)_(.*)', preferred_v)
384                 if m:
385                     preferred_v = m.group(1)
386                     preferred_r = m.group(2)
387
388                 for file_set in pkg_pn[pn]:
389                     for f in file_set:
390                         pv,pr = self.status.pkg_pvpr[f]
391                         if preferred_v == pv and (preferred_r == pr or preferred_r == None):
392                             preferred_file = f
393                             preferred_ver = (pv, pr)
394                             break
395                     if preferred_file:
396                         break
397                 if preferred_r:
398                     pv_str = '%s-%s' % (preferred_v, preferred_r)
399                 else:
400                     pv_str = preferred_v
401                 if preferred_file is None:
402                     bb.note("preferred version %s of %s not available" % (pv_str, pn))
403                 else:
404                     bb.debug(1, "selecting %s as PREFERRED_VERSION %s of package %s" % (preferred_file, pv_str, pn))
405
406             if preferred_file is None:
407                 # get highest priority file set
408                 files = pkg_pn[pn][0]
409                 latest = None
410                 latest_p = 0
411                 latest_f = None
412                 for f in files:
413                     pv,pr = self.status.pkg_pvpr[f]
414                     dp    = self.status.pkg_dp[f]
415
416                     if (latest is None) or ((latest_p == dp) and (make.vercmp(latest, (pv, pr)) < 0)) or (dp > latest_p):
417                         latest = (pv, pr)
418                         latest_f = f
419                         latest_p = dp
420                 preferred_file = latest_f
421                 preferred_ver = latest
422
423                 bb.debug(1, "selecting %s as latest version of provider %s" % (preferred_file, pn))
424
425             preferred_versions[pn] = (preferred_ver, preferred_file)
426             eligible.append(preferred_file)
427
428         for p in eligible:
429             if p in self.build_cache_fail:
430                 bb.debug(1, "rejecting already-failed %s" % p)
431                 eligible.remove(p)
432
433         if len(eligible) == 0:
434             bb.error("no eligible providers for %s" % item)
435             return 0
436
437         # look to see if one of them is already staged, or marked as preferred.
438         # if so, bump it to the head of the queue
439         for p in all_p:
440             the_data = make.pkgdata[p]
441             pn = bb.data.getVar('PN', the_data, 1)
442             pv = bb.data.getVar('PV', the_data, 1)
443             pr = bb.data.getVar('PR', the_data, 1)
444             tmpdir = bb.data.getVar('TMPDIR', the_data, 1)
445             stamp = '%s/stamps/%s-%s-%s.do_populate_staging' % (tmpdir, pn, pv, pr)
446             if os.path.exists(stamp):
447                 (newvers, fn) = preferred_versions[pn]
448                 if not fn in eligible:
449                     # package was made ineligible by already-failed check
450                     continue
451                 oldver = "%s-%s" % (pv, pr)
452                 newver = '-'.join(newvers)
453                 if (newver != oldver):
454                     extra_chat = "; upgrading from %s to %s" % (oldver, newver)
455                 else:
456                     extra_chat = ""
457                 if make.options.verbose:
458                     bb.note("selecting already-staged %s to satisfy %s%s" % (pn, item, extra_chat))
459                 eligible.remove(fn)
460                 eligible = [fn] + eligible
461                 discriminated = True
462                 break
463
464         prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, make.cfg, 1)
465         if prefervar:
466             self.preferred[item] = prefervar
467
468         if item in self.preferred:
469             for p in eligible:
470                 pn = self.status.pkg_fn[p]
471                 if self.preferred[item] == pn:
472                     if make.options.verbose:
473                         bb.note("selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
474                     eligible.remove(p)
475                     eligible = [p] + eligible
476                     discriminated = True
477                     break
478
479         if len(eligible) > 1 and discriminated == False:
480             if item not in self.consider_msgs_cache:
481                 providers_list = []
482                 for fn in eligible:
483                     providers_list.append(self.status.pkg_fn[fn])
484                 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
485                 bb.note("consider defining PREFERRED_PROVIDER_%s" % item)
486             self.consider_msgs_cache.append(item)
487
488
489         # run through the list until we find one that we can build
490         for fn in eligible:
491             bb.debug(2, "selecting %s to satisfy %s" % (fn, item))
492             if self.tryBuild(fn, item):
493                 return 1
494
495         bb.note("no buildable providers for %s" % item)
496         return 0
497
498     def buildDepgraph( self ):
499         all_depends = self.status.all_depends
500         pn_provides = self.status.pn_provides
501
502         def calc_bbfile_priority(filename):
503             for (regex, pri) in self.status.bbfile_config_priorities:
504                 if regex.match(filename):
505                     return pri
506             return 0
507
508         # Handle PREFERRED_PROVIDERS
509         for p in (bb.data.getVar('PREFERRED_PROVIDERS', make.cfg, 1) or "").split():
510             (providee, provider) = p.split(':')
511             if providee in self.preferred and self.preferred[providee] != provider:
512                 bb.error("conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.preferred[providee]))
513             self.preferred[providee] = provider
514
515         # Calculate priorities for each file
516         for p in make.pkgdata.keys():
517             self.status.bbfile_priority[p] = calc_bbfile_priority(p)
518
519         # Build package list for "bitbake world"
520         bb.debug(1, "collating packages for \"world\"")
521         for f in self.status.possible_world:
522             terminal = True
523             pn = self.status.pkg_fn[f]
524
525             for p in pn_provides[pn]:
526                 if p.startswith('virtual/'):
527                     bb.debug(2, "skipping %s due to %s provider starting with virtual/" % (f, p))
528                     terminal = False
529                     break
530                 for pf in self.status.providers[p]:
531                     if self.status.pkg_fn[pf] != pn:
532                         bb.debug(2, "skipping %s due to both us and %s providing %s" % (f, pf, p))
533                         terminal = False
534                         break
535             if terminal:
536                 self.status.world_target.add(pn)
537
538             # drop reference count now
539             self.status.possible_world = None
540             self.status.all_depends    = None
541
542     def myProgressCallback( self, x, y, f, file_data, from_cache ):
543         # feed the status with new input
544         self.status.handle_bb_data(f, file_data, from_cache)
545
546         if bbdebug > 0:
547             return
548         if os.isatty(sys.stdout.fileno()):
549             sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
550             sys.stdout.flush()
551         else:
552             if x == 1:
553                 sys.stdout.write("Parsing .bb files, please wait...")
554                 sys.stdout.flush()
555             if x == y:
556                 sys.stdout.write("done.")
557                 sys.stdout.flush()
558
559     def interactiveMode( self ):
560         """Drop off into a shell"""
561         try:
562             from bb import shell
563         except ImportError, details:
564             bb.fatal("Sorry, shell not available (%s)" % details )
565         else:
566             shell.start( self )
567             sys.exit( 0 )
568
569     def parseConfigurationFile( self, afile ):
570         try:
571             make.cfg = bb.parse.handle( afile, make.cfg )
572         except IOError:
573             bb.fatal( "Unable to open %s" % afile )
574         except bb.parse.ParseError:
575             bb.fatal( "Unable to parse %s" % afile )
576
577     def handleCollections( self, collections ):
578         """Handle collections"""
579         if collections:
580             collection_list = collections.split()
581             for c in collection_list:
582                 regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, make.cfg, 1)
583                 if regex == None:
584                     bb.error("BBFILE_PATTERN_%s not defined" % c)
585                     continue
586                 priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, make.cfg, 1)
587                 if priority == None:
588                     bb.error("BBFILE_PRIORITY_%s not defined" % c)
589                     continue
590                 try:
591                     cre = re.compile(regex)
592                 except re.error:
593                     bb.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
594                     continue
595                 try:
596                     pri = int(priority)
597                     self.status.bbfile_config_priorities.append((cre, pri))
598                 except ValueError:
599                     bb.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
600
601
602     def cook( self, args ):
603         if not make.options.cmd:
604             make.options.cmd = "build"
605
606         if make.options.debug:
607             bb.debug_level = make.options.debug
608
609         make.cfg = bb.data.init()
610
611         for f in make.options.file:
612             self.parseConfigurationFile( f )
613
614         self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
615
616         if not bb.data.getVar("BUILDNAME", make.cfg):
617             bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), make.cfg)
618
619         buildname = bb.data.getVar("BUILDNAME", make.cfg)
620
621         if make.options.interactive:
622             self.interactiveMode()
623
624         bf = make.options.buildfile
625         if bf:
626             try:
627                 bbfile_data = bb.parse.handle(bf, make.cfg)
628             except IOError:
629                 bb.fatal("Unable to open %s" % bf)
630
631             item = bb.data.getVar('PN', bbfile_data, 1)
632             self.tryBuildPackage( os.path.abspath( bf ), item, bbfile_data )
633             sys.exit( self.stats.show() )
634
635         # initialise the parsing status now we know we will need deps
636         self.status = BBParsingStatus()
637
638         ignore = bb.data.getVar("ASSUME_PROVIDED", make.cfg, 1) or ""
639         self.status.ignored_dependencies = Set( ignore.split() )
640
641         self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", make.cfg, 1) )
642
643         pkgs_to_build = None
644         if args:
645             if not pkgs_to_build:
646                 pkgs_to_build = []
647             pkgs_to_build.extend(args)
648         if not pkgs_to_build:
649                 bbpkgs = bb.data.getVar('BBPKGS', make.cfg, 1)
650                 if bbpkgs:
651                         pkgs_to_build = bbpkgs.split()
652         if not pkgs_to_build and not make.options.show_versions and not make.options.interactive:
653                 print "Nothing to do.  Use 'bitbake world' to build everything, or run 'bitbake --help'"
654                 print "for usage information."
655                 sys.exit(0)
656
657         # Import Psyco if available and not disabled
658         if not make.options.disable_psyco:
659             try:
660                 import psyco
661             except ImportError:
662                 if bbdebug == 0:
663                     bb.note("Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
664             else:
665                 psyco.bind( make.collect_bbfiles )
666         else:
667             bb.note("You have disabled Psyco. This decreases performance.")
668
669         try:
670             bb.debug(1, "collecting .bb files")
671             make.collect_bbfiles( self.myProgressCallback )
672             bb.debug(1, "parsing complete")
673             if bbdebug == 0:
674                 print
675             if make.options.parse_only:
676                 print "Requested parsing .bb files only.  Exiting."
677                 return
678
679             bb.data.update_data( make.cfg )
680             self.buildDepgraph()
681
682             if make.options.show_versions:
683                 self.showVersions()
684                 sys.exit( 0 )
685             if 'world' in pkgs_to_build:
686                 pkgs_to_build.remove('world')
687                 for t in self.status.world_target:
688                     pkgs_to_build.append(t)
689
690             bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, make.cfg))
691
692             for k in pkgs_to_build:
693                 failed = False
694                 try:
695                     if self.buildProvider( k ) == 0:
696                         # already diagnosed
697                         failed = True
698                 except bb.build.EventException:
699                     bb.error("Build of " + k + " failed")
700                     failed = True
701
702                 if failed:
703                     if make.options.abort:
704                         sys.exit(1)
705
706             bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, make.cfg))
707
708             sys.exit( self.stats.show() )
709
710         except KeyboardInterrupt:
711             print "\nNOTE: KeyboardInterrupt - Build not completed."
712             sys.exit(1)
713
714 #============================================================================#
715 # main
716 #============================================================================#
717
718 if __name__ == "__main__":
719
720     parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
721     usage = """%prog [options] [package ...]
722
723 Executes the specified task (default is 'build') for a given set of BitBake files.
724 It expects that BBFILES is defined, which is a space seperated list of files to
725 be executed.  BBFILES does support wildcards.
726 Default BBFILES are the .bb files in the current directory.""" )
727
728     parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
729                action = "store", dest = "buildfile", default = None )
730
731     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.",
732                action = "store_false", dest = "abort", default = True )
733
734     parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
735                action = "store_true", dest = "force", default = False )
736
737     parser.add_option( "-i", "--interactive", help = "drop into the interactive mode.",
738                action = "store_true", dest = "interactive", default = False )
739
740     parser.add_option( "-c", "--cmd", help = "Specify task to execute",
741                action = "store", dest = "cmd", default = "build" )
742
743     parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
744                action = "append", dest = "file", default = [] )
745
746     parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
747                action = "store_true", dest = "verbose", default = False )
748
749     parser.add_option( "-D", "--debug", help = "Increase the debug level",
750                action = "count", dest="debug", default = 0)
751
752     parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
753                action = "store_true", dest = "dry_run", default = False )
754
755     parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
756                action = "store_true", dest = "parse_only", default = False )
757
758     parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
759                action = "store_true", dest = "disable_psyco", default = False )
760
761     parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
762                action = "store_true", dest = "show_versions", default = False )
763
764     options, args = parser.parse_args( sys.argv )
765
766     make.options = options
767     cooker = BBCooker()
768     cooker.cook( args[1:] )