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