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