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