bitbake/bin/bitbake: Add code to handle RDEPENDS
[vuplus_bitbake] / 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, time
25 sys.path.insert(0,os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
26 import bb
27 from bb import utils, data, parse, debug, event, fatal, cache
28 from sets import Set
29 import itertools, optparse
30
31 parsespin = itertools.cycle( r'|/-\\' )
32 bbdebug = 0
33
34 __version__ = "1.5.0"
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.providers   = {}
48         self.rproviders = {}
49         self.packages = {}
50         self.packages_dynamic = {}
51         self.bbfile_priority = {}
52         self.bbfile_config_priorities = []
53         self.ignored_dependencies = None
54         self.possible_world = []
55         self.world_target = Set()
56         self.pkg_pn = {}
57         self.pkg_fn = {}
58         self.pkg_pvpr = {}
59         self.pkg_dp = {}
60         self.pn_provides = {}
61         self.all_depends = Set()
62         self.build_all = {}
63         self.rundeps = {}
64         self.runrecs = {}
65         self.stamp = {}
66
67     def handle_bb_data(self, file_name, bb_cache, cached):
68         """
69         We will fill the dictionaries with the stuff we
70         need for building the tree more fast
71         """
72
73         pn       = bb_cache.getVar('PN', file_name, True)
74         pv       = bb_cache.getVar('PV', file_name, True)
75         pr       = bb_cache.getVar('PR', file_name, True)
76         dp       = int(bb_cache.getVar('DEFAULT_PREFERENCE', file_name, True) or "0")
77         provides  = Set([pn] + (bb_cache.getVar("PROVIDES", file_name, True) or "").split())
78         depends   = (bb_cache.getVar("DEPENDS", file_name, True) or "").split()
79         packages  = (bb_cache.getVar('PACKAGES', file_name, True) or "").split()
80         packages_dynamic = (bb_cache.getVar('PACKAGES_DYNAMIC', file_name, True) or "").split()
81         rprovides = (bb_cache.getVar("RPROVIDES", file_name, True) or "").split()
82
83         # build PackageName to FileName lookup table
84         if pn not in self.pkg_pn:
85             self.pkg_pn[pn] = []
86         self.pkg_pn[pn].append(file_name)
87
88         self.build_all[file_name] = int(bb_cache.getVar('BUILD_ALL_DEPS', file_name, True) or "0")
89         self.stamp[file_name] = bb_cache.getVar('STAMP', file_name, True)
90
91         # build FileName to PackageName lookup table
92         self.pkg_fn[file_name] = pn
93         self.pkg_pvpr[file_name] = (pv,pr)
94         self.pkg_dp[file_name] = dp
95
96         # Build forward and reverse provider hashes
97         # Forward: virtual -> [filenames]
98         # Reverse: PN -> [virtuals]
99         if pn not in self.pn_provides:
100             self.pn_provides[pn] = Set()
101         self.pn_provides[pn] |= provides
102
103         for provide in provides:
104             if provide not in self.providers:
105                 self.providers[provide] = []
106             self.providers[provide].append(file_name)
107
108         for dep in depends:
109             self.all_depends.add(dep)
110
111         # Build reverse hash for PACKAGES, so runtime dependencies 
112         # can be be resolved (RDEPENDS, RRECOMMENDS etc.)
113         for package in packages:
114             if not package in self.packages:
115                 self.packages[package] = []
116             self.packages[package].append(file_name)
117             rprovides += (bb_cache.getVar("RPROVIDES_%s" % package, file_name, 1) or "").split() 
118
119         for package in packages_dynamic:
120             if not package in self.packages_dynamic:
121                 self.packages_dynamic[package] = []
122             self.packages_dynamic[package].append(file_name)
123
124         for rprovide in rprovides:
125             if not rprovide in self.rproviders:
126                 self.rproviders[rprovide] = []
127             self.rproviders[rprovide].append(file_name)
128
129         # Build hash of runtime depeneds and rececommends
130
131         def add_dep(deplist, deps):
132             for dep in deps:
133                 if not dep in deplist:
134                     deplist[dep] = ""
135
136         if not file_name in self.rundeps:
137             self.rundeps[file_name] = {}
138         if not file_name in self.runrecs:
139             self.runrecs[file_name] = {}
140
141         for package in packages + [pn]:
142             if not package in self.rundeps[file_name]:
143                 self.rundeps[file_name][package] = {}
144             if not package in self.runrecs[file_name]:
145                 self.runrecs[file_name][package] = {}
146
147             add_dep(self.rundeps[file_name][package], bb.utils.explode_deps(bb_cache.getVar('RDEPENDS', file_name, True) or ""))
148             add_dep(self.runrecs[file_name][package], bb.utils.explode_deps(bb_cache.getVar('RRECOMMENDS', file_name, True) or ""))
149             add_dep(self.rundeps[file_name][package], bb.utils.explode_deps(bb_cache.getVar("RDEPENDS_%s" % package, file_name, True) or ""))
150             add_dep(self.runrecs[file_name][package], bb.utils.explode_deps(bb_cache.getVar("RRECOMMENDS_%s" % package, file_name, True) or ""))
151
152         # Collect files we may need for possible world-dep
153         # calculations
154         if not bb_cache.getVar('BROKEN', file_name, True) and not bb_cache.getVar('EXCLUDE_FROM_WORLD', file_name, True):
155             self.possible_world.append(file_name)
156
157
158 #============================================================================#
159 # BBStatistics
160 #============================================================================#
161 class BBStatistics:
162     """
163     Manage build statistics for one run
164     """
165     def __init__(self ):
166         self.attempt = 0
167         self.success = 0
168         self.fail = 0
169         self.deps = 0
170
171     def show( self ):
172         print "Build statistics:"
173         print "  Attempted builds: %d" % self.attempt
174         if self.fail:
175             print "  Failed builds: %d" % self.fail
176         if self.deps:
177             print "  Dependencies not satisfied: %d" % self.deps
178         if self.fail or self.deps: return 1
179         else: return 0
180
181
182 #============================================================================#
183 # BBOptions
184 #============================================================================#
185 class BBConfiguration( object ):
186     """
187     Manages build options and configurations for one run
188     """
189     def __init__( self, options ):
190         for key, val in options.__dict__.items():
191             setattr( self, key, val )
192
193 #============================================================================#
194 # BBCooker
195 #============================================================================#
196 class BBCooker:
197     """
198     Manages one bitbake build run
199     """
200
201     ParsingStatus = BBParsingStatus     # make it visible from the shell
202     Statistics = BBStatistics           # make it visible from the shell
203
204     def __init__( self ):
205         self.build_cache_fail = []
206         self.build_cache = []
207         self.rbuild_cache = []
208         self.building_list = []
209         self.build_path = []
210         self.consider_msgs_cache = []
211         self.preferred = {}
212         self.stats = BBStatistics()
213         self.status = None
214
215         self.cache = None
216         self.bb_cache = None
217
218     def tryBuildPackage( self, fn, item, the_data ):
219         """Build one package"""
220         bb.event.fire(bb.event.PkgStarted(item, the_data))
221         try:
222             self.stats.attempt += 1
223             if self.configuration.force:
224                 bb.data.setVarFlag('do_%s' % self.configuration.cmd, 'force', 1, the_data)
225             if not self.configuration.dry_run:
226                 bb.build.exec_task('do_%s' % self.configuration.cmd, the_data)
227             bb.event.fire(bb.event.PkgSucceeded(item, the_data))
228             self.build_cache.append(fn)
229             return True
230         except bb.build.FuncFailed:
231             self.stats.fail += 1
232             bb.error("task stack execution failed")
233             bb.event.fire(bb.event.PkgFailed(item, the_data))
234             self.build_cache_fail.append(fn)
235             raise
236         except bb.build.EventException, e:
237             self.stats.fail += 1
238             event = e.args[1]
239             bb.error("%s event exception, aborting" % bb.event.getName(event))
240             bb.event.fire(bb.event.PkgFailed(item, the_data))
241             self.build_cache_fail.append(fn)
242             raise
243
244     def tryBuild( self, fn, virtual , buildAllDeps , build_depends = []):
245         """
246         Build a provider and its dependencies. 
247         build_depends is a list of previous build dependencies (not runtime)
248         If build_depends is empty, we're dealing with a runtime depends
249         """
250
251         the_data = self.bb_cache.loadDataFull(fn, self)
252
253         # Only follow all (runtime) dependencies if doing a build
254         if not buildAllDeps and self.configuration.cmd is "build":
255             buildAllDeps = self.status.build_all[fn]
256
257         # Error on build time dependency loops
258         if build_depends and build_depends.count(fn) > 1:
259             bb.error("%s depends on itself (eventually)" % fn)
260             bb.error("upwards chain is: %s" % (" -> ".join(self.build_path)))
261             return False
262
263         # See if this is a runtime dependency we've already built
264         # Or a build dependency being handled in a different build chain
265         if fn in self.building_list:
266             return self.addRunDeps(fn, virtual , buildAllDeps)
267
268         item = self.status.pkg_fn[fn]
269
270         self.building_list.append(fn)
271
272         pathstr = "%s (%s)" % (item, virtual)
273         self.build_path.append(pathstr)
274
275         depends_list = (bb.data.getVar('DEPENDS', the_data, True) or "").split()
276
277         if self.configuration.verbose:
278             bb.note("current path: %s" % (" -> ".join(self.build_path)))
279             bb.note("dependencies for %s are: %s" % (item, " ".join(depends_list)))
280
281         try:
282             failed = False
283
284             depcmd = self.configuration.cmd
285             bbdepcmd = bb.data.getVarFlag('do_%s' % self.configuration.cmd, 'bbdepcmd', the_data)
286             if bbdepcmd is not None:
287                 if bbdepcmd == "":
288                     depcmd = None
289                 else:
290                     depcmd = bbdepcmd
291
292             if depcmd:
293                 oldcmd = self.configuration.cmd
294                 self.configuration.cmd = depcmd
295
296             for dependency in depends_list:
297                 if dependency in self.status.ignored_dependencies:
298                     continue
299                 if not depcmd:
300                     continue
301                 if self.buildProvider( dependency , buildAllDeps , build_depends ) == 0:
302                     bb.error("dependency %s (for %s) not satisfied" % (dependency,item))
303                     failed = True
304                     if self.configuration.abort:
305                         break
306
307             if depcmd:
308                 self.configuration.cmd = oldcmd
309
310             if failed:
311                 self.stats.deps += 1
312                 return False
313
314             if not self.addRunDeps(fn, virtual , buildAllDeps):
315                 return False
316
317             if bb.build.stamp_is_current('do_%s' % self.configuration.cmd, the_data):
318                 self.build_cache.append(fn)
319                 return True
320
321             return self.tryBuildPackage( fn, item, the_data )
322
323         finally:
324             self.building_list.remove(fn)
325             self.build_path.remove(pathstr)
326
327     def findBestProvider( self, pn, pkg_pn = None):
328         """
329         If there is a PREFERRED_VERSION, find the highest-priority bbfile
330         providing that version.  If not, find the latest version provided by
331         an bbfile in the highest-priority set.
332         """
333         if not pkg_pn:
334             pkg_pn = self.status.pkg_pn
335
336         files = pkg_pn[pn]
337         priorities = {}
338         for f in files:
339             priority = self.status.bbfile_priority[f]
340             if priority not in priorities:
341                 priorities[priority] = []
342             priorities[priority].append(f)
343         p_list = priorities.keys()
344         p_list.sort(lambda a, b: a - b)
345         tmp_pn = []
346         for p in p_list:
347             tmp_pn = [priorities[p]] + tmp_pn
348
349         preferred_file = None
350
351         localdata = data.createCopy(self.configuration.data)
352         bb.data.setVar('OVERRIDES', "%s:%s" % (pn, data.getVar('OVERRIDES', localdata)), localdata)
353         bb.data.update_data(localdata)
354
355         preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, localdata, True)
356         if preferred_v:
357             m = re.match('(.*)_(.*)', preferred_v)
358             if m:
359                 preferred_v = m.group(1)
360                 preferred_r = m.group(2)
361             else:
362                 preferred_r = None
363
364             for file_set in tmp_pn:
365                 for f in file_set:
366                     pv,pr = self.status.pkg_pvpr[f]
367                     if preferred_v == pv and (preferred_r == pr or preferred_r == None):
368                         preferred_file = f
369                         preferred_ver = (pv, pr)
370                         break
371                 if preferred_file:
372                     break;
373             if preferred_r:
374                 pv_str = '%s-%s' % (preferred_v, preferred_r)
375             else:
376                 pv_str = preferred_v
377             if preferred_file is None:
378                 bb.note("preferred version %s of %s not available" % (pv_str, pn))
379             else:
380                 bb.debug(1, "selecting %s as PREFERRED_VERSION %s of package %s" % (preferred_file, pv_str, pn))
381
382         del localdata
383
384         # get highest priority file set
385         files = tmp_pn[0]
386         latest = None
387         latest_p = 0
388         latest_f = None
389         for file_name in files:
390             pv,pr = self.status.pkg_pvpr[file_name]
391             dp = self.status.pkg_dp[file_name]
392
393             if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pv, pr)) < 0)) or (dp > latest_p):
394                 latest = (pv, pr)
395                 latest_f = file_name
396                 latest_p = dp
397         if preferred_file is None:
398             preferred_file = latest_f
399             preferred_ver = latest
400
401         return (latest,latest_f,preferred_ver, preferred_file)
402
403     def showVersions( self ):
404         pkg_pn = self.status.pkg_pn
405         preferred_versions = {}
406         latest_versions = {}
407
408         # Sort by priority
409         for pn in pkg_pn.keys():
410             (last_ver,last_file,pref_ver,pref_file) = self.findBestProvider(pn)
411             preferred_versions[pn] = (pref_ver, pref_file)
412             latest_versions[pn] = (last_ver, last_file)
413
414         pkg_list = pkg_pn.keys()
415         pkg_list.sort()
416
417         for p in pkg_list:
418             pref = preferred_versions[p]
419             latest = latest_versions[p]
420
421             if pref != latest:
422                 prefstr = pref[0][0] + "-" + pref[0][1]
423             else:
424                 prefstr = ""
425
426             print "%-30s %20s %20s" % (p, latest[0][0] + "-" + latest[0][1],
427                                         prefstr)
428
429
430     def showEnvironment( self ):
431         """Show the outer or per-package environment"""
432         if self.configuration.buildfile:
433             self.cb = None
434             self.bb_cache = bb.cache.init(self)
435             try:
436                 self.configuration.data = self.bb_cache.loadDataFull(self.configuration.buildfile, self)
437             except IOError, e:
438                 fatal("Unable to read %s: %s" % ( self.configuration.buildfile, e ))
439             except Exception, e:
440                 fatal("%s" % e)
441         # emit variables and shell functions
442         try:
443             data.update_data( self.configuration.data )
444             data.emit_env(sys.__stdout__, self.configuration.data, True)
445         except Exception, e:
446             fatal("%s" % e)
447         # emit the metadata which isnt valid shell
448         for e in self.configuration.data.keys():
449             if data.getVarFlag( e, 'python', self.configuration.data ):
450                 sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, self.configuration.data, 1)))
451
452     def generateDotGraph( self, pkgs_to_build, ignore_deps ):
453         """
454         Generate two graphs one for the DEPENDS and RDEPENDS. The current
455         implementation creates crappy graphs ;)
456
457         pkgs_to_build A list of packages that needs to be built
458         ignore_deps   A list of names where processing of dependencies
459                       should be stopped. e.g. dependencies that get
460         """
461
462         def myFilterProvider( providers, item):
463             """
464             Take a list of providers and filter according to environment
465             variables. In contrast to filterProviders we do not discriminate
466             and take PREFERRED_PROVIDER into account.
467             """
468             eligible = []
469             preferred_versions = {}
470
471             # Collate providers by PN
472             pkg_pn = {}
473             for p in providers:
474                 pn = self.status.pkg_fn[p]
475                 if pn not in pkg_pn:
476                     pkg_pn[pn] = []
477                 pkg_pn[pn].append(p)
478
479             bb.debug(1, "providers for %s are: %s" % (item, pkg_pn.keys()))
480
481             for pn in pkg_pn.keys():
482                 preferred_versions[pn] = self.findBestProvider(pn, pkg_pn)[2:4]
483                 eligible.append(preferred_versions[pn][1])
484
485             for p in eligible:
486                 if p in self.build_cache_fail:
487                     bb.debug(1, "rejecting already-failed %s" % p)
488                     eligible.remove(p)
489
490             if len(eligible) == 0:
491                 bb.error("no eligible providers for %s" % item)
492                 return 0
493
494             prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % package, self.configuration.data, 1)
495
496             # try the preferred provider first
497             if prefervar:
498                 for p in elligible:
499                     if prefervar == self.status.pkg_fn[p]:
500                         bb.note("Selecting PREFERRED_PROVIDER %s" % prefervar)
501                         elligible.remove(p)
502                         elligible = [p] + elligible
503
504             return eligible
505
506
507
508
509         # try to avoid adding the same rdepends over an over again
510         seen_depends  = []
511         seen_rdepends = []
512
513
514         def add_depends(package_list):
515             """
516             Add all depends of all packages from this list
517             """
518             for package in package_list:
519                 if package in seen_depends or package in ignore_deps:
520                     continue
521
522                 seen_depends.append( package )
523                 if not package in self.status.providers:
524                     """
525                     We have not seen this name -> error in
526                     dependency handling
527                     """
528                     bb.note( "ERROR with provider: %(package)s" % vars() )
529                     print >> depends_file, '"%(package)s" -> ERROR' % vars()
530                     continue
531
532                 # get all providers for this package
533                 providers = self.status.providers[package]
534
535                 # now let us find the bestProvider for it
536                 fn = self.filterProviders(providers, package)[0]
537
538                 depends  = bb.utils.explode_deps(self.bb_cache.getVar('DEPENDS', fn, True) or "")
539                 version  = self.bb_cache.getVar('PV', fn, True ) + '-' + self.bb_cache.getVar('PR', fn, True)
540                 add_depends ( depends )
541
542                 # now create the node
543                 print >> depends_file, '"%(package)s" [label="%(package)s\\n%(version)s"]' % vars()
544
545                 depends = filter( (lambda x: x not in ignore_deps), depends )
546                 for depend in depends:
547                     print >> depends_file, '"%(package)s" -> "%(depend)s"' % vars()
548
549
550         def add_all_depends( the_depends, the_rdepends ):
551             """
552             Add both DEPENDS and RDEPENDS. RDEPENDS will get dashed
553             lines
554             """
555             package_list = the_depends + the_rdepends
556             for package in package_list:
557                 if package in seen_rdepends or package in ignore_deps:
558                     continue
559
560                 seen_rdepends.append( package )
561
562                 # let us see if this is a runtime or
563                 if package in the_depends:
564                     if not package in self.status.providers:
565                         bb.note( "ERROR with provider: %(package)s" % vars() )
566                         print >> alldepends_file, '"%(package)s" -> ERROR' % vars()
567                         continue
568
569                     providers = self.status.providers[package]
570                 elif package in the_rdepends:
571                     if len(self.getProvidersRun(package)) == 0:
572                         bb.note( "ERROR with rprovider: %(package)s" % vars() )
573                         print >> alldepends_file, '"%(package)s" -> ERROR [style="dashed"]' % vars()
574                         continue
575
576                     providers = self.getProvidersRun(package)
577                 else:
578                     print "Complete ERROR! %s" % package
579                     continue
580
581                 # now let us find the bestProvider for it
582                 fn = self.filterProviders(providers, package)[0]
583
584                 depends  = bb.utils.explode_deps(self.bb_cache.getVar('DEPENDS', fn, True) or "")
585                 if fn in self.status.rundeps and package in self.status.rundeps[fn]:
586                     rdepends= self.status.rundeps[fn][package].keys()
587                 else:
588                     rdepends = []
589                 version  = self.bb_cache.getVar('PV', fn, True ) + '-' + self.bb_cache.getVar('PR', fn, True)
590                 if package == "task-opie-applets":
591                     print fn
592                     print depends
593                     print depends
594                     print version
595
596                 add_all_depends ( depends, rdepends )
597
598                 # now create the node
599                 print >> alldepends_file, '"%(package)s" [label="%(package)s\\n%(version)s"]' % vars()
600
601                 depends = filter( (lambda x: x not in ignore_deps), depends )
602                 rdepends = filter( (lambda x: x not in ignore_deps), rdepends )
603                 for depend in depends:
604                     print >> alldepends_file, '"%(package)s" -> "%(depend)s"' % vars()
605                 for depend in rdepends:
606                     print >> alldepends_file, '"%(package)s" -> "%(depend)s" [style=dashed]' % vars()
607
608
609         # Add depends now
610         depends_file = file('depends.dot', 'w' )
611         print >> depends_file, "digraph depends {"
612         add_depends( pkgs_to_build )
613         print >> depends_file,  "}"
614
615         # Add all depends now
616         alldepends_file = file('alldepends.dot', 'w' )
617         print >> alldepends_file, "digraph alldepends {"
618         add_all_depends( pkgs_to_build, [] )
619         print >> alldepends_file, "}"
620
621     def filterProviders(self, providers, item):
622         """
623         Take a list of providers and filter/reorder according to the 
624         environment variables and previous build results
625         """
626         eligible = []
627         preferred_versions = {}
628
629         # Collate providers by PN
630         pkg_pn = {}
631         for p in providers:
632             pn = self.status.pkg_fn[p]
633             if pn not in pkg_pn:
634                 pkg_pn[pn] = []
635             pkg_pn[pn].append(p)
636
637         bb.debug(1, "providers for %s are: %s" % (item, pkg_pn.keys()))
638
639         for pn in pkg_pn.keys():
640             preferred_versions[pn] = self.findBestProvider(pn, pkg_pn)[2:4]
641             eligible.append(preferred_versions[pn][1])
642
643         for p in eligible:
644             if p in self.build_cache_fail:
645                 bb.debug(1, "rejecting already-failed %s" % p)
646                 eligible.remove(p)
647
648         if len(eligible) == 0:
649             bb.error("no eligible providers for %s" % item)
650             return 0
651
652         # look to see if one of them is already staged, or marked as preferred.
653         # if so, bump it to the head of the queue
654         for p in providers:
655             pn = self.status.pkg_fn[p]
656             pv, pr = self.status.pkg_pvpr[p]
657
658             stamp = '%s.do_populate_staging' % self.status.stamp[p]
659             if os.path.exists(stamp):
660                 (newvers, fn) = preferred_versions[pn]
661                 if not fn in eligible:
662                     # package was made ineligible by already-failed check
663                     continue
664                 oldver = "%s-%s" % (pv, pr)
665                 newver = '-'.join(newvers)
666                 if (newver != oldver):
667                     extra_chat = "%s (%s) already staged but upgrading to %s to satisfy %s" % (pn, oldver, newver, item)
668                 else:
669                     extra_chat = "Selecting already-staged %s (%s) to satisfy %s" % (pn, oldver, item)
670                 if self.configuration.verbose:
671                     bb.note("%s" % extra_chat)
672                 eligible.remove(fn)
673                 eligible = [fn] + eligible
674                 discriminated = True
675                 break
676
677         return eligible
678
679     def buildProvider( self, item , buildAllDeps , build_depends = [] ):
680         """
681         Build something to provide a named build requirement
682         (takes item names from DEPENDS namespace)
683         """
684
685         fn = None
686         discriminated = False
687
688         if not item in self.status.providers:
689             bb.error("Nothing provides dependency %s" % item)
690             bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
691             return 0
692
693         all_p = self.status.providers[item]
694
695         for p in all_p:
696             if p in self.build_cache:
697                 bb.debug(1, "already built %s in this run\n" % p)
698                 return 1
699
700         eligible = self.filterProviders(all_p, item)
701
702         if not eligible:
703             return 0
704
705         prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
706         if prefervar:
707             self.preferred[item] = prefervar
708
709         if item in self.preferred:
710             for p in eligible:
711                 pn = self.status.pkg_fn[p]
712                 if self.preferred[item] == pn:
713                     if self.configuration.verbose:
714                         bb.note("selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
715                     eligible.remove(p)
716                     eligible = [p] + eligible
717                     discriminated = True
718                     break
719
720         if len(eligible) > 1 and discriminated == False:
721             if item not in self.consider_msgs_cache:
722                 providers_list = []
723                 for fn in eligible:
724                     providers_list.append(self.status.pkg_fn[fn])
725                 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
726                 bb.note("consider defining PREFERRED_PROVIDER_%s" % item)
727                 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data))
728             self.consider_msgs_cache.append(item)
729
730
731         # run through the list until we find one that we can build
732         for fn in eligible:
733             bb.debug(2, "selecting %s to satisfy %s" % (fn, item))
734             if self.tryBuild(fn, item, buildAllDeps, build_depends + [fn]):
735                 return 1
736
737         bb.note("no buildable providers for %s" % item)
738         bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
739         return 0
740
741     def buildRProvider( self, item , buildAllDeps ):
742         """
743         Build something to provide a named runtime requirement
744         (takes item names from RDEPENDS/PACKAGES namespace)
745         """
746
747         fn = None
748         all_p = []
749         discriminated = False
750
751         if not buildAllDeps:
752             return True
753
754         all_p = self.getProvidersRun(item)
755
756         if not all_p:
757             bb.error("Nothing provides runtime dependency %s" % (item))
758             bb.event.fire(bb.event.NoProvider(item,self.configuration.data,runtime=True))
759             return False
760
761         for p in all_p:
762             if p in self.rbuild_cache:
763                 bb.debug(2, "Already built %s providing runtime %s\n" % (p,item))
764                 return True
765             if p in self.build_cache:
766                 bb.debug(2, "Already built %s but adding any further RDEPENDS for %s\n" % (p, item))
767                 return self.addRunDeps(p, item , buildAllDeps)
768
769         eligible = self.filterProviders(all_p, item)
770         if not eligible:
771             return 0
772
773         preferred = []
774         for p in eligible:
775             pn = self.status.pkg_fn[p]
776             provides = self.status.pn_provides[pn]
777             for provide in provides:
778                 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, self.configuration.data, 1)
779                 if prefervar == pn:
780                     if self.configuration.verbose:
781                         bb.note("selecting %s to satisfy runtime %s due to PREFERRED_PROVIDERS" % (pn, item))
782                     eligible.remove(p)
783                     eligible = [p] + eligible
784                     preferred.append(p)
785
786         if len(eligible) > 1 and len(preferred) == 0:
787             if item not in self.consider_msgs_cache:
788                 providers_list = []
789                 for fn in eligible:
790                     providers_list.append(self.status.pkg_fn[fn])
791                 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
792                 bb.note("consider defining a PREFERRED_PROVIDER to match runtime %s" % item)
793                 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
794             self.consider_msgs_cache.append(item)
795
796         if len(preferred) > 1:
797             if item not in self.consider_msgs_cache:
798                 providers_list = []
799                 for fn in preferred:
800                     providers_list.append(self.status.pkg_fn[fn])
801                 bb.note("multiple preferred providers are available (%s);" % ", ".join(providers_list))
802                 bb.note("consider defining only one PREFERRED_PROVIDER to match runtime %s" % item)
803                 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
804             self.consider_msgs_cache.append(item)
805
806         # run through the list until we find one that we can build
807         for fn in eligible:
808             bb.debug(2, "selecting %s to satisfy runtime %s" % (fn, item))
809             if self.tryBuild(fn, item, buildAllDeps):
810                 return True
811
812         bb.error("No buildable providers for runtime %s" % item)
813         bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
814         return False
815
816     def getProvidersRun(self, rdepend):
817         """
818         Return any potential providers of runtime rdepend
819         """
820         rproviders = []
821
822         if rdepend in self.status.rproviders:
823             rproviders += self.status.rproviders[rdepend]
824
825         if rdepend in self.status.packages:
826             rproviders += self.status.packages[rdepend]
827
828         if rproviders:
829             return rproviders
830
831         # Only search dynamic packages if we can't find anything in other variables
832         for pattern in self.status.packages_dynamic:
833             regexp = re.compile(pattern)
834             if regexp.match(rdepend):
835                 rproviders += self.status.packages_dynamic[pattern]
836
837         return rproviders
838
839     def addRunDeps(self , fn, item , buildAllDeps):
840         """
841         Add any runtime dependencies of runtime item provided by fn 
842         as long as item has't previously been processed by this function.
843         """
844
845         if item in self.rbuild_cache:
846             return True
847
848         if not buildAllDeps:
849             return True
850
851         rdepends = []
852         self.rbuild_cache.append(item)
853
854         if fn in self.status.rundeps and item in self.status.rundeps[fn]:
855             rdepends += self.status.rundeps[fn][item].keys()
856         if fn in self.status.runrecs and item in self.status.runrecs[fn]:
857             rdepends += self.status.runrecs[fn][item].keys()
858
859         bb.debug(2, "Additional runtime dependencies for %s are: %s" % (item, " ".join(rdepends)))
860
861         for rdepend in rdepends:
862             if rdepend in self.status.ignored_dependencies:
863                 continue
864             if not self.buildRProvider(rdepend, buildAllDeps):
865                 return False
866         return True
867
868     def buildDepgraph( self ):
869         all_depends = self.status.all_depends
870         pn_provides = self.status.pn_provides
871
872         localdata = data.createCopy(self.configuration.data)
873         bb.data.update_data(localdata)
874
875         def calc_bbfile_priority(filename):
876             for (regex, pri) in self.status.bbfile_config_priorities:
877                 if regex.match(filename):
878                     return pri
879             return 0
880
881         # Handle PREFERRED_PROVIDERS
882         for p in (bb.data.getVar('PREFERRED_PROVIDERS', localdata, 1) or "").split():
883             (providee, provider) = p.split(':')
884             if providee in self.preferred and self.preferred[providee] != provider:
885                 bb.error("conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.preferred[providee]))
886             self.preferred[providee] = provider
887
888         # Calculate priorities for each file
889         for p in self.status.pkg_fn.keys():
890             self.status.bbfile_priority[p] = calc_bbfile_priority(p)
891
892     def buildWorldTargetList(self):
893         """
894          Build package list for "bitbake world"
895         """
896         all_depends = self.status.all_depends
897         pn_provides = self.status.pn_provides
898         bb.debug(1, "collating packages for \"world\"")
899         for f in self.status.possible_world:
900             terminal = True
901             pn = self.status.pkg_fn[f]
902
903             for p in pn_provides[pn]:
904                 if p.startswith('virtual/'):
905                     bb.debug(2, "skipping %s due to %s provider starting with virtual/" % (f, p))
906                     terminal = False
907                     break
908                 for pf in self.status.providers[p]:
909                     if self.status.pkg_fn[pf] != pn:
910                         bb.debug(2, "skipping %s due to both us and %s providing %s" % (f, pf, p))
911                         terminal = False
912                         break
913             if terminal:
914                 self.status.world_target.add(pn)
915
916             # drop reference count now
917             self.status.possible_world = None
918             self.status.all_depends    = None
919
920     def myProgressCallback( self, x, y, f, bb_cache, from_cache ):
921         # feed the status with new input
922
923         self.status.handle_bb_data(f, bb_cache, from_cache)
924
925         if bbdebug > 0:
926             return
927         if os.isatty(sys.stdout.fileno()):
928             sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
929             sys.stdout.flush()
930         else:
931             if x == 1:
932                 sys.stdout.write("Parsing .bb files, please wait...")
933                 sys.stdout.flush()
934             if x == y:
935                 sys.stdout.write("done.")
936                 sys.stdout.flush()
937
938     def interactiveMode( self ):
939         """Drop off into a shell"""
940         try:
941             from bb import shell
942         except ImportError, details:
943             bb.fatal("Sorry, shell not available (%s)" % details )
944         else:
945             bb.data.update_data( self.configuration.data )
946             shell.start( self )
947             sys.exit( 0 )
948
949     def parseConfigurationFile( self, afile ):
950         try:
951             self.configuration.data = bb.parse.handle( afile, self.configuration.data )
952
953             # Add the handlers we inherited by INHERIT
954             # we need to do this manually as it is not guranteed
955             # we will pick up these classes... as we only INHERIT
956             # on .inc and .bb files but not on .conf
957             data = bb.data.createCopy( self.configuration.data )
958             inherits  = ["base"] + (bb.data.getVar('INHERIT', data, True ) or "").split()
959             for inherit in inherits:
960                 data = bb.parse.handle( os.path.join('classes', '%s.bbclass' % inherit ), data, True )
961
962             # FIXME: This assumes that we included at least one .inc file
963             for var in bb.data.keys(data):
964                 if bb.data.getVarFlag(var, 'handler', data):
965                     bb.event.register(var,bb.data.getVar(var, data))
966
967         except IOError:
968             bb.fatal( "Unable to open %s" % afile )
969         except bb.parse.ParseError, details:
970             bb.fatal( "Unable to parse %s (%s)" % (afile, details) )
971
972     def handleCollections( self, collections ):
973         """Handle collections"""
974         if collections:
975             collection_list = collections.split()
976             for c in collection_list:
977                 regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1)
978                 if regex == None:
979                     bb.error("BBFILE_PATTERN_%s not defined" % c)
980                     continue
981                 priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1)
982                 if priority == None:
983                     bb.error("BBFILE_PRIORITY_%s not defined" % c)
984                     continue
985                 try:
986                     cre = re.compile(regex)
987                 except re.error:
988                     bb.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
989                     continue
990                 try:
991                     pri = int(priority)
992                     self.status.bbfile_config_priorities.append((cre, pri))
993                 except ValueError:
994                     bb.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
995
996
997     def cook( self, configuration, args ):
998         """
999         We are building stuff here. We do the building
1000         from here. By default we try to execute task
1001         build.
1002         """
1003
1004         self.configuration = configuration
1005
1006         if not self.configuration.cmd:
1007             self.configuration.cmd = "build"
1008
1009         if self.configuration.debug:
1010             bb.debug_level = self.configuration.debug
1011
1012         self.configuration.data = bb.data.init()
1013
1014         for f in self.configuration.file:
1015             self.parseConfigurationFile( f )
1016
1017         self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
1018
1019
1020         #
1021         # Special updated configuration we use for firing events
1022         #
1023         self.configuration.event_data = bb.data.createCopy(self.configuration.data)
1024         bb.data.update_data(self.configuration.event_data)
1025
1026         if self.configuration.show_environment:
1027             self.showEnvironment()
1028             sys.exit( 0 )
1029
1030         # inject custom variables
1031         if not bb.data.getVar("BUILDNAME", self.configuration.data):
1032             bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
1033         bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data)
1034
1035         buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
1036
1037         if self.configuration.interactive:
1038             self.interactiveMode()
1039
1040         if self.configuration.buildfile is not None:
1041             bf = os.path.abspath( self.configuration.buildfile )
1042             try:
1043                 bbfile_data = bb.parse.handle(bf, self.configuration.data)
1044             except IOError:
1045                 bb.fatal("Unable to open %s" % bf)
1046
1047             item = bb.data.getVar('PN', bbfile_data, 1)
1048             try:
1049                 self.tryBuildPackage( bf, item, bbfile_data )
1050             except bb.build.EventException:
1051                 bb.error( "Build of '%s' failed" % item )
1052
1053             sys.exit( self.stats.show() )
1054
1055         # initialise the parsing status now we know we will need deps
1056         self.status = BBParsingStatus()
1057
1058         ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
1059         self.status.ignored_dependencies = Set( ignore.split() )
1060
1061         self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
1062
1063         pkgs_to_build = None
1064         if args:
1065             if not pkgs_to_build:
1066                 pkgs_to_build = []
1067             pkgs_to_build.extend(args)
1068         if not pkgs_to_build:
1069                 bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
1070                 if bbpkgs:
1071                         pkgs_to_build = bbpkgs.split()
1072         if not pkgs_to_build and not self.configuration.show_versions \
1073                              and not self.configuration.interactive \
1074                              and not self.configuration.show_environment:
1075                 print "Nothing to do.  Use 'bitbake world' to build everything, or run 'bitbake --help'"
1076                 print "for usage information."
1077                 sys.exit(0)
1078
1079         # Import Psyco if available and not disabled
1080         if not self.configuration.disable_psyco:
1081             try:
1082                 import psyco
1083             except ImportError:
1084                 if bbdebug == 0:
1085                     bb.note("Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
1086             else:
1087                 psyco.bind( self.collect_bbfiles )
1088         else:
1089             bb.note("You have disabled Psyco. This decreases performance.")
1090
1091         try:
1092             bb.debug(1, "collecting .bb files")
1093             self.collect_bbfiles( self.myProgressCallback )
1094             bb.debug(1, "parsing complete")
1095             if bbdebug == 0:
1096                 print
1097             if self.configuration.parse_only:
1098                 print "Requested parsing .bb files only.  Exiting."
1099                 return
1100
1101
1102             self.buildDepgraph()
1103
1104             if self.configuration.show_versions:
1105                 self.showVersions()
1106                 sys.exit( 0 )
1107             if 'world' in pkgs_to_build:
1108                 self.buildWorldTargetList()
1109                 pkgs_to_build.remove('world')
1110                 for t in self.status.world_target:
1111                     pkgs_to_build.append(t)
1112
1113             if self.configuration.dot_graph:
1114                 self.generateDotGraph( pkgs_to_build, self.configuration.ignored_dot_deps )
1115                 sys.exit( 0 )
1116
1117
1118             bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.event_data))
1119
1120             failures = 0
1121             for k in pkgs_to_build:
1122                 failed = False
1123                 try:
1124                     if self.buildProvider( k , False ) == 0:
1125                         # already diagnosed
1126                         failed = True
1127                 except bb.build.EventException:
1128                     bb.error("Build of " + k + " failed")
1129                     failed = True
1130
1131                 if failed:
1132                     failures += failures
1133                     if self.configuration.abort:
1134                         sys.exit(1)
1135
1136             bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.event_data, failures))
1137
1138             sys.exit( self.stats.show() )
1139
1140         except KeyboardInterrupt:
1141             print "\nNOTE: KeyboardInterrupt - Build not completed."
1142             sys.exit(1)
1143
1144     def get_bbfiles( self, path = os.getcwd() ):
1145         """Get list of default .bb files by reading out the current directory"""
1146         contents = os.listdir(path)
1147         bbfiles = []
1148         for f in contents:
1149             (root, ext) = os.path.splitext(f)
1150             if ext == ".bb":
1151                 bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
1152         return bbfiles
1153
1154     def find_bbfiles( self, path ):
1155         """Find all the .bb files in a directory (uses find)"""
1156         findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
1157         try:
1158             finddata = os.popen(findcmd)
1159         except OSError:
1160             return []
1161         return finddata.readlines()
1162
1163     def collect_bbfiles( self, progressCallback ):
1164         """Collect all available .bb build files"""
1165         self.cb = progressCallback
1166         parsed, cached, skipped, masked = 0, 0, 0, 0
1167         self.bb_cache = bb.cache.init(self)
1168
1169         files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
1170         data.setVar("BBFILES", " ".join(files), self.configuration.data)
1171
1172         if not len(files):
1173             files = self.get_bbfiles()
1174
1175         if not len(files):
1176             bb.error("no files to build.")
1177
1178         newfiles = []
1179         for f in files:
1180             if os.path.isdir(f):
1181                 dirfiles = self.find_bbfiles(f)
1182                 if dirfiles:
1183                     newfiles += dirfiles
1184                     continue
1185             newfiles += glob.glob(f) or [ f ]
1186
1187         bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1) or ""
1188         try:
1189             bbmask_compiled = re.compile(bbmask)
1190         except sre_constants.error:
1191             bb.fatal("BBMASK is not a valid regular expression.")
1192
1193         for i in xrange( len( newfiles ) ):
1194             f = newfiles[i]
1195             if bbmask and bbmask_compiled.search(f):
1196                 bb.debug(1, "bbmake: skipping %s" % f)
1197                 masked += 1
1198                 continue
1199             debug(1, "bbmake: parsing %s" % f)
1200
1201             # read a file's metadata
1202             try:
1203                 fromCache, skip = self.bb_cache.loadData(f, self)
1204                 if skip:
1205                     skipped += 1
1206                     #bb.note("Skipping %s" % f)
1207                     self.bb_cache.skip(f)
1208                     continue
1209                 elif fromCache: cached += 1
1210                 else: parsed += 1
1211                 deps = None
1212
1213                 # allow metadata files to add items to BBFILES
1214                 #data.update_data(self.pkgdata[f])
1215                 addbbfiles = self.bb_cache.getVar('BBFILES', f, False) or None
1216                 if addbbfiles:
1217                     for aof in addbbfiles.split():
1218                         if not files.count(aof):
1219                             if not os.path.isabs(aof):
1220                                 aof = os.path.join(os.path.dirname(f),aof)
1221                             files.append(aof)
1222
1223                 # now inform the caller
1224                 if self.cb is not None:
1225                     self.cb( i + 1, len( newfiles ), f, self.bb_cache, fromCache )
1226
1227             except IOError, e:
1228                 self.bb_cache.remove(f)
1229                 bb.error("opening %s: %s" % (f, e))
1230                 pass
1231             except KeyboardInterrupt:
1232                 self.bb_cache.sync()
1233                 raise
1234             except Exception, e:
1235                 self.bb_cache.remove(f)
1236                 bb.error("%s while parsing %s" % (e, f))
1237             except:
1238                 self.bb_cache.remove(f)
1239                 raise
1240
1241         if self.cb is not None:
1242             print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ),
1243
1244         self.bb_cache.sync()
1245
1246 #============================================================================#
1247 # main
1248 #============================================================================#
1249
1250 def main():
1251     parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
1252     usage = """%prog [options] [package ...]
1253
1254 Executes the specified task (default is 'build') for a given set of BitBake files.
1255 It expects that BBFILES is defined, which is a space seperated list of files to
1256 be executed.  BBFILES does support wildcards.
1257 Default BBFILES are the .bb files in the current directory.""" )
1258
1259     parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
1260                action = "store", dest = "buildfile", default = None )
1261
1262     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.",
1263                action = "store_false", dest = "abort", default = True )
1264
1265     parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
1266                action = "store_true", dest = "force", default = False )
1267
1268     parser.add_option( "-i", "--interactive", help = "drop into the interactive mode also called the BitBake shell.",
1269                action = "store_true", dest = "interactive", default = False )
1270
1271     parser.add_option( "-c", "--cmd", help = "Specify task to execute. Note that this only executes the specified task for the providee and the packages it depends on, i.e. 'compile' does not implicitly call stage for the dependencies (IOW: use only if you know what you are doing). Depending on the base.bbclass a listtaks tasks is defined and will show available tasks",
1272                action = "store", dest = "cmd", default = "build" )
1273
1274     parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
1275                action = "append", dest = "file", default = [] )
1276
1277     parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
1278                action = "store_true", dest = "verbose", default = False )
1279
1280     parser.add_option( "-D", "--debug", help = "Increase the debug level. You can specify this more than once.",
1281                action = "count", dest="debug", default = 0)
1282
1283     parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
1284                action = "store_true", dest = "dry_run", default = False )
1285
1286     parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
1287                action = "store_true", dest = "parse_only", default = False )
1288
1289     parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
1290                action = "store_true", dest = "disable_psyco", default = False )
1291
1292     parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
1293                action = "store_true", dest = "show_versions", default = False )
1294
1295     parser.add_option( "-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
1296                action = "store_true", dest = "show_environment", default = False )
1297
1298     parser.add_option( "-g", "--graphviz", help = "emit the dependency trees of the specified packages in the dot syntax",
1299                 action = "store_true", dest = "dot_graph", default = False )
1300     parser.add_option( "-I", "--ignore-deps", help = """Stop processing at the given list of dependencies when generating dependency graphs. This can help to make the graph more appealing""",
1301                 action = "append", dest = "ignored_dot_deps", default = [] )
1302
1303
1304     options, args = parser.parse_args( sys.argv )
1305
1306     cooker = BBCooker()
1307     cooker.cook( BBConfiguration( options ), args[1:] )
1308
1309
1310
1311 if __name__ == "__main__":
1312     print """WARNING, WARNING, WARNING
1313 This is a Bitbake from the Unstable/Development Branch.
1314 You might want to use the bitbake-1.4 stable branch (if you are not a BitBake developer or tester). I'm going to sleep 5 seconds now to make sure you see that."""
1315     import time
1316     time.sleep(5)
1317     main()