2 # ex:ts=4:sw=4:sts=4:et
3 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
5 import sys, os, getopt, glob, copy, os.path, re
6 sys.path.append('/usr/share/oe')
10 import itertools, optparse
12 parsespin = itertools.cycle( r'|/-\\' )
15 __build_cache_fail = []
21 __world_target = Set()
22 __ignored_dependencies = Set()
23 __depcmds = { "clean": None,
28 oefile_config_priorities = []
32 def handle_options( args ):
33 parser = optparse.OptionParser( version = "OpenEmbedded Build Infrastructure Core version %s, %%prog version %s" % ( oe.__version__, __version__ ),
34 usage = """%prog [options] [package ...]
36 Builds specified packages, expecting that the .oe files
37 it has to work from are in OEFILES
38 Default packages are all packages in OEFILES.
39 Default OEFILES are the .oe files in the current directory.""" )
41 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.",
42 action = "store_false", dest = "abort", default = True )
44 parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
45 action = "store_true", dest = "force", default = False )
48 parser.add_option( "-c", "--cmd", help = "specify command to pass to oebuild. Valid commands are "
49 "'fetch' (fetch all sources), "
50 "'unpack' (unpack the sources), "
51 "'patch' (apply the patches), "
52 "'configure' (configure the source tree), "
53 "'compile' (compile the source tree), "
54 "'stage' (install libraries and headers needed for subsequent packages), "
55 "'install' (install libraries and executables), and"
56 "'package' (package files into the selected package format)",
57 action = "store", dest = "cmd", default = "build" )
59 parser.add_option( "-r", "--read", help = "read the specified file before oe.conf",
60 action = "append", dest = "file", default = [] )
62 parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
63 action = "store_true", dest = "verbose", default = False )
65 parser.add_option( "-n", "--dry-run", help = "don't call oebuild, just go through the motions",
66 action = "store_true", dest = "dry_run", default = False )
68 parser.add_option( "-p", "--parse-only", help = "quit after parsing the OE files (developers only)",
69 action = "store_true", dest = "parse_only", default = False )
71 parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
72 action = "store_true", dest = "disable_psyco", default = False )
74 options, args = parser.parse_args( args )
75 return options, args[1:]
77 def try_build(fn, virtual):
78 if fn in __building_list:
79 oe.error("%s depends on itself (eventually)" % fn)
80 oe.error("upwards chain is: %s" % (" -> ".join(__build_path)))
83 __building_list.append(fn)
85 the_data = make.pkgdata[fn]
86 item = oe.data.getVar('PN', the_data, 1)
87 pathstr = "%s (%s)" % (item, virtual)
88 __build_path.append(pathstr)
90 depends_list = (oe.data.getVar('DEPENDS', the_data, 1) or "").split()
91 if make.options.verbose:
92 oe.note("current path: %s" % (" -> ".join(__build_path)))
93 oe.note("dependencies for %s are: %s" % (item, " ".join(depends_list)))
99 oldcmd = make.options.cmd
100 make.options.cmd = __depcmd
102 for d in depends_list:
103 if d in __ignored_dependencies:
107 if buildPackage(d) == 0:
108 oe.error("dependency %s (for %s) not satisfied" % (d,item))
110 if make.options.abort:
114 make.options.cmd = oldcmd
120 oe.event.fire(oe.event.PkgStarted(item, make.pkgdata[fn]))
122 __stats["attempt"] += 1
123 if not make.options.dry_run:
124 oe.build.exec_task('do_%s' % make.options.cmd, make.pkgdata[fn])
125 oe.event.fire(oe.event.PkgSucceeded(item, make.pkgdata[fn]))
126 __build_cache.append(fn)
128 except oe.build.FuncFailed:
130 oe.error("task stack execution failed")
131 oe.event.fire(oe.event.PkgFailed(item, make.pkgdata[fn]))
132 __build_cache_fail.append(fn)
134 except oe.build.EventException:
136 (type, value, traceback) = sys.exc_info()
138 oe.error("%s event exception, aborting" % oe.event.getName(e))
139 oe.event.fire(oe.event.PkgFailed(item, make.pkgdata[fn]))
140 __build_cache_fail.append(fn)
143 __building_list.remove(fn)
144 __build_path.remove(pathstr)
146 def buildPackage(item):
149 discriminated = False
151 if not providers.has_key(item):
152 oe.error("Nothing provides %s" % item)
155 all_p = providers[item]
158 if p in __build_cache:
159 oe.debug(1, "already built %s in this run\n" % p)
163 preferred_versions = {}
165 # Collate providers by PN
168 the_data = make.pkgdata[p]
169 pn = oe.data.getVar('PN', the_data, 1)
170 if not pkg_pn.has_key(pn):
174 oe.debug(1, "providers for %s are: %s" % (item, pkg_pn.keys()))
177 for pn in pkg_pn.keys():
181 priority = oefile_priority[f]
182 if not priorities.has_key(priority):
183 priorities[priority] = []
184 priorities[priority].append(f)
185 p_list = priorities.keys()
186 p_list.sort(lambda a, b: a - b)
189 pkg_pn[pn] = [ priorities[p] ] + pkg_pn[pn]
191 # If there is a PREFERRED_VERSION, find the highest-priority oefile providing that
192 # version. If not, find the latest version provided by an oefile in the
193 # highest-priority set.
194 for pn in pkg_pn.keys():
195 preferred_file = None
197 preferred_v = oe.data.getVar('PREFERRED_VERSION_%s' % pn, make.cfg, 1)
200 m = re.match('(.*)-(.*)', preferred_v)
202 preferred_v = m.group(1)
203 preferred_r = m.group(2)
205 for file_set in pkg_pn[pn]:
207 the_data = make.pkgdata[f]
208 pv = oe.data.getVar('PV', the_data, 1)
209 pr = oe.data.getVar('PR', the_data, 1)
210 if preferred_v == pv and (preferred_r == pr or preferred_r == None):
212 preferred_ver = (pv, pr)
217 pv_str = '%s-%s' % (preferred_v, preferred_r)
220 if preferred_file is None:
221 oe.note("preferred version %s of %s not available" % (pv_str, pn))
223 oe.debug(1, "selecting %s as PREFERRED_VERSION %s of package %s" % (preferred_file, pv_str, pn))
225 if preferred_file is None:
226 # get highest priority file set
227 files = pkg_pn[pn][0]
231 the_data = make.pkgdata[f]
232 pv = oe.data.getVar('PV', the_data, 1)
233 pr = oe.data.getVar('PR', the_data, 1)
234 if (latest is None) or (make.vercmp(latest, (pv, pr)) < 0):
237 preferred_file = latest_f
238 preferred_ver = latest
240 oe.debug(1, "selecting %s as latest version of provider %s" % (preferred_file, pn))
242 preferred_versions[pn] = (preferred_ver, preferred_file)
243 eligible.append(preferred_file)
246 if p in __build_cache_fail:
247 oe.debug(1, "rejecting already-failed %s" % p)
250 if len(eligible) == 0:
251 oe.error("no eligible providers for %s" % item)
254 # look to see if one of them is already staged, or marked as preferred.
255 # if so, bump it to the head of the queue
257 the_data = make.pkgdata[p]
258 pn = oe.data.getVar('PN', the_data, 1)
259 pv = oe.data.getVar('PV', the_data, 1)
260 pr = oe.data.getVar('PR', the_data, 1)
261 tmpdir = oe.data.getVar('TMPDIR', the_data, 1)
262 stamp = '%s/stamps/%s-%s-%s.do_populate_staging' % (tmpdir, pn, pv, pr)
263 if os.path.exists(stamp):
264 (newvers, fn) = preferred_versions[pn]
265 if not fn in eligible:
266 # package was made ineligible by already-failed check
268 oldver = "%s-%s" % (pv, pr)
269 newver = '-'.join(newvers)
270 if (newver != oldver):
271 extra_chat = "; upgrading from %s to %s" % (oldver, newver)
274 if make.options.verbose:
275 oe.note("selecting already-staged %s to satisfy %s%s" % (pn, item, extra_chat))
277 eligible = [fn] + eligible
281 prefervar = oe.data.getVar('PREFERRED_PROVIDER_%s' % item, make.cfg, 1)
283 __preferred[item] = prefervar
285 if __preferred.has_key(item):
287 the_data = make.pkgdata[p]
288 pn = oe.data.getVar('PN', the_data, 1)
289 if __preferred[item] == pn:
290 if make.options.verbose:
291 oe.note("selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
293 eligible = [p] + eligible
297 if len(eligible) > 1 and discriminated == False:
300 providers_list.append(oe.data.getVar('PN', make.pkgdata[fn], 1))
301 oe.note("multiple providers are available (%s);" % ", ".join(providers_list))
302 oe.note("consider defining PREFERRED_PROVIDER_%s" % item)
304 # run through the list until we find one that we can build
306 oe.debug(2, "selecting %s to satisfy %s" % (fn, item))
307 if try_build(fn, item):
310 oe.note("no buildable providers for %s" % item)
313 def build_depgraph():
318 if oedebug or progress.p == p: return
320 if os.isatty(sys.stdout.fileno()):
321 sys.stdout.write("\rNOTE: Building provider hash: [%s%s] (%02d%%)" % ( "#" * (p/5), " " * ( 20 - p/5 ), p ) )
325 sys.stdout.write("NOTE: Building provider hash, please wait...\n")
327 sys.stdout.write("done.\n")
330 def calc_oefile_priority(filename):
331 for (regex, pri) in oefile_config_priorities:
332 if regex.match(filename):
336 # Handle PREFERRED_PROVIDERS
337 for p in (oe.data.getVar('PREFERRED_PROVIDERS', make.cfg, 1) or "").split():
338 (providee, provider) = p.split(':')
339 if __preferred.has_key(providee) and __preferred[providee] != provider:
340 oe.error("conflicting preferences for %s: both %s and %s specified" % (providee, provider, __preferred[providee]))
341 __preferred[providee] = provider
343 # Calculate priorities for each file
344 for p in make.pkgdata.keys():
345 oefile_priority[p] = calc_oefile_priority(p)
347 n = len(make.pkgdata.keys())
352 oe.debug(1, "OEMAKE building providers hashes")
354 # Build forward and reverse provider hashes
355 # Forward: virtual -> [filenames]
356 # Reverse: PN -> [virtuals]
357 for f in make.pkgdata.keys():
360 pn = oe.data.getVar('PN', d, 1)
361 provides = Set([pn] + (oe.data.getVar("PROVIDES", d, 1) or "").split())
363 if not pn_provides.has_key(pn):
364 pn_provides[pn] = Set()
365 pn_provides[pn] |= provides
367 for provide in provides:
368 if not providers.has_key(provide):
369 providers[provide] = []
370 providers[provide].append(f)
372 deps = (oe.data.getVar("DEPENDS", d, 1) or "").split()
383 sys.stdout.write("\n")
385 # Build package list for "oemake world"
386 oe.debug(1, "OEMAKE collating packages for \"world\"")
387 for f in make.pkgdata.keys():
389 if oe.data.getVar('BROKEN', d, 1):
392 pn = oe.data.getVar('PN', d, 1)
393 for p in pn_provides[pn]:
394 if p in all_depends or p.startswith('virtual/'):
398 __world_target.add(pn)
400 def myProgressCallback( x, y, f ):
403 if os.isatty(sys.stdout.fileno()):
404 sys.stdout.write("\rNOTE: Parsing .oe files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
408 sys.stdout.write("Parsing .oe files, please wait...")
411 sys.stdout.write("done.")
419 if __name__ == "__main__":
421 if "OEDEBUG" in os.environ:
422 oedebug = int(os.environ["OEDEBUG"])
424 make.options, args = handle_options( sys.argv )
426 if not make.options.cmd:
427 make.options.cmd = "build"
429 if make.options.cmd in __depcmds:
430 __depcmd=__depcmds[make.options.cmd]
432 __depcmd=make.options.cmd
438 for f in make.options.file:
440 make.cfg = oe.parse.handle(f, make.cfg)
442 oe.fatal("Unable to open %s" % f)
445 make.cfg = oe.parse.handle("conf/oe.conf", make.cfg)
447 oe.fatal("Unable to open oe.conf")
449 if not oe.data.getVar("BUILDNAME", make.cfg):
450 oe.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), make.cfg)
452 buildname = oe.data.getVar("BUILDNAME", make.cfg)
454 ignore = oe.data.getVar("ASSUME_PROVIDED", make.cfg, 1) or ""
455 __ignored_dependencies = ignore.split()
457 collections = oe.data.getVar("OEFILE_COLLECTIONS", make.cfg, 1)
459 collection_list = collections.split()
460 for c in collection_list:
461 regex = oe.data.getVar("OEFILE_PATTERN_%s" % c, make.cfg, 1)
463 oe.error("OEFILE_PATTERN_%s not defined" % c)
465 priority = oe.data.getVar("OEFILE_PRIORITY_%s" % c, make.cfg, 1)
467 oe.error("OEFILE_PRIORITY_%s not defined" % c)
470 cre = re.compile(regex)
472 oe.error("OEFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
476 oefile_config_priorities.append((cre, pri))
478 oe.error("invalid value for OEFILE_PRIORITY_%s: \"%s\"" % (c, priority))
482 if not pkgs_to_build:
484 pkgs_to_build.extend(args)
485 if not pkgs_to_build:
486 oepkgs = oe.data.getVar('OEPKGS', make.cfg, 1)
488 pkgs_to_build = oepkgs.split()
489 if not pkgs_to_build:
490 print "Nothing to build. Use 'oemake world' to build everything."
493 __stats["attempt"] = 0
494 __stats["success"] = 0
498 # Import Psyco if available and not disabled
499 if not make.options.disable_psyco:
504 oe.note("Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
506 psyco.bind( make.collect_oefiles )
508 oe.note("You have disabled Psyco. This decreases performance.")
511 oe.debug(1, "OEMAKE collecting .oe files")
512 make.collect_oefiles( myProgressCallback )
513 oe.debug(1, "OEMAKE parsing complete")
516 if make.options.parse_only:
517 print "Requested parsing .oe files only. Exiting."
521 if 'world' in pkgs_to_build:
522 pkgs_to_build.remove('world')
523 for t in __world_target:
524 pkgs_to_build.append(t)
526 oe.event.fire(oe.event.BuildStarted(buildname, pkgs_to_build, make.cfg))
528 for k in pkgs_to_build:
531 if buildPackage(k) == 0:
534 except oe.build.EventException:
535 oe.error("Build of " + k + " failed")
539 if make.options.abort:
542 oe.event.fire(oe.event.BuildCompleted(buildname, pkgs_to_build, make.cfg))
544 print "Build statistics:"
545 print " Attempted builds: %d" % __stats["attempt"]
546 if __stats["fail"] != 0:
547 print " Failed builds: %d" % __stats["fail"]
548 if __stats["deps"] != 0:
549 print " Dependencies not satisfied: %d" % __stats["deps"]
550 if __stats["fail"] != 0 or __stats["deps"] != 0:
554 except KeyboardInterrupt:
555 print "\nNOTE: KeyboardInterrupt - Build not completed."