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