1 # ex:ts=4:sw=4:sts=4:et
2 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4 BitBake 'Make' implementations
6 Functions for reading BB files, building a dependency graph and
7 building a set of BB files while walking along the dependency graph.
9 Copyright (C) 2003, 2004 Mickey Lauer
10 Copyright (C) 2003, 2004 Phil Blundell
11 Copyright (C) 2003, 2004 Chris Larson
13 This program is free software; you can redistribute it and/or modify it under
14 the terms of the GNU General Public License as published by the Free Software
15 Foundation; either version 2 of the License, or (at your option) any later
18 This program is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License along with
23 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
24 Place, Suite 330, Boston, MA 02111-1307 USA.
26 This file is part of the BitBake build tools.
29 from bb import debug, digraph, data, fetch, fatal, error, note, event, parse
30 import copy, bb, re, sys, os, glob, sre_constants
32 import cPickle as pickle
35 print "NOTE: Importing cPickle failed. Falling back to a very slow implementation."
41 ascii_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
44 def get_bbfiles( path = os.getcwd() ):
45 """Get list of default .bb files by reading out the current directory"""
46 contents = os.listdir(path)
49 (root, ext) = os.path.splitext(f)
51 bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
54 def find_bbfiles( path ):
55 """Find all the .bb files in a directory (uses find)"""
56 findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
58 finddata = os.popen(findcmd)
61 return finddata.readlines()
64 depstr = data.getVar('__depends', d)
66 deps = depstr.split(" ")
68 (f,old_mtime_s) = dep.split("@")
69 old_mtime = int(old_mtime_s)
70 new_mtime = parse.cached_mtime(f)
71 if (new_mtime > old_mtime):
75 def load_bbfile( bbfile ):
76 """Load and parse one .bb build file"""
78 if not cache in [None, '']:
79 cache_bbfile = bbfile.replace( '/', '_' )
82 cache_mtime = os.stat( "%s/%s" % ( cache, cache_bbfile ) )[8]
85 file_mtime = parse.cached_mtime(bbfile)
87 if file_mtime > cache_mtime:
88 #print " : '%s' dirty. reparsing..." % bbfile
91 #print " : '%s' clean. loading from cache..." % bbfile
92 cache_data = unpickle_bb( cache_bbfile )
93 if deps_clean(cache_data):
94 return cache_data, True
96 topdir = data.getVar('TOPDIR', cfg)
98 topdir = os.path.abspath(os.getcwd())
100 data.setVar('TOPDIR', topdir, cfg)
101 bbfile = os.path.abspath(bbfile)
102 bbfile_loc = os.path.abspath(os.path.dirname(bbfile))
103 # expand tmpdir to include this topdir
104 data.setVar('TMPDIR', data.getVar('TMPDIR', cfg, 1) or "", cfg)
105 # set topdir to location of .bb file
107 #data.setVar('TOPDIR', topdir, cfg)
109 oldpath = os.path.abspath(os.getcwd())
111 bb = data.createCopy(cfg)
113 parse.handle(bbfile, bb) # read .bb data
114 if not cache in [None, '']: pickle_bb( cache_bbfile, bb) # write cache
120 def pickle_bb( bbfile, bb ):
121 p = pickle.Pickler( file( "%s/%s" % ( cache, bbfile ), "wb" ), -1 )
124 def unpickle_bb( bbfile ):
125 p = pickle.Unpickler( file( "%s/%s" % ( cache, bbfile ), "rb" ) )
127 funcstr = data.getVar('__functions__', bb)
129 comp = compile(funcstr, "<pickled>", "exec")
130 exec comp in __builtins__
133 def collect_bbfiles( progressCallback ):
134 """Collect all available .bb build files"""
136 parsed, cached, skipped, masked = 0, 0, 0, 0
138 cache = bb.data.getVar( "CACHE", cfg, 1 )
139 if not cache in [None, '']:
140 print "NOTE: Using cache in '%s'" % cache
144 bb.mkdirhier( cache )
145 else: print "NOTE: Not using a cache. Set CACHE = <directory> to enable."
146 files = (data.getVar( "BBFILES", cfg, 1 ) or "").split()
147 data.setVar("BBFILES", " ".join(files), cfg)
150 files = get_bbfiles()
153 bb.error("no files to build.")
158 dirfiles = find_bbfiles(f)
162 newfiles += glob.glob(f) or [ f ]
164 bbmask = bb.data.getVar('BBMASK', cfg, 1) or ""
166 bbmask_compiled = re.compile(bbmask)
167 except sre_constants.error:
168 bb.fatal("BBMASK is not a valid regular expression.")
170 for i in xrange( len( newfiles ) ):
172 if bbmask and bbmask_compiled.search(f):
173 bb.debug(1, "bbmake: skipping %s" % f)
176 progressCallback( i + 1, len( newfiles ), f )
177 debug(1, "bbmake: parsing %s" % f)
179 # read a file's metadata
181 pkgdata[f], fromCache = load_bbfile(f)
182 if fromCache: cached += 1
185 if pkgdata[f] is not None:
186 # allow metadata files to add items to BBFILES
187 #data.update_data(pkgdata[f])
188 addbbfiles = data.getVar('BBFILES', pkgdata[f]) or None
190 for aof in addbbfiles.split():
191 if not files.count(aof):
192 if not os.path.isabs(aof):
193 aof = os.path.join(os.path.dirname(f),aof)
195 for var in pkgdata[f].keys():
196 if data.getVarFlag(var, "handler", pkgdata[f]) and data.getVar(var, pkgdata[f]):
197 event.register(data.getVar(var, pkgdata[f]))
199 bb.error("opening %s: %s" % (f, e))
201 except bb.parse.SkipPackage:
204 except KeyboardInterrupt:
207 bb.error("%s while parsing %s" % (e, f))
208 print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ),
210 def explode_version(s):
213 alpha_regexp = re.compile('^([a-zA-Z]+)(.*)$')
214 numeric_regexp = re.compile('^(\d+)(.*)$')
217 m = numeric_regexp.match(s)
218 r.append(int(m.group(1)))
221 if s[0] in ascii_letters:
222 m = alpha_regexp.match(s)
229 def vercmp_part(a, b):
230 va = explode_version(a)
231 vb = explode_version(b)
241 if ca == None and cb == None:
252 r = vercmp_part(va, vb)
254 r = vercmp_part(ra, rb)