bitbake/bin/bitbake: Make sure we add all handlers from INHERIT
[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 ):
453         """
454         Generate two graphs one for the DEPENDS and RDEPENDS. The current
455         implementation creates crappy graphs ;)
456         """
457
458         rdepends_file = file('rdepends.dot', 'w' )
459         depends_file  = file('depends.dot', 'w' )
460
461
462         # setup the graphs
463         print >> depends_file, "digraph depends {"
464         print >> rdepends_file, "digraph rdepends {"
465
466
467         # try to avoid adding the same rdepends over an over again
468         seen_depends   = {}
469         seen_rdepends =  {}
470
471         added_depends_error = False
472
473         def add_depends(package_list):
474             """
475             Add all depends of all packages from this list
476             """
477             for package in package_list:
478                 if package in seen_depends:
479                     continue
480                 else:
481                     seen_depends[package] = 1
482
483                 if not package in self.status.providers:
484                     """
485                     We have not seen this name -> error in
486                     dependency handling
487                     """
488                     print >> depends_file, '"%(package)s" -> ERROR' % vars()
489                     continue
490
491                 # get all providers for this package
492                 providers = self.status.providers[package]
493
494                 # now let us find the bestProvider for it
495                 elligible = self.filterProviders(providers, package)
496                 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % package, self.configuration.data, 1)
497
498                 # try the preferred provider first
499                 if prefervar:
500                     for p in elligible:
501                         if prefervar == self.status.pkg_fn[p]:
502                             bb.note("Selecting PREFERRED_PROVIDER %s" % prefervar)
503                             elligible.remove(p)
504                             elligible = [p] + elligible
505
506                 fn = elligible[0] 
507                 depends  = bb.utils.explode_deps(self.bb_cache.getVar('DEPENDS', fn, True) or "")
508                 rdepends = bb.utils.explode_deps(self.bb_cache.getVar('RDEPENDS', fn, True) or "")
509                 add_depends( depends )
510                 add_rdepends( rdepends )
511
512                 for depend in depends:
513                     print >> depends_file, '"%(package)s" -> "%(depend)s"' % vars()
514
515         def add_rdepends(package_list):
516             """
517             for each package of the package_list
518             we will see if we have handled it already
519             """
520             pass
521         
522         # start with the initial list
523         add_depends( pkgs_to_build )
524         add_rdepends( pkgs_to_build )
525
526         # finish it up
527         print >> depends_file,  "}"
528         print >> rdepends_file, "}"
529
530     def filterProviders(self, providers, item):
531         """
532         Take a list of providers and filter/reorder according to the 
533         environment variables and previous build results
534         """
535         eligible = []
536         preferred_versions = {}
537
538         # Collate providers by PN
539         pkg_pn = {}
540         for p in providers:
541             pn = self.status.pkg_fn[p]
542             if pn not in pkg_pn:
543                 pkg_pn[pn] = []
544             pkg_pn[pn].append(p)
545
546         bb.debug(1, "providers for %s are: %s" % (item, pkg_pn.keys()))
547
548         for pn in pkg_pn.keys():
549             preferred_versions[pn] = self.findBestProvider(pn, pkg_pn)[2:4]
550             eligible.append(preferred_versions[pn][1])
551
552         for p in eligible:
553             if p in self.build_cache_fail:
554                 bb.debug(1, "rejecting already-failed %s" % p)
555                 eligible.remove(p)
556
557         if len(eligible) == 0:
558             bb.error("no eligible providers for %s" % item)
559             return 0
560
561         # look to see if one of them is already staged, or marked as preferred.
562         # if so, bump it to the head of the queue
563         for p in providers:
564             pn = self.status.pkg_fn[p]
565             pv, pr = self.status.pkg_pvpr[p]
566
567             stamp = '%s.do_populate_staging' % self.status.stamp[p]
568             if os.path.exists(stamp):
569                 (newvers, fn) = preferred_versions[pn]
570                 if not fn in eligible:
571                     # package was made ineligible by already-failed check
572                     continue
573                 oldver = "%s-%s" % (pv, pr)
574                 newver = '-'.join(newvers)
575                 if (newver != oldver):
576                     extra_chat = "%s (%s) already staged but upgrading to %s to satisfy %s" % (pn, oldver, newver, item)
577                 else:
578                     extra_chat = "Selecting already-staged %s (%s) to satisfy %s" % (pn, oldver, item)
579                 if self.configuration.verbose:
580                     bb.note("%s" % extra_chat)
581                 eligible.remove(fn)
582                 eligible = [fn] + eligible
583                 discriminated = True
584                 break
585
586         return eligible
587
588     def buildProvider( self, item , buildAllDeps , build_depends = [] ):
589         """
590         Build something to provide a named build requirement
591         (takes item names from DEPENDS namespace)
592         """
593
594         fn = None
595         discriminated = False
596
597         if not item in self.status.providers:
598             bb.error("Nothing provides dependency %s" % item)
599             bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
600             return 0
601
602         all_p = self.status.providers[item]
603
604         for p in all_p:
605             if p in self.build_cache:
606                 bb.debug(1, "already built %s in this run\n" % p)
607                 return 1
608
609         eligible = self.filterProviders(all_p, item)
610
611         if not eligible:
612             return 0
613
614         prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
615         if prefervar:
616             self.preferred[item] = prefervar
617
618         if item in self.preferred:
619             for p in eligible:
620                 pn = self.status.pkg_fn[p]
621                 if self.preferred[item] == pn:
622                     if self.configuration.verbose:
623                         bb.note("selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
624                     eligible.remove(p)
625                     eligible = [p] + eligible
626                     discriminated = True
627                     break
628
629         if len(eligible) > 1 and discriminated == False:
630             if item not in self.consider_msgs_cache:
631                 providers_list = []
632                 for fn in eligible:
633                     providers_list.append(self.status.pkg_fn[fn])
634                 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
635                 bb.note("consider defining PREFERRED_PROVIDER_%s" % item)
636                 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data))
637             self.consider_msgs_cache.append(item)
638
639
640         # run through the list until we find one that we can build
641         for fn in eligible:
642             bb.debug(2, "selecting %s to satisfy %s" % (fn, item))
643             if self.tryBuild(fn, item, buildAllDeps, build_depends + [fn]):
644                 return 1
645
646         bb.note("no buildable providers for %s" % item)
647         bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
648         return 0
649
650     def buildRProvider( self, item , buildAllDeps ):
651         """
652         Build something to provide a named runtime requirement
653         (takes item names from RDEPENDS/PACKAGES namespace)
654         """
655
656         fn = None
657         all_p = []
658         discriminated = False
659
660         if not buildAllDeps:
661             return True
662
663         all_p = self.getProvidersRun(item)
664
665         if not all_p:
666             bb.error("Nothing provides runtime dependency %s" % (item))
667             bb.event.fire(bb.event.NoProvider(item,self.configuration.data,runtime=True))
668             return False
669
670         for p in all_p:
671             if p in self.rbuild_cache:
672                 bb.debug(2, "Already built %s providing runtime %s\n" % (p,item))
673                 return True
674             if p in self.build_cache:
675                 bb.debug(2, "Already built %s but adding any further RDEPENDS for %s\n" % (p, item))
676                 return self.addRunDeps(p, item , buildAllDeps)
677
678         eligible = self.filterProviders(all_p, item)
679         if not eligible:
680             return 0
681
682         preferred = []
683         for p in eligible:
684             pn = self.status.pkg_fn[p]
685             provides = self.status.pn_provides[pn]
686             for provide in provides:
687                 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, self.configuration.data, 1)
688                 if prefervar == pn:
689                     if self.configuration.verbose:
690                         bb.note("selecting %s to satisfy runtime %s due to PREFERRED_PROVIDERS" % (pn, item))
691                     eligible.remove(p)
692                     eligible = [p] + eligible
693                     preferred.append(p)
694
695         if len(eligible) > 1 and len(preferred) == 0:
696             if item not in self.consider_msgs_cache:
697                 providers_list = []
698                 for fn in eligible:
699                     providers_list.append(self.status.pkg_fn[fn])
700                 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
701                 bb.note("consider defining a PREFERRED_PROVIDER to match runtime %s" % item)
702                 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
703             self.consider_msgs_cache.append(item)
704
705         if len(preferred) > 1:
706             if item not in self.consider_msgs_cache:
707                 providers_list = []
708                 for fn in preferred:
709                     providers_list.append(self.status.pkg_fn[fn])
710                 bb.note("multiple preferred providers are available (%s);" % ", ".join(providers_list))
711                 bb.note("consider defining only one PREFERRED_PROVIDER to match runtime %s" % item)
712                 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
713             self.consider_msgs_cache.append(item)
714
715         # run through the list until we find one that we can build
716         for fn in eligible:
717             bb.debug(2, "selecting %s to satisfy runtime %s" % (fn, item))
718             if self.tryBuild(fn, item, buildAllDeps):
719                 return True
720
721         bb.error("No buildable providers for runtime %s" % item)
722         bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
723         return False
724
725     def getProvidersRun(self, rdepend):
726         """
727         Return any potential providers of runtime rdepend
728         """
729         rproviders = []
730
731         if rdepend in self.status.rproviders:
732             rproviders += self.status.rproviders[rdepend]
733
734         if rdepend in self.status.packages:
735             rproviders += self.status.packages[rdepend]
736
737         if rproviders:
738             return rproviders
739
740         # Only search dynamic packages if we can't find anything in other variables
741         for pattern in self.status.packages_dynamic:
742             regexp = re.compile(pattern)
743             if regexp.match(rdepend):
744                 rproviders += self.status.packages_dynamic[pattern]
745
746         return rproviders
747
748     def addRunDeps(self , fn, item , buildAllDeps):
749         """
750         Add any runtime dependencies of runtime item provided by fn 
751         as long as item has't previously been processed by this function.
752         """
753
754         if item in self.rbuild_cache:
755             return True
756
757         if not buildAllDeps:
758             return True
759
760         rdepends = []
761         self.rbuild_cache.append(item)
762
763         if fn in self.status.rundeps and item in self.status.rundeps[fn]:
764             rdepends += self.status.rundeps[fn][item].keys()
765         if fn in self.status.runrecs and item in self.status.runrecs[fn]:
766             rdepends += self.status.runrecs[fn][item].keys()
767
768         bb.debug(2, "Additional runtime dependencies for %s are: %s" % (item, " ".join(rdepends)))
769
770         for rdepend in rdepends:
771             if rdepend in self.status.ignored_dependencies:
772                 continue
773             if not self.buildRProvider(rdepend, buildAllDeps):
774                 return False
775         return True
776
777     def buildDepgraph( self ):
778         all_depends = self.status.all_depends
779         pn_provides = self.status.pn_provides
780
781         localdata = data.createCopy(self.configuration.data)
782         bb.data.update_data(localdata)
783
784         def calc_bbfile_priority(filename):
785             for (regex, pri) in self.status.bbfile_config_priorities:
786                 if regex.match(filename):
787                     return pri
788             return 0
789
790         # Handle PREFERRED_PROVIDERS
791         for p in (bb.data.getVar('PREFERRED_PROVIDERS', localdata, 1) or "").split():
792             (providee, provider) = p.split(':')
793             if providee in self.preferred and self.preferred[providee] != provider:
794                 bb.error("conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.preferred[providee]))
795             self.preferred[providee] = provider
796
797         # Calculate priorities for each file
798         for p in self.status.pkg_fn.keys():
799             self.status.bbfile_priority[p] = calc_bbfile_priority(p)
800
801     def buildWorldTargetList(self):
802         """
803          Build package list for "bitbake world"
804         """
805         all_depends = self.status.all_depends
806         pn_provides = self.status.pn_provides
807         bb.debug(1, "collating packages for \"world\"")
808         for f in self.status.possible_world:
809             terminal = True
810             pn = self.status.pkg_fn[f]
811
812             for p in pn_provides[pn]:
813                 if p.startswith('virtual/'):
814                     bb.debug(2, "skipping %s due to %s provider starting with virtual/" % (f, p))
815                     terminal = False
816                     break
817                 for pf in self.status.providers[p]:
818                     if self.status.pkg_fn[pf] != pn:
819                         bb.debug(2, "skipping %s due to both us and %s providing %s" % (f, pf, p))
820                         terminal = False
821                         break
822             if terminal:
823                 self.status.world_target.add(pn)
824
825             # drop reference count now
826             self.status.possible_world = None
827             self.status.all_depends    = None
828
829     def myProgressCallback( self, x, y, f, bb_cache, from_cache ):
830         # feed the status with new input
831
832         self.status.handle_bb_data(f, bb_cache, from_cache)
833
834         if bbdebug > 0:
835             return
836         if os.isatty(sys.stdout.fileno()):
837             sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
838             sys.stdout.flush()
839         else:
840             if x == 1:
841                 sys.stdout.write("Parsing .bb files, please wait...")
842                 sys.stdout.flush()
843             if x == y:
844                 sys.stdout.write("done.")
845                 sys.stdout.flush()
846
847     def interactiveMode( self ):
848         """Drop off into a shell"""
849         try:
850             from bb import shell
851         except ImportError, details:
852             bb.fatal("Sorry, shell not available (%s)" % details )
853         else:
854             bb.data.update_data( self.configuration.data )
855             shell.start( self )
856             sys.exit( 0 )
857
858     def parseConfigurationFile( self, afile ):
859         try:
860             self.configuration.data = bb.parse.handle( afile, self.configuration.data )
861
862             # Add the handlers we inherited by INHERIT
863             # we need to do this manually as it is not guranteed
864             # we will pick up these classes... as we only INHERIT
865             # on .inc and .bb files but not on .conf
866             data = bb.data.createCopy( self.configuration.data )
867             inherits  = ["base"] + (bb.data.getVar('INHERIT', data, True ) or "").split()
868             for inherit in inherits:
869                 data = bb.parse.handle( os.path.join('classes', '%s.bbclass' % inherit ), data, True )
870
871             # FIXME: This assumes that we included at least one .inc file
872             for var in bb.data.keys(data):
873                 if bb.data.getVarFlag(var, 'handler', data):
874                     bb.event.register(var,bb.data.getVar(var, data))
875
876         except IOError:
877             bb.fatal( "Unable to open %s" % afile )
878         except bb.parse.ParseError, details:
879             bb.fatal( "Unable to parse %s (%s)" % (afile, details) )
880
881     def handleCollections( self, collections ):
882         """Handle collections"""
883         if collections:
884             collection_list = collections.split()
885             for c in collection_list:
886                 regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1)
887                 if regex == None:
888                     bb.error("BBFILE_PATTERN_%s not defined" % c)
889                     continue
890                 priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1)
891                 if priority == None:
892                     bb.error("BBFILE_PRIORITY_%s not defined" % c)
893                     continue
894                 try:
895                     cre = re.compile(regex)
896                 except re.error:
897                     bb.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
898                     continue
899                 try:
900                     pri = int(priority)
901                     self.status.bbfile_config_priorities.append((cre, pri))
902                 except ValueError:
903                     bb.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
904
905
906     def cook( self, configuration, args ):
907         """
908         We are building stuff here. We do the building
909         from here. By default we try to execute task
910         build.
911         """
912
913         self.configuration = configuration
914
915         if not self.configuration.cmd:
916             self.configuration.cmd = "build"
917
918         if self.configuration.debug:
919             bb.debug_level = self.configuration.debug
920
921         self.configuration.data = bb.data.init()
922
923         for f in self.configuration.file:
924             self.parseConfigurationFile( f )
925
926         self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
927
928
929         #
930         # Special updated configuration we use for firing events
931         #
932         self.configuration.event_data = bb.data.createCopy(self.configuration.data)
933         bb.data.update_data(self.configuration.event_data)
934
935         if self.configuration.show_environment:
936             self.showEnvironment()
937             sys.exit( 0 )
938
939         # inject custom variables
940         if not bb.data.getVar("BUILDNAME", self.configuration.data):
941             bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
942         bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data)
943
944         buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
945
946         if self.configuration.interactive:
947             self.interactiveMode()
948
949         if self.configuration.buildfile is not None:
950             bf = os.path.abspath( self.configuration.buildfile )
951             try:
952                 bbfile_data = bb.parse.handle(bf, self.configuration.data)
953             except IOError:
954                 bb.fatal("Unable to open %s" % bf)
955
956             item = bb.data.getVar('PN', bbfile_data, 1)
957             try:
958                 self.tryBuildPackage( bf, item, bbfile_data )
959             except bb.build.EventException:
960                 bb.error( "Build of '%s' failed" % item )
961
962             sys.exit( self.stats.show() )
963
964         # initialise the parsing status now we know we will need deps
965         self.status = BBParsingStatus()
966
967         ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
968         self.status.ignored_dependencies = Set( ignore.split() )
969
970         self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
971
972         pkgs_to_build = None
973         if args:
974             if not pkgs_to_build:
975                 pkgs_to_build = []
976             pkgs_to_build.extend(args)
977         if not pkgs_to_build:
978                 bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
979                 if bbpkgs:
980                         pkgs_to_build = bbpkgs.split()
981         if not pkgs_to_build and not self.configuration.show_versions \
982                              and not self.configuration.interactive \
983                              and not self.configuration.show_environment:
984                 print "Nothing to do.  Use 'bitbake world' to build everything, or run 'bitbake --help'"
985                 print "for usage information."
986                 sys.exit(0)
987
988         # Import Psyco if available and not disabled
989         if not self.configuration.disable_psyco:
990             try:
991                 import psyco
992             except ImportError:
993                 if bbdebug == 0:
994                     bb.note("Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
995             else:
996                 psyco.bind( self.collect_bbfiles )
997         else:
998             bb.note("You have disabled Psyco. This decreases performance.")
999
1000         try:
1001             bb.debug(1, "collecting .bb files")
1002             self.collect_bbfiles( self.myProgressCallback )
1003             bb.debug(1, "parsing complete")
1004             if bbdebug == 0:
1005                 print
1006             if self.configuration.parse_only:
1007                 print "Requested parsing .bb files only.  Exiting."
1008                 return
1009
1010
1011             self.buildDepgraph()
1012
1013             if self.configuration.show_versions:
1014                 self.showVersions()
1015                 sys.exit( 0 )
1016             if 'world' in pkgs_to_build:
1017                 self.buildWorldTargetList()
1018                 pkgs_to_build.remove('world')
1019                 for t in self.status.world_target:
1020                     pkgs_to_build.append(t)
1021     
1022             if self.configuration.dot_graph:
1023                 self.generateDotGraph( pkgs_to_build )
1024                 sys.exit( 0 )
1025
1026
1027             bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.event_data))
1028
1029             failures = 0
1030             for k in pkgs_to_build:
1031                 failed = False
1032                 try:
1033                     if self.buildProvider( k , False ) == 0:
1034                         # already diagnosed
1035                         failed = True
1036                 except bb.build.EventException:
1037                     bb.error("Build of " + k + " failed")
1038                     failed = True
1039
1040                 if failed:
1041                     failures += failures
1042                     if self.configuration.abort:
1043                         sys.exit(1)
1044
1045             bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.event_data, failures))
1046
1047             sys.exit( self.stats.show() )
1048
1049         except KeyboardInterrupt:
1050             print "\nNOTE: KeyboardInterrupt - Build not completed."
1051             sys.exit(1)
1052
1053     def get_bbfiles( self, path = os.getcwd() ):
1054         """Get list of default .bb files by reading out the current directory"""
1055         contents = os.listdir(path)
1056         bbfiles = []
1057         for f in contents:
1058             (root, ext) = os.path.splitext(f)
1059             if ext == ".bb":
1060                 bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
1061         return bbfiles
1062
1063     def find_bbfiles( self, path ):
1064         """Find all the .bb files in a directory (uses find)"""
1065         findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
1066         try:
1067             finddata = os.popen(findcmd)
1068         except OSError:
1069             return []
1070         return finddata.readlines()
1071
1072     def collect_bbfiles( self, progressCallback ):
1073         """Collect all available .bb build files"""
1074         self.cb = progressCallback
1075         parsed, cached, skipped, masked = 0, 0, 0, 0
1076         self.bb_cache = bb.cache.init(self)
1077
1078         files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
1079         data.setVar("BBFILES", " ".join(files), self.configuration.data)
1080
1081         if not len(files):
1082             files = self.get_bbfiles()
1083
1084         if not len(files):
1085             bb.error("no files to build.")
1086
1087         newfiles = []
1088         for f in files:
1089             if os.path.isdir(f):
1090                 dirfiles = self.find_bbfiles(f)
1091                 if dirfiles:
1092                     newfiles += dirfiles
1093                     continue
1094             newfiles += glob.glob(f) or [ f ]
1095
1096         bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1) or ""
1097         try:
1098             bbmask_compiled = re.compile(bbmask)
1099         except sre_constants.error:
1100             bb.fatal("BBMASK is not a valid regular expression.")
1101
1102         for i in xrange( len( newfiles ) ):
1103             f = newfiles[i]
1104             if bbmask and bbmask_compiled.search(f):
1105                 bb.debug(1, "bbmake: skipping %s" % f)
1106                 masked += 1
1107                 continue
1108             debug(1, "bbmake: parsing %s" % f)
1109
1110             # read a file's metadata
1111             try:
1112                 fromCache, skip = self.bb_cache.loadData(f, self)
1113                 if skip:
1114                     skipped += 1
1115                     #bb.note("Skipping %s" % f)
1116                     self.bb_cache.skip(f)
1117                     continue
1118                 elif fromCache: cached += 1
1119                 else: parsed += 1
1120                 deps = None
1121
1122                 # allow metadata files to add items to BBFILES
1123                 #data.update_data(self.pkgdata[f])
1124                 addbbfiles = self.bb_cache.getVar('BBFILES', f, False) or None
1125                 if addbbfiles:
1126                     for aof in addbbfiles.split():
1127                         if not files.count(aof):
1128                             if not os.path.isabs(aof):
1129                                 aof = os.path.join(os.path.dirname(f),aof)
1130                             files.append(aof)
1131
1132                 # now inform the caller
1133                 if self.cb is not None:
1134                     self.cb( i + 1, len( newfiles ), f, self.bb_cache, fromCache )
1135
1136             except IOError, e:
1137                 self.bb_cache.remove(f)
1138                 bb.error("opening %s: %s" % (f, e))
1139                 pass
1140             except KeyboardInterrupt:
1141                 self.bb_cache.sync()
1142                 raise
1143             except Exception, e:
1144                 self.bb_cache.remove(f)
1145                 bb.error("%s while parsing %s" % (e, f))
1146             except:
1147                 self.bb_cache.remove(f)
1148                 raise
1149
1150         if self.cb is not None:
1151             print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ),
1152
1153         self.bb_cache.sync()
1154
1155 #============================================================================#
1156 # main
1157 #============================================================================#
1158
1159 def main():
1160     parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
1161     usage = """%prog [options] [package ...]
1162
1163 Executes the specified task (default is 'build') for a given set of BitBake files.
1164 It expects that BBFILES is defined, which is a space seperated list of files to
1165 be executed.  BBFILES does support wildcards.
1166 Default BBFILES are the .bb files in the current directory.""" )
1167
1168     parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
1169                action = "store", dest = "buildfile", default = None )
1170
1171     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.",
1172                action = "store_false", dest = "abort", default = True )
1173
1174     parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
1175                action = "store_true", dest = "force", default = False )
1176
1177     parser.add_option( "-i", "--interactive", help = "drop into the interactive mode.",
1178                action = "store_true", dest = "interactive", default = False )
1179
1180     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)",
1181                action = "store", dest = "cmd", default = "build" )
1182
1183     parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
1184                action = "append", dest = "file", default = [] )
1185
1186     parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
1187                action = "store_true", dest = "verbose", default = False )
1188
1189     parser.add_option( "-D", "--debug", help = "Increase the debug level",
1190                action = "count", dest="debug", default = 0)
1191
1192     parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
1193                action = "store_true", dest = "dry_run", default = False )
1194
1195     parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
1196                action = "store_true", dest = "parse_only", default = False )
1197
1198     parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
1199                action = "store_true", dest = "disable_psyco", default = False )
1200
1201     parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
1202                action = "store_true", dest = "show_versions", default = False )
1203
1204     parser.add_option( "-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
1205                action = "store_true", dest = "show_environment", default = False )
1206
1207     parser.add_option( "-g", "--graphviz", help = "emit the dependency trees of the specified packages in the dot syntax",
1208                 action = "store_true", dest = "dot_graph", default = False )
1209
1210     options, args = parser.parse_args( sys.argv )
1211
1212     cooker = BBCooker()
1213     cooker.cook( BBConfiguration( options ), args[1:] )
1214
1215
1216
1217 if __name__ == "__main__":
1218     print """WARNING, WARNING, WARNING
1219 This is a Bitbake from the Unstable/Development Branch.
1220 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."""
1221     import time
1222     time.sleep(5)
1223     main()