bitbake/lib/bb/providers.py:
[bitbake.git] / bin / bitbake
1 #!/usr/bin/env python
2 # ex:ts=4:sw=4:sts=4:et
3 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4 #
5 # Copyright (C) 2003, 2004  Chris Larson
6 # Copyright (C) 2003, 2004  Phil Blundell
7 # Copyright (C) 2003 - 2005 Michael 'Mickey' Lauer
8 # Copyright (C) 2005        Holger Hans Peter Freyther
9 # Copyright (C) 2005        ROAD GmbH
10 #
11 # This program is free software; you can redistribute it and/or modify it under
12 # the terms of the GNU General Public License as published by the Free Software
13 # Foundation; either version 2 of the License, or (at your option) any later
14 # version.
15 #
16 # This program is distributed in the hope that it will be useful, but WITHOUT
17 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19 #
20 # You should have received a copy of the GNU General Public License along with
21 # this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22 # Place, Suite 330, Boston, MA 02111-1307 USA.
23
24 import sys, os, getopt, glob, copy, os.path, re, 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, providers
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
328     def showVersions( self ):
329         pkg_pn = self.status.pkg_pn
330         preferred_versions = {}
331         latest_versions = {}
332
333         # Sort by priority
334         for pn in pkg_pn.keys():
335             (last_ver,last_file,pref_ver,pref_file) = self.findBestProvider(pn, self.configuration.data, self.status)
336             preferred_versions[pn] = (pref_ver, pref_file)
337             latest_versions[pn] = (last_ver, last_file)
338
339         pkg_list = pkg_pn.keys()
340         pkg_list.sort()
341
342         for p in pkg_list:
343             pref = preferred_versions[p]
344             latest = latest_versions[p]
345
346             if pref != latest:
347                 prefstr = pref[0][0] + "-" + pref[0][1]
348             else:
349                 prefstr = ""
350
351             print "%-30s %20s %20s" % (p, latest[0][0] + "-" + latest[0][1],
352                                         prefstr)
353
354
355     def showEnvironment( self ):
356         """Show the outer or per-package environment"""
357         if self.configuration.buildfile:
358             self.cb = None
359             self.bb_cache = bb.cache.init(self)
360             try:
361                 self.configuration.data = self.bb_cache.loadDataFull(self.configuration.buildfile, self)
362             except IOError, e:
363                 fatal("Unable to read %s: %s" % ( self.configuration.buildfile, e ))
364             except Exception, e:
365                 fatal("%s" % e)
366         # emit variables and shell functions
367         try:
368             data.update_data( self.configuration.data )
369             data.emit_env(sys.__stdout__, self.configuration.data, True)
370         except Exception, e:
371             fatal("%s" % e)
372         # emit the metadata which isnt valid shell
373         for e in self.configuration.data.keys():
374             if data.getVarFlag( e, 'python', self.configuration.data ):
375                 sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, self.configuration.data, 1)))
376
377     def generateDotGraph( self, pkgs_to_build, ignore_deps ):
378         """
379         Generate two graphs one for the DEPENDS and RDEPENDS. The current
380         implementation creates crappy graphs ;)
381
382         pkgs_to_build A list of packages that needs to be built
383         ignore_deps   A list of names where processing of dependencies
384                       should be stopped. e.g. dependencies that get
385         """
386
387         def myFilterProvider( providers, item):
388             """
389             Take a list of providers and filter according to environment
390             variables. In contrast to filterProviders we do not discriminate
391             and take PREFERRED_PROVIDER into account.
392             """
393             eligible = []
394             preferred_versions = {}
395
396             # Collate providers by PN
397             pkg_pn = {}
398             for p in providers:
399                 pn = self.status.pkg_fn[p]
400                 if pn not in pkg_pn:
401                     pkg_pn[pn] = []
402                 pkg_pn[pn].append(p)
403
404             bb.debug(1, "providers for %s are: %s" % (item, pkg_pn.keys()))
405
406             for pn in pkg_pn.keys():
407                 preferred_versions[pn] = self.findBestProvider(pn, pkg_pn)[2:4]
408                 eligible.append(preferred_versions[pn][1])
409
410             for p in eligible:
411                 if p in self.build_cache_fail:
412                     bb.debug(1, "rejecting already-failed %s" % p)
413                     eligible.remove(p)
414
415             if len(eligible) == 0:
416                 bb.error("no eligible providers for %s" % item)
417                 return 0
418
419             prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
420
421             # try the preferred provider first
422             if prefervar:
423                 for p in eligible:
424                     if prefervar == self.status.pkg_fn[p]:
425                         bb.note("Selecting PREFERRED_PROVIDER %s" % prefervar)
426                         eligible.remove(p)
427                         eligible = [p] + eligible
428
429             return eligible
430
431
432
433
434         # try to avoid adding the same rdepends over an over again
435         seen_depends  = []
436         seen_rdepends = []
437
438
439         def add_depends(package_list):
440             """
441             Add all depends of all packages from this list
442             """
443             for package in package_list:
444                 if package in seen_depends or package in ignore_deps:
445                     continue
446
447                 seen_depends.append( package )
448                 if not package in self.status.providers:
449                     """
450                     We have not seen this name -> error in
451                     dependency handling
452                     """
453                     bb.note( "ERROR with provider: %(package)s" % vars() )
454                     print >> depends_file, '"%(package)s" -> ERROR' % vars()
455                     continue
456
457                 # get all providers for this package
458                 providers = self.status.providers[package]
459
460                 # now let us find the bestProvider for it
461                 fn = myFilterProvider(providers, package)[0]
462
463                 depends  = bb.utils.explode_deps(self.bb_cache.getVar('DEPENDS', fn, True) or "")
464                 version  = self.bb_cache.getVar('PV', fn, True ) + '-' + self.bb_cache.getVar('PR', fn, True)
465                 add_depends ( depends )
466
467                 # now create the node
468                 print >> depends_file, '"%(package)s" [label="%(package)s\\n%(version)s"]' % vars()
469
470                 depends = filter( (lambda x: x not in ignore_deps), depends )
471                 for depend in depends:
472                     print >> depends_file, '"%(package)s" -> "%(depend)s"' % vars()
473
474
475         def add_all_depends( the_depends, the_rdepends ):
476             """
477             Add both DEPENDS and RDEPENDS. RDEPENDS will get dashed
478             lines
479             """
480             package_list = the_depends + the_rdepends
481             for package in package_list:
482                 if package in seen_rdepends or package in ignore_deps:
483                     continue
484
485                 seen_rdepends.append( package )
486
487                 # Let us find out if the package is a DEPENDS or RDEPENDS
488                 # and we will set 'providers' with the avilable providers
489                 # for the package.
490                 if package in the_depends:
491                     if not package in self.status.providers:
492                         bb.note( "ERROR with provider: %(package)s" % vars() )
493                         print >> alldepends_file, '"%(package)s" -> ERROR' % vars()
494                         continue
495
496                     providers = self.status.providers[package]
497                 elif package in the_rdepends:
498                     if len(self.getProvidersRun(package)) == 0:
499                         bb.note( "ERROR with rprovider: %(package)s" % vars() )
500                         print >> alldepends_file, '"%(package)s" -> ERROR [style="dashed"]' % vars()
501                         continue
502
503                     providers = self.getProvidersRun(package)
504                 else:
505                     # something went wrong...
506                     print "Complete ERROR! %s" % package
507                     continue
508
509                 # now let us find the bestProvider for it
510                 fn = myFilterProvider(providers, package)[0]
511
512                 # Now we have a filename let us get the depends and RDEPENDS of it
513                 depends  = bb.utils.explode_deps(self.bb_cache.getVar('DEPENDS', fn, True) or "")
514                 if fn in self.status.rundeps and package in self.status.rundeps[fn]:
515                     rdepends= self.status.rundeps[fn][package].keys()
516                 else:
517                     rdepends = []
518                 version  = self.bb_cache.getVar('PV', fn, True ) + '-' + self.bb_cache.getVar('PR', fn, True)
519
520                 # handle all the depends and rdepends of package
521                 add_all_depends ( depends, rdepends )
522
523                 # now create the node using package name
524                 print >> alldepends_file, '"%(package)s" [label="%(package)s\\n%(version)s"]' % vars()
525
526                 # remove the stuff we want to ignore and add the edges
527                 depends = filter( (lambda x: x not in ignore_deps), depends )
528                 rdepends = filter( (lambda x: x not in ignore_deps), rdepends )
529                 for depend in depends:
530                     print >> alldepends_file, '"%(package)s" -> "%(depend)s"' % vars()
531                 for depend in rdepends:
532                     print >> alldepends_file, '"%(package)s" -> "%(depend)s" [style=dashed]' % vars()
533
534
535         # Add depends now
536         depends_file = file('depends.dot', 'w' )
537         print >> depends_file, "digraph depends {"
538         add_depends( pkgs_to_build )
539         print >> depends_file,  "}"
540
541         # Add all depends now
542         alldepends_file = file('alldepends.dot', 'w' )
543         print >> alldepends_file, "digraph alldepends {"
544         add_all_depends( pkgs_to_build, [] )
545         print >> alldepends_file, "}"
546
547     def buildProvider( self, item , buildAllDeps , build_depends = [] ):
548         """
549         Build something to provide a named build requirement
550         (takes item names from DEPENDS namespace)
551         """
552
553         fn = None
554         discriminated = False
555
556         if not item in self.status.providers:
557             bb.error("Nothing provides dependency %s" % item)
558             bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
559             return 0
560
561         all_p = self.status.providers[item]
562
563         for p in all_p:
564             if p in self.build_cache:
565                 bb.debug(1, "already built %s in this run\n" % p)
566                 return 1
567
568         eligible = bb.providers.filterProviders(all_p, item, self.configuration.data, self.status, self.build_cache_fail, self.configuration.verbose)
569
570         if not eligible:
571             return 0
572
573         prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
574         if prefervar:
575             self.preferred[item] = prefervar
576
577         if item in self.preferred:
578             for p in eligible:
579                 pn = self.status.pkg_fn[p]
580                 if self.preferred[item] == pn:
581                     if self.configuration.verbose:
582                         bb.note("selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
583                     eligible.remove(p)
584                     eligible = [p] + eligible
585                     discriminated = True
586                     break
587
588         if len(eligible) > 1 and discriminated == False:
589             if item not in self.consider_msgs_cache:
590                 providers_list = []
591                 for fn in eligible:
592                     providers_list.append(self.status.pkg_fn[fn])
593                 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
594                 bb.note("consider defining PREFERRED_PROVIDER_%s" % item)
595                 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data))
596             self.consider_msgs_cache.append(item)
597
598
599         # run through the list until we find one that we can build
600         for fn in eligible:
601             bb.debug(2, "selecting %s to satisfy %s" % (fn, item))
602             if self.tryBuild(fn, item, buildAllDeps, build_depends + [fn]):
603                 return 1
604
605         bb.note("no buildable providers for %s" % item)
606         bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
607         return 0
608
609     def buildRProvider( self, item , buildAllDeps ):
610         """
611         Build something to provide a named runtime requirement
612         (takes item names from RDEPENDS/PACKAGES namespace)
613         """
614
615         fn = None
616         all_p = []
617         discriminated = False
618
619         if not buildAllDeps:
620             return True
621
622         all_p = self.getProvidersRun(item)
623
624         if not all_p:
625             bb.error("Nothing provides runtime dependency %s" % (item))
626             bb.event.fire(bb.event.NoProvider(item,self.configuration.data,runtime=True))
627             return False
628
629         for p in all_p:
630             if p in self.rbuild_cache:
631                 bb.debug(2, "Already built %s providing runtime %s\n" % (p,item))
632                 return True
633             if p in self.build_cache:
634                 bb.debug(2, "Already built %s but adding any further RDEPENDS for %s\n" % (p, item))
635                 return self.addRunDeps(p, item , buildAllDeps)
636
637         eligible = bb.providers.filterProviders(all_p, item, self.configuration.data, self.status, self.build_cache_fail, self.configuration.verbose)
638         if not eligible:
639             return 0
640
641         preferred = []
642         for p in eligible:
643             pn = self.status.pkg_fn[p]
644             provides = self.status.pn_provides[pn]
645             for provide in provides:
646                 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, self.configuration.data, 1)
647                 if prefervar == pn:
648                     if self.configuration.verbose:
649                         bb.note("selecting %s to satisfy runtime %s due to PREFERRED_PROVIDERS" % (pn, item))
650                     eligible.remove(p)
651                     eligible = [p] + eligible
652                     preferred.append(p)
653
654         if len(eligible) > 1 and len(preferred) == 0:
655             if item not in self.consider_msgs_cache:
656                 providers_list = []
657                 for fn in eligible:
658                     providers_list.append(self.status.pkg_fn[fn])
659                 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
660                 bb.note("consider defining a PREFERRED_PROVIDER to match runtime %s" % item)
661                 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
662             self.consider_msgs_cache.append(item)
663
664         if len(preferred) > 1:
665             if item not in self.consider_msgs_cache:
666                 providers_list = []
667                 for fn in preferred:
668                     providers_list.append(self.status.pkg_fn[fn])
669                 bb.note("multiple preferred providers are available (%s);" % ", ".join(providers_list))
670                 bb.note("consider defining only one PREFERRED_PROVIDER to match runtime %s" % item)
671                 bb.event.fire(bb.event.MultipleProviders(item,providers_list,self.configuration.data,runtime=True))
672             self.consider_msgs_cache.append(item)
673
674         # run through the list until we find one that we can build
675         for fn in eligible:
676             bb.debug(2, "selecting %s to satisfy runtime %s" % (fn, item))
677             if self.tryBuild(fn, item, buildAllDeps):
678                 return True
679
680         bb.error("No buildable providers for runtime %s" % item)
681         bb.event.fire(bb.event.NoProvider(item,self.configuration.data))
682         return False
683
684     def getProvidersRun(self, rdepend):
685         """
686         Return any potential providers of runtime rdepend
687         """
688         rproviders = []
689
690         if rdepend in self.status.rproviders:
691             rproviders += self.status.rproviders[rdepend]
692
693         if rdepend in self.status.packages:
694             rproviders += self.status.packages[rdepend]
695
696         if rproviders:
697             return rproviders
698
699         # Only search dynamic packages if we can't find anything in other variables
700         for pattern in self.status.packages_dynamic:
701             regexp = re.compile(pattern)
702             if regexp.match(rdepend):
703                 rproviders += self.status.packages_dynamic[pattern]
704
705         return rproviders
706
707     def addRunDeps(self , fn, item , buildAllDeps):
708         """
709         Add any runtime dependencies of runtime item provided by fn 
710         as long as item has't previously been processed by this function.
711         """
712
713         if item in self.rbuild_cache:
714             return True
715
716         if not buildAllDeps:
717             return True
718
719         rdepends = []
720         self.rbuild_cache.append(item)
721
722         if fn in self.status.rundeps and item in self.status.rundeps[fn]:
723             rdepends += self.status.rundeps[fn][item].keys()
724         if fn in self.status.runrecs and item in self.status.runrecs[fn]:
725             rdepends += self.status.runrecs[fn][item].keys()
726
727         bb.debug(2, "Additional runtime dependencies for %s are: %s" % (item, " ".join(rdepends)))
728
729         for rdepend in rdepends:
730             if rdepend in self.status.ignored_dependencies:
731                 continue
732             if not self.buildRProvider(rdepend, buildAllDeps):
733                 return False
734         return True
735
736     def buildDepgraph( self ):
737         all_depends = self.status.all_depends
738         pn_provides = self.status.pn_provides
739
740         localdata = data.createCopy(self.configuration.data)
741         bb.data.update_data(localdata)
742
743         def calc_bbfile_priority(filename):
744             for (regex, pri) in self.status.bbfile_config_priorities:
745                 if regex.match(filename):
746                     return pri
747             return 0
748
749         # Handle PREFERRED_PROVIDERS
750         for p in (bb.data.getVar('PREFERRED_PROVIDERS', localdata, 1) or "").split():
751             (providee, provider) = p.split(':')
752             if providee in self.preferred and self.preferred[providee] != provider:
753                 bb.error("conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.preferred[providee]))
754             self.preferred[providee] = provider
755
756         # Calculate priorities for each file
757         for p in self.status.pkg_fn.keys():
758             self.status.bbfile_priority[p] = calc_bbfile_priority(p)
759
760     def buildWorldTargetList(self):
761         """
762          Build package list for "bitbake world"
763         """
764         all_depends = self.status.all_depends
765         pn_provides = self.status.pn_provides
766         bb.debug(1, "collating packages for \"world\"")
767         for f in self.status.possible_world:
768             terminal = True
769             pn = self.status.pkg_fn[f]
770
771             for p in pn_provides[pn]:
772                 if p.startswith('virtual/'):
773                     bb.debug(2, "skipping %s due to %s provider starting with virtual/" % (f, p))
774                     terminal = False
775                     break
776                 for pf in self.status.providers[p]:
777                     if self.status.pkg_fn[pf] != pn:
778                         bb.debug(2, "skipping %s due to both us and %s providing %s" % (f, pf, p))
779                         terminal = False
780                         break
781             if terminal:
782                 self.status.world_target.add(pn)
783
784             # drop reference count now
785             self.status.possible_world = None
786             self.status.all_depends    = None
787
788     def myProgressCallback( self, x, y, f, bb_cache, from_cache ):
789         # feed the status with new input
790
791         self.status.handle_bb_data(f, bb_cache, from_cache)
792
793         if bbdebug > 0:
794             return
795         if os.isatty(sys.stdout.fileno()):
796             sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
797             sys.stdout.flush()
798         else:
799             if x == 1:
800                 sys.stdout.write("Parsing .bb files, please wait...")
801                 sys.stdout.flush()
802             if x == y:
803                 sys.stdout.write("done.")
804                 sys.stdout.flush()
805
806     def interactiveMode( self ):
807         """Drop off into a shell"""
808         try:
809             from bb import shell
810         except ImportError, details:
811             bb.fatal("Sorry, shell not available (%s)" % details )
812         else:
813             bb.data.update_data( self.configuration.data )
814             shell.start( self )
815             sys.exit( 0 )
816
817     def parseConfigurationFile( self, afile ):
818         try:
819             self.configuration.data = bb.parse.handle( afile, self.configuration.data )
820
821             # Add the handlers we inherited by INHERIT
822             # we need to do this manually as it is not guranteed
823             # we will pick up these classes... as we only INHERIT
824             # on .inc and .bb files but not on .conf
825             data = bb.data.createCopy( self.configuration.data )
826             inherits  = ["base"] + (bb.data.getVar('INHERIT', data, True ) or "").split()
827             for inherit in inherits:
828                 data = bb.parse.handle( os.path.join('classes', '%s.bbclass' % inherit ), data, True )
829
830             # FIXME: This assumes that we included at least one .inc file
831             for var in bb.data.keys(data):
832                 if bb.data.getVarFlag(var, 'handler', data):
833                     bb.event.register(var,bb.data.getVar(var, data))
834
835         except IOError:
836             bb.fatal( "Unable to open %s" % afile )
837         except bb.parse.ParseError, details:
838             bb.fatal( "Unable to parse %s (%s)" % (afile, details) )
839
840     def handleCollections( self, collections ):
841         """Handle collections"""
842         if collections:
843             collection_list = collections.split()
844             for c in collection_list:
845                 regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1)
846                 if regex == None:
847                     bb.error("BBFILE_PATTERN_%s not defined" % c)
848                     continue
849                 priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1)
850                 if priority == None:
851                     bb.error("BBFILE_PRIORITY_%s not defined" % c)
852                     continue
853                 try:
854                     cre = re.compile(regex)
855                 except re.error:
856                     bb.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
857                     continue
858                 try:
859                     pri = int(priority)
860                     self.status.bbfile_config_priorities.append((cre, pri))
861                 except ValueError:
862                     bb.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
863
864
865     def cook( self, configuration, args ):
866         """
867         We are building stuff here. We do the building
868         from here. By default we try to execute task
869         build.
870         """
871
872         self.configuration = configuration
873
874         if not self.configuration.cmd:
875             self.configuration.cmd = "build"
876
877         if self.configuration.debug:
878             bb.debug_level = self.configuration.debug
879
880         self.configuration.data = bb.data.init()
881
882         for f in self.configuration.file:
883             self.parseConfigurationFile( f )
884
885         self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
886
887
888         #
889         # Special updated configuration we use for firing events
890         #
891         self.configuration.event_data = bb.data.createCopy(self.configuration.data)
892         bb.data.update_data(self.configuration.event_data)
893
894         if self.configuration.show_environment:
895             self.showEnvironment()
896             sys.exit( 0 )
897
898         # inject custom variables
899         if not bb.data.getVar("BUILDNAME", self.configuration.data):
900             bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
901         bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data)
902
903         buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
904
905         if self.configuration.interactive:
906             self.interactiveMode()
907
908         if self.configuration.buildfile is not None:
909             bf = os.path.abspath( self.configuration.buildfile )
910             try:
911                 bbfile_data = bb.parse.handle(bf, self.configuration.data)
912             except IOError:
913                 bb.fatal("Unable to open %s" % bf)
914
915             item = bb.data.getVar('PN', bbfile_data, 1)
916             try:
917                 self.tryBuildPackage( bf, item, bbfile_data )
918             except bb.build.EventException:
919                 bb.error( "Build of '%s' failed" % item )
920
921             sys.exit( self.stats.show() )
922
923         # initialise the parsing status now we know we will need deps
924         self.status = BBParsingStatus()
925
926         ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
927         self.status.ignored_dependencies = Set( ignore.split() )
928
929         self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
930
931         pkgs_to_build = None
932         if args:
933             if not pkgs_to_build:
934                 pkgs_to_build = []
935             pkgs_to_build.extend(args)
936         if not pkgs_to_build:
937                 bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
938                 if bbpkgs:
939                         pkgs_to_build = bbpkgs.split()
940         if not pkgs_to_build and not self.configuration.show_versions \
941                              and not self.configuration.interactive \
942                              and not self.configuration.show_environment:
943                 print "Nothing to do.  Use 'bitbake world' to build everything, or run 'bitbake --help'"
944                 print "for usage information."
945                 sys.exit(0)
946
947         # Import Psyco if available and not disabled
948         if not self.configuration.disable_psyco:
949             try:
950                 import psyco
951             except ImportError:
952                 if bbdebug == 0:
953                     bb.note("Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
954             else:
955                 psyco.bind( self.collect_bbfiles )
956         else:
957             bb.note("You have disabled Psyco. This decreases performance.")
958
959         try:
960             bb.debug(1, "collecting .bb files")
961             self.collect_bbfiles( self.myProgressCallback )
962             bb.debug(1, "parsing complete")
963             if bbdebug == 0:
964                 print
965             if self.configuration.parse_only:
966                 print "Requested parsing .bb files only.  Exiting."
967                 return
968
969
970             self.buildDepgraph()
971
972             if self.configuration.show_versions:
973                 self.showVersions()
974                 sys.exit( 0 )
975             if 'world' in pkgs_to_build:
976                 self.buildWorldTargetList()
977                 pkgs_to_build.remove('world')
978                 for t in self.status.world_target:
979                     pkgs_to_build.append(t)
980
981             if self.configuration.dot_graph:
982                 self.generateDotGraph( pkgs_to_build, self.configuration.ignored_dot_deps )
983                 sys.exit( 0 )
984
985
986             bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.event_data))
987
988             failures = 0
989             for k in pkgs_to_build:
990                 failed = False
991                 try:
992                     if self.buildProvider( k , False ) == 0:
993                         # already diagnosed
994                         failed = True
995                 except bb.build.EventException:
996                     bb.error("Build of " + k + " failed")
997                     failed = True
998
999                 if failed:
1000                     failures += failures
1001                     if self.configuration.abort:
1002                         sys.exit(1)
1003
1004             bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.event_data, failures))
1005
1006             sys.exit( self.stats.show() )
1007
1008         except KeyboardInterrupt:
1009             print "\nNOTE: KeyboardInterrupt - Build not completed."
1010             sys.exit(1)
1011
1012     def get_bbfiles( self, path = os.getcwd() ):
1013         """Get list of default .bb files by reading out the current directory"""
1014         contents = os.listdir(path)
1015         bbfiles = []
1016         for f in contents:
1017             (root, ext) = os.path.splitext(f)
1018             if ext == ".bb":
1019                 bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
1020         return bbfiles
1021
1022     def find_bbfiles( self, path ):
1023         """Find all the .bb files in a directory (uses find)"""
1024         findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
1025         try:
1026             finddata = os.popen(findcmd)
1027         except OSError:
1028             return []
1029         return finddata.readlines()
1030
1031     def collect_bbfiles( self, progressCallback ):
1032         """Collect all available .bb build files"""
1033         self.cb = progressCallback
1034         parsed, cached, skipped, masked = 0, 0, 0, 0
1035         self.bb_cache = bb.cache.init(self)
1036
1037         files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
1038         data.setVar("BBFILES", " ".join(files), self.configuration.data)
1039
1040         if not len(files):
1041             files = self.get_bbfiles()
1042
1043         if not len(files):
1044             bb.error("no files to build.")
1045
1046         newfiles = []
1047         for f in files:
1048             if os.path.isdir(f):
1049                 dirfiles = self.find_bbfiles(f)
1050                 if dirfiles:
1051                     newfiles += dirfiles
1052                     continue
1053             newfiles += glob.glob(f) or [ f ]
1054
1055         bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1) or ""
1056         try:
1057             bbmask_compiled = re.compile(bbmask)
1058         except sre_constants.error:
1059             bb.fatal("BBMASK is not a valid regular expression.")
1060
1061         for i in xrange( len( newfiles ) ):
1062             f = newfiles[i]
1063             if bbmask and bbmask_compiled.search(f):
1064                 bb.debug(1, "bbmake: skipping %s" % f)
1065                 masked += 1
1066                 continue
1067             debug(1, "bbmake: parsing %s" % f)
1068
1069             # read a file's metadata
1070             try:
1071                 fromCache, skip = self.bb_cache.loadData(f, self)
1072                 if skip:
1073                     skipped += 1
1074                     #bb.note("Skipping %s" % f)
1075                     self.bb_cache.skip(f)
1076                     continue
1077                 elif fromCache: cached += 1
1078                 else: parsed += 1
1079                 deps = None
1080
1081                 # allow metadata files to add items to BBFILES
1082                 #data.update_data(self.pkgdata[f])
1083                 addbbfiles = self.bb_cache.getVar('BBFILES', f, False) or None
1084                 if addbbfiles:
1085                     for aof in addbbfiles.split():
1086                         if not files.count(aof):
1087                             if not os.path.isabs(aof):
1088                                 aof = os.path.join(os.path.dirname(f),aof)
1089                             files.append(aof)
1090
1091                 # now inform the caller
1092                 if self.cb is not None:
1093                     self.cb( i + 1, len( newfiles ), f, self.bb_cache, fromCache )
1094
1095             except IOError, e:
1096                 self.bb_cache.remove(f)
1097                 bb.error("opening %s: %s" % (f, e))
1098                 pass
1099             except KeyboardInterrupt:
1100                 self.bb_cache.sync()
1101                 raise
1102             except Exception, e:
1103                 self.bb_cache.remove(f)
1104                 bb.error("%s while parsing %s" % (e, f))
1105             except:
1106                 self.bb_cache.remove(f)
1107                 raise
1108
1109         if self.cb is not None:
1110             print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ),
1111
1112         self.bb_cache.sync()
1113
1114 #============================================================================#
1115 # main
1116 #============================================================================#
1117
1118 def main():
1119     parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
1120     usage = """%prog [options] [package ...]
1121
1122 Executes the specified task (default is 'build') for a given set of BitBake files.
1123 It expects that BBFILES is defined, which is a space seperated list of files to
1124 be executed.  BBFILES does support wildcards.
1125 Default BBFILES are the .bb files in the current directory.""" )
1126
1127     parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
1128                action = "store", dest = "buildfile", default = None )
1129
1130     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.",
1131                action = "store_false", dest = "abort", default = True )
1132
1133     parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
1134                action = "store_true", dest = "force", default = False )
1135
1136     parser.add_option( "-i", "--interactive", help = "drop into the interactive mode also called the BitBake shell.",
1137                action = "store_true", dest = "interactive", default = False )
1138
1139     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",
1140                action = "store", dest = "cmd", default = "build" )
1141
1142     parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
1143                action = "append", dest = "file", default = [] )
1144
1145     parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
1146                action = "store_true", dest = "verbose", default = False )
1147
1148     parser.add_option( "-D", "--debug", help = "Increase the debug level. You can specify this more than once.",
1149                action = "count", dest="debug", default = 0)
1150
1151     parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
1152                action = "store_true", dest = "dry_run", default = False )
1153
1154     parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
1155                action = "store_true", dest = "parse_only", default = False )
1156
1157     parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
1158                action = "store_true", dest = "disable_psyco", default = False )
1159
1160     parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
1161                action = "store_true", dest = "show_versions", default = False )
1162
1163     parser.add_option( "-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
1164                action = "store_true", dest = "show_environment", default = False )
1165
1166     parser.add_option( "-g", "--graphviz", help = "emit the dependency trees of the specified packages in the dot syntax",
1167                 action = "store_true", dest = "dot_graph", default = False )
1168     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""",
1169                 action = "append", dest = "ignored_dot_deps", default = [] )
1170
1171
1172     options, args = parser.parse_args( sys.argv )
1173
1174     cooker = BBCooker()
1175     cooker.cook( BBConfiguration( options ), args[1:] )
1176
1177
1178
1179 if __name__ == "__main__":
1180     print """WARNING, WARNING, WARNING
1181 This is a Bitbake from the Unstable/Development Branch.
1182 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."""
1183     import time
1184     time.sleep(5)
1185     main()