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