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