aboutsummaryrefslogtreecommitdiffstats
path: root/bitbake
diff options
context:
space:
mode:
authorRichard Purdie <richard@openedhand.com>2008-01-06 16:51:51 +0000
committerRichard Purdie <richard@openedhand.com>2008-01-06 16:51:51 +0000
commit7821f2250d16e24097d973c34197db7fd60bc51a (patch)
treea65ca61381af497265f02b5363196b36fe1b0150 /bitbake
parentc7fca99aab060efe14332ce6d913bc7d346a4478 (diff)
downloadopenembedded-core-contrib-7821f2250d16e24097d973c34197db7fd60bc51a.tar.gz
bitbake: Sync with bitbake upstream for various fixes
git-svn-id: https://svn.o-hand.com/repos/poky/trunk@3411 311d38ba-8fff-0310-9ca6-ca027cbcb966
Diffstat (limited to 'bitbake')
-rw-r--r--bitbake/ChangeLog10
-rw-r--r--bitbake/lib/bb/cooker.py77
-rw-r--r--bitbake/lib/bb/runqueue.py399
-rw-r--r--bitbake/lib/bb/shell.py36
4 files changed, 391 insertions, 131 deletions
diff --git a/bitbake/ChangeLog b/bitbake/ChangeLog
index 4fddeca86c..4f3eafe2ba 100644
--- a/bitbake/ChangeLog
+++ b/bitbake/ChangeLog
@@ -25,6 +25,16 @@ Changes in BitBake 1.8.x:
faster at the expense of not creating mirror tarballs.
- SRCREV handling updates, improvements and fixes from Poky
- Add bb.utils.lockfile() and bb.utils.unlockfile() from Poky
+ - Add support for task selfstamp and lockfiles flags
+ - Disable task number acceleration since it can allow the tasks to run
+ out of sequence
+ - Improve runqueue code comments
+ - Add task scheduler abstraction and some example schedulers
+ - Improve circular dependency chain debugging code and user feedback
+ - Don't give a stacktrace for invalid tasks, have a user friendly message (#3431)
+ - Add support for "-e target" (#3432)
+ - Fix shell showdata command (#3259)
+ - Fix shell data updating problems (#1880)
Changes in Bitbake 1.8.8:
- Rewrite svn fetcher to make adding extra operations easier
diff --git a/bitbake/lib/bb/cooker.py b/bitbake/lib/bb/cooker.py
index c16709e552..c6597c52f9 100644
--- a/bitbake/lib/bb/cooker.py
+++ b/bitbake/lib/bb/cooker.py
@@ -67,6 +67,10 @@ class BBCooker:
if not self.configuration.cmd:
self.configuration.cmd = bb.data.getVar("BB_DEFAULT_TASK", self.configuration.data) or "build"
+ bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, True)
+ if bbpkgs:
+ self.configuration.pkgs_to_build.extend(bbpkgs.split())
+
#
# Special updated configuration we use for firing events
#
@@ -158,29 +162,68 @@ class BBCooker:
prefstr)
- def showEnvironment( self ):
- """Show the outer or per-package environment"""
- if self.configuration.buildfile:
+ def showEnvironment(self , buildfile = None, pkgs_to_build = []):
+ """
+ Show the outer or per-package environment
+ """
+ fn = None
+ envdata = None
+
+ if 'world' in pkgs_to_build:
+ print "'world' is not a valid target for --environment."
+ sys.exit(1)
+
+ if len(pkgs_to_build) > 1:
+ print "Only one target can be used with the --environment option."
+ sys.exit(1)
+
+ if buildfile:
+ if len(pkgs_to_build) > 0:
+ print "No target should be used with the --environment and --buildfile options."
+ sys.exit(1)
self.cb = None
self.bb_cache = bb.cache.init(self)
- bf = self.matchFile(self.configuration.buildfile)
+ fn = self.matchFile(buildfile)
+ elif len(pkgs_to_build) == 1:
+ self.updateCache()
+
+ localdata = data.createCopy(self.configuration.data)
+ bb.data.update_data(localdata)
+ bb.data.expandKeys(localdata)
+
+ taskdata = bb.taskdata.TaskData(self.configuration.abort)
+
+ try:
+ taskdata.add_provider(localdata, self.status, pkgs_to_build[0])
+ taskdata.add_unresolved(localdata, self.status)
+ except bb.providers.NoProvider:
+ sys.exit(1)
+
+ targetid = taskdata.getbuild_id(pkgs_to_build[0])
+ fnid = taskdata.build_targets[targetid][0]
+ fn = taskdata.fn_index[fnid]
+ else:
+ envdata = self.configuration.data
+
+ if fn:
try:
- self.configuration.data = self.bb_cache.loadDataFull(bf, self.configuration.data)
+ envdata = self.bb_cache.loadDataFull(fn, self.configuration.data)
except IOError, e:
- bb.msg.fatal(bb.msg.domain.Parsing, "Unable to read %s: %s" % (bf, e))
+ bb.msg.fatal(bb.msg.domain.Parsing, "Unable to read %s: %s" % (fn, e))
except Exception, e:
bb.msg.fatal(bb.msg.domain.Parsing, "%s" % e)
+
# emit variables and shell functions
try:
- data.update_data( self.configuration.data )
- data.emit_env(sys.__stdout__, self.configuration.data, True)
+ data.update_data( envdata )
+ data.emit_env(sys.__stdout__, envdata, True)
except Exception, e:
bb.msg.fatal(bb.msg.domain.Parsing, "%s" % e)
# emit the metadata which isnt valid shell
- data.expandKeys( self.configuration.data )
- for e in self.configuration.data.keys():
- if data.getVarFlag( e, 'python', self.configuration.data ):
- sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, self.configuration.data, 1)))
+ data.expandKeys( envdata )
+ for e in envdata.keys():
+ if data.getVarFlag( e, 'python', envdata ):
+ sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, envdata, 1)))
def generateDotGraph( self, pkgs_to_build, ignore_deps ):
"""
@@ -338,8 +381,6 @@ class BBCooker:
except ImportError, details:
bb.msg.fatal(bb.msg.domain.Parsing, "Sorry, shell not available (%s)" % details )
else:
- bb.data.update_data( self.configuration.data )
- bb.data.expandKeys( self.configuration.data )
shell.start( self )
sys.exit( 0 )
@@ -519,7 +560,7 @@ class BBCooker:
"""
if self.configuration.show_environment:
- self.showEnvironment()
+ self.showEnvironment(self.configuration.buildfile, self.configuration.pkgs_to_build)
sys.exit( 0 )
self.buildSetVars()
@@ -539,11 +580,7 @@ class BBCooker:
pkgs_to_build = self.configuration.pkgs_to_build
- bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
- if bbpkgs:
- pkgs_to_build.extend(bbpkgs.split())
- if len(pkgs_to_build) == 0 and not self.configuration.show_versions \
- and not self.configuration.show_environment:
+ if len(pkgs_to_build) == 0 and not self.configuration.show_versions:
print "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help'"
print "for usage information."
sys.exit(0)
diff --git a/bitbake/lib/bb/runqueue.py b/bitbake/lib/bb/runqueue.py
index 2f80dd4c88..68ef3a722f 100644
--- a/bitbake/lib/bb/runqueue.py
+++ b/bitbake/lib/bb/runqueue.py
@@ -51,6 +51,88 @@ class RunQueueStats:
def taskSkipped(self):
self.skipped = self.skipped + 1
+class RunQueueScheduler:
+ """
+ Control the order tasks are scheduled in.
+ """
+ def __init__(self, runqueue):
+ """
+ The default scheduler just returns the first buildable task (the
+ priority map is sorted by task numer)
+ """
+ self.rq = runqueue
+ numTasks = len(self.rq.runq_fnid)
+
+ self.prio_map = []
+ self.prio_map.extend(range(numTasks))
+
+ def next(self):
+ """
+ Return the id of the first task we find that is buildable
+ """
+ for task1 in range(len(self.rq.runq_fnid)):
+ task = self.prio_map[task1]
+ if self.rq.runq_running[task] == 1:
+ continue
+ if self.rq.runq_buildable[task] == 1:
+ return task
+
+class RunQueueSchedulerSpeed(RunQueueScheduler):
+ """
+ A scheduler optimised for speed. The priority map is sorted by task weight,
+ heavier weighted tasks (tasks needed by the most other tasks) are run first.
+ """
+ def __init__(self, runqueue):
+ """
+ The priority map is sorted by task weight.
+ """
+ from copy import deepcopy
+
+ self.rq = runqueue
+
+ sortweight = deepcopy(self.rq.runq_weight)
+ sortweight.sort()
+ copyweight = deepcopy(self.rq.runq_weight)
+ self.prio_map = []
+
+ for weight in sortweight:
+ idx = copyweight.index(weight)
+ self.prio_map.append(idx)
+ copyweight[idx] = -1
+
+ self.prio_map.reverse()
+
+class RunQueueSchedulerCompletion(RunQueueSchedulerSpeed):
+ """
+ A scheduler optimised to complete .bb files are quickly as possible. The
+ priority map is sorted by task weight, but then reordered so once a given
+ .bb file starts to build, its completed as quickly as possible. This works
+ well where disk space is at a premium and classes like OE's rm_work are in
+ force.
+ """
+ def __init__(self, runqueue):
+ RunQueueSchedulerSpeed.__init__(self, runqueue)
+ from copy import deepcopy
+
+ #FIXME - whilst this groups all fnids together it does not reorder the
+ #fnid groups optimally.
+
+ basemap = deepcopy(self.prio_map)
+ self.prio_map = []
+ while (len(basemap) > 0):
+ entry = basemap.pop(0)
+ self.prio_map.append(entry)
+ fnid = self.rq.runq_fnid[entry]
+ todel = []
+ for entry in basemap:
+ entry_fnid = self.rq.runq_fnid[entry]
+ if entry_fnid == fnid:
+ todel.append(basemap.index(entry))
+ self.prio_map.append(entry)
+ todel.reverse()
+ for idx in todel:
+ del basemap[idx]
+
class RunQueue:
"""
BitBake Run Queue implementation
@@ -71,14 +153,158 @@ class RunQueue:
self.runq_task = []
self.runq_depends = []
self.runq_revdeps = []
- self.runq_weight = []
- self.prio_map = []
def get_user_idstring(self, task):
fn = self.taskData.fn_index[self.runq_fnid[task]]
taskname = self.runq_task[task]
return "%s, %s" % (fn, taskname)
+ def circular_depchains_handler(self, tasks):
+ """
+ Some tasks aren't buildable, likely due to circular dependency issues.
+ Identify the circular dependencies and print them in a user readable format.
+ """
+ from copy import deepcopy
+
+ valid_chains = []
+ explored_deps = {}
+ msgs = []
+
+ def chain_reorder(chain):
+ """
+ Reorder a dependency chain so the lowest task id is first
+ """
+ lowest = 0
+ new_chain = []
+ for entry in range(len(chain)):
+ if chain[entry] < chain[lowest]:
+ lowest = entry
+ new_chain.extend(chain[lowest:])
+ new_chain.extend(chain[:lowest])
+ return new_chain
+
+ def chain_compare_equal(chain1, chain2):
+ """
+ Compare two dependency chains and see if they're the same
+ """
+ if len(chain1) != len(chain2):
+ return False
+ for index in range(len(chain1)):
+ if chain1[index] != chain2[index]:
+ return False
+ return True
+
+ def chain_array_contains(chain, chain_array):
+ """
+ Return True if chain_array contains chain
+ """
+ for ch in chain_array:
+ if chain_compare_equal(ch, chain):
+ return True
+ return False
+
+ def find_chains(taskid, prev_chain):
+ prev_chain.append(taskid)
+ total_deps = []
+ total_deps.extend(self.runq_revdeps[taskid])
+ for revdep in self.runq_revdeps[taskid]:
+ if revdep in prev_chain:
+ idx = prev_chain.index(revdep)
+ # To prevent duplicates, reorder the chain to start with the lowest taskid
+ # and search through an array of those we've already printed
+ chain = prev_chain[idx:]
+ new_chain = chain_reorder(chain)
+ if not chain_array_contains(new_chain, valid_chains):
+ valid_chains.append(new_chain)
+ msgs.append("Dependency loop #%d found:\n" % len(valid_chains))
+ for dep in new_chain:
+ msgs.append(" Task %s (%s) (depends: %s)\n" % (dep, self.get_user_idstring(dep), self.runq_depends[dep]))
+ msgs.append("\n")
+ if len(valid_chains) > 10:
+ msgs.append("Aborted dependency loops search after 10 matches.\n")
+ return msgs
+ continue
+ scan = False
+ if revdep not in explored_deps:
+ scan = True
+ elif revdep in explored_deps[revdep]:
+ scan = True
+ else:
+ for dep in prev_chain:
+ if dep in explored_deps[revdep]:
+ scan = True
+ if scan:
+ find_chains(revdep, deepcopy(prev_chain))
+ for dep in explored_deps[revdep]:
+ if dep not in total_deps:
+ total_deps.append(dep)
+
+ explored_deps[taskid] = total_deps
+
+ for task in tasks:
+ find_chains(task, [])
+
+ return msgs
+
+ def calculate_task_weights(self, endpoints):
+ """
+ Calculate a number representing the "weight" of each task. Heavier weighted tasks
+ have more dependencies and hence should be executed sooner for maximum speed.
+
+ This function also sanity checks the task list finding tasks that its not
+ possible to execute due to circular dependencies.
+ """
+
+ numTasks = len(self.runq_fnid)
+ weight = []
+ deps_left = []
+ task_done = []
+
+ for listid in range(numTasks):
+ task_done.append(False)
+ weight.append(0)
+ deps_left.append(len(self.runq_revdeps[listid]))
+
+ for listid in endpoints:
+ weight[listid] = 1
+ task_done[listid] = True
+
+ while 1:
+ next_points = []
+ for listid in endpoints:
+ for revdep in self.runq_depends[listid]:
+ weight[revdep] = weight[revdep] + weight[listid]
+ deps_left[revdep] = deps_left[revdep] - 1
+ if deps_left[revdep] == 0:
+ next_points.append(revdep)
+ task_done[revdep] = True
+ endpoints = next_points
+ if len(next_points) == 0:
+ break
+
+ # Circular dependency sanity check
+ problem_tasks = []
+ for task in range(numTasks):
+ if task_done[task] is False or deps_left[task] != 0:
+ problem_tasks.append(task)
+ bb.msg.debug(2, bb.msg.domain.RunQueue, "Task %s (%s) is not buildable\n" % (task, self.get_user_idstring(task)))
+ bb.msg.debug(2, bb.msg.domain.RunQueue, "(Complete marker was %s and the remaining dependency count was %s)\n\n" % (task_done[task], deps_left[task]))
+
+ if problem_tasks:
+ message = "Unbuildable tasks were found.\n"
+ message = message + "These are usually caused by circular dependencies and any circular dependency chains found will be printed below. Increase the debug level to see a list of unbuildable tasks.\n\n"
+ message = message + "Identifying dependency loops (this may take a short while)...\n"
+ bb.msg.error(bb.msg.domain.RunQueue, message)
+
+ msgs = self.circular_depchains_handler(problem_tasks)
+
+ message = "\n"
+ for msg in msgs:
+ message = message + msg
+ bb.msg.fatal(bb.msg.domain.RunQueue, message)
+
+ return weight
+
def prepare_runqueue(self):
"""
Turn a set of taskData into a RunQueue and compute data needed
@@ -86,9 +312,7 @@ class RunQueue:
"""
depends = []
- runq_weight1 = []
runq_build = []
- runq_done = []
taskData = self.taskData
@@ -98,6 +322,17 @@ class RunQueue:
bb.msg.note(1, bb.msg.domain.RunQueue, "Preparing runqueue")
+ # Step A - Work out a list of tasks to run
+ #
+ # Taskdata gives us a list of possible providers for a every target
+ # ordered by priority (build_targets, run_targets). It also gives
+ # information on each of those providers.
+ #
+ # To create the actual list of tasks to execute we fix the list of
+ # providers and then resolve the dependencies into task IDs. This
+ # process is repeated for each type of dependency (tdepends, deptask,
+ # rdeptast, recrdeptask, idepends).
+
for task in range(len(taskData.tasks_name)):
fnid = taskData.tasks_fnid[task]
fn = taskData.fn_index[fnid]
@@ -105,9 +340,15 @@ class RunQueue:
if fnid not in taskData.failed_fnids:
+ # Resolve task internal dependencies
+ #
+ # e.g. addtask before X after Y
depends = taskData.tasks_tdepends[task]
- # Resolve Depends
+ # Resolve 'deptask' dependencies
+ #
+ # e.g. do_sometask[deptask] = "do_someothertask"
+ # (makes sure sometask runs after someothertask of all DEPENDS)
if 'deptask' in task_deps and taskData.tasks_name[task] in task_deps['deptask']:
tasknames = task_deps['deptask'][taskData.tasks_name[task]].split()
for depid in taskData.depids[fnid]:
@@ -119,7 +360,10 @@ class RunQueue:
for taskname in tasknames:
depends.append(taskData.gettask_id(dep, taskname))
- # Resolve Runtime Depends
+ # Resolve 'rdeptask' dependencies
+ #
+ # e.g. do_sometask[rdeptask] = "do_someothertask"
+ # (makes sure sometask runs after someothertask of all RDEPENDS)
if 'rdeptask' in task_deps and taskData.tasks_name[task] in task_deps['rdeptask']:
taskname = task_deps['rdeptask'][taskData.tasks_name[task]]
for depid in taskData.rdepids[fnid]:
@@ -129,6 +373,10 @@ class RunQueue:
dep = taskData.fn_index[depdata]
depends.append(taskData.gettask_id(dep, taskname))
+ # Resolve inter-task dependencies
+ #
+ # e.g. do_sometask[depends] = "targetname:do_someothertask"
+ # (makes sure sometask runs after targetname's someothertask)
idepends = taskData.tasks_idepends[task]
for idepend in idepends:
depid = int(idepend.split(":")[0])
@@ -207,9 +455,10 @@ class RunQueue:
if nextdepid not in dep_seen:
add_recursive_build(nextdepid, fnid)
-
- # Resolve Recursive Runtime Depends
- # Also includes all thier build depends, intertask depends and runtime depends
+ # Resolve recursive 'recrdeptask' dependencies
+ #
+ # e.g. do_sometask[recrdeptask] = "do_someothertask"
+ # (makes sure sometask runs after someothertask of all DEPENDS, RDEPENDS and intertask dependencies, recursively)
if 'recrdeptask' in task_deps and taskData.tasks_name[task] in task_deps['recrdeptask']:
for taskname in task_deps['recrdeptask'][taskData.tasks_name[task]].split():
dep_seen = []
@@ -223,7 +472,7 @@ class RunQueue:
depid = int(idepend.split(":")[0])
add_recursive_build(depid, fnid)
- #Prune self references
+ # Rmove all self references
if task in depends:
newdep = []
bb.msg.debug(2, bb.msg.domain.RunQueue, "Task %s (%s %s) contains self reference! %s" % (task, taskData.fn_index[taskData.tasks_fnid[task]], taskData.tasks_name[task], depends))
@@ -237,11 +486,14 @@ class RunQueue:
self.runq_task.append(taskData.tasks_name[task])
self.runq_depends.append(Set(depends))
self.runq_revdeps.append(Set())
- self.runq_weight.append(0)
- runq_weight1.append(0)
runq_build.append(0)
- runq_done.append(0)
+
+ # Step B - Mark all active tasks
+ #
+ # Start with the tasks we were asked to run and mark all dependencies
+ # as active too. If the task is to be 'forced', clear its stamp. Once
+ # all active tasks are marked, prune the ones we don't need.
bb.msg.note(2, bb.msg.domain.RunQueue, "Marking Active Tasks")
@@ -280,11 +532,17 @@ class RunQueue:
if fnid in taskData.failed_fnids:
continue
+ if target[1] not in taskData.tasks_lookup[fnid]:
+ bb.msg.fatal(bb.msg.domain.RunQueue, "Task %s does not exist for target %s" % (target[1], target[0]))
+
listid = taskData.tasks_lookup[fnid][target[1]]
mark_active(listid, 1)
- # Prune inactive tasks
+ # Step C - Prune all inactive tasks
+ #
+ # Once all active tasks are marked, prune the ones we don't need.
+
maps = []
delcount = 0
for listid in range(len(self.runq_fnid)):
@@ -294,14 +552,16 @@ class RunQueue:
del self.runq_fnid[listid-delcount]
del self.runq_task[listid-delcount]
del self.runq_depends[listid-delcount]
- del self.runq_weight[listid-delcount]
- del runq_weight1[listid-delcount]
del runq_build[listid-delcount]
- del runq_done[listid-delcount]
del self.runq_revdeps[listid-delcount]
delcount = delcount + 1
maps.append(-1)
+ #
+ # Step D - Sanity checks and computation
+ #
+
+ # Check to make sure we still have tasks to run
if len(self.runq_fnid) == 0:
if not taskData.abort:
bb.msg.note(1, bb.msg.domain.RunQueue, "All possible tasks have been run but build incomplete (--continue mode). See errors above for incomplete tasks.")
@@ -310,6 +570,8 @@ class RunQueue:
bb.msg.note(2, bb.msg.domain.RunQueue, "Pruned %s inactive tasks, %s left" % (delcount, len(self.runq_fnid)))
+ # Remap the dependencies to account for the deleted tasks
+ # Check we didn't delete a task we depend on
for listid in range(len(self.runq_fnid)):
newdeps = []
origdeps = self.runq_depends[listid]
@@ -321,62 +583,37 @@ class RunQueue:
bb.msg.note(2, bb.msg.domain.RunQueue, "Assign Weightings")
+ # Generate a list of reverse dependencies to ease future calculations
for listid in range(len(self.runq_fnid)):
for dep in self.runq_depends[listid]:
self.runq_revdeps[dep].add(listid)
+ # Identify tasks at the end of dependency chains
+ # Error on circular dependency loops (length two)
endpoints = []
for listid in range(len(self.runq_fnid)):
revdeps = self.runq_revdeps[listid]
if len(revdeps) == 0:
- runq_done[listid] = 1
- self.runq_weight[listid] = 1
endpoints.append(listid)
for dep in revdeps:
if dep in self.runq_depends[listid]:
#self.dump_data(taskData)
bb.msg.fatal(bb.msg.domain.RunQueue, "Task %s (%s) has circular dependency on %s (%s)" % (taskData.fn_index[self.runq_fnid[dep]], self.runq_task[dep] , taskData.fn_index[self.runq_fnid[listid]], self.runq_task[listid]))
- runq_weight1[listid] = len(revdeps)
bb.msg.note(2, bb.msg.domain.RunQueue, "Compute totals (have %s endpoint(s))" % len(endpoints))
- while 1:
- next_points = []
- for listid in endpoints:
- for revdep in self.runq_depends[listid]:
- self.runq_weight[revdep] = self.runq_weight[revdep] + self.runq_weight[listid]
- runq_weight1[revdep] = runq_weight1[revdep] - 1
- if runq_weight1[revdep] == 0:
- next_points.append(revdep)
- runq_done[revdep] = 1
- endpoints = next_points
- if len(next_points) == 0:
- break
- # Sanity Checks
- for task in range(len(self.runq_fnid)):
- if runq_done[task] == 0:
- seen = []
- deps_seen = []
- def print_chain(taskid, finish):
- seen.append(taskid)
- for revdep in self.runq_revdeps[taskid]:
- if runq_done[revdep] == 0 and revdep not in seen and not finish:
- bb.msg.error(bb.msg.domain.RunQueue, "Task %s (%s) (depends: %s)" % (revdep, self.get_user_idstring(revdep), self.runq_depends[revdep]))
- if revdep in deps_seen:
- bb.msg.error(bb.msg.domain.RunQueue, "Chain ends at Task %s (%s)" % (revdep, self.get_user_idstring(revdep)))
- finish = True
- return
- for dep in self.runq_depends[revdep]:
- deps_seen.append(dep)
- print_chain(revdep, finish)
- print_chain(task, False)
- bb.msg.fatal(bb.msg.domain.RunQueue, "Task %s (%s) not processed!\nThis is probably a circular dependency (the chain might be printed above)." % (task, self.get_user_idstring(task)))
- if runq_weight1[task] != 0:
- bb.msg.fatal(bb.msg.domain.RunQueue, "Task %s (%s) count not zero!" % (task, self.get_user_idstring(task)))
-
-
- # Check for multiple tasks building the same provider
+ # Calculate task weights
+ # Check of higher length circular dependencies
+ self.runq_weight = self.calculate_task_weights(endpoints)
+
+ # Decide what order to execute the tasks in, pick a scheduler
+ # FIXME - Allow user selection
+ #self.sched = RunQueueScheduler(self)
+ self.sched = RunQueueSchedulerSpeed(self)
+ #self.sched = RunQueueSchedulerCompletion(self)
+
+ # Sanity Check - Check for multiple tasks building the same provider
prov_list = {}
seen_fn = []
for task in range(len(self.runq_fnid)):
@@ -397,21 +634,6 @@ class RunQueue:
#if error:
# bb.msg.fatal(bb.msg.domain.RunQueue, "Corrupted metadata configuration detected, aborting...")
-
- # Make a weight sorted map
- from copy import deepcopy
-
- sortweight = deepcopy(self.runq_weight)
- sortweight.sort()
- copyweight = deepcopy(self.runq_weight)
- self.prio_map = []
-
- for weight in sortweight:
- idx = copyweight.index(weight)
- self.prio_map.append(idx)
- copyweight[idx] = -1
- self.prio_map.reverse()
-
#self.dump_data(taskData)
def execute_runqueue(self):
@@ -483,18 +705,6 @@ class RunQueue:
taskname = self.runq_task[revdep]
bb.msg.debug(1, bb.msg.domain.RunQueue, "Marking task %s (%s, %s) as buildable" % (revdep, fn, taskname))
- def get_next_task(self):
- """
- Return the id of the highest priority task that is buildable
- """
- for task1 in range(len(self.runq_fnid)):
- task = self.prio_map[task1]
- if self.runq_running[task] == 1:
- continue
- if self.runq_buildable[task] == 1:
- return task
- return None
-
def execute_runqueue_internal(self):
"""
Run the tasks in a queue prepared by prepare_runqueue
@@ -511,20 +721,21 @@ class RunQueue:
def sigint_handler(signum, frame):
raise KeyboardInterrupt
+ # RP - this code allows tasks to run out of the correct order - disabled, FIXME
# Find any tasks with current stamps and remove them from the queue
- for task1 in range(len(self.runq_fnid)):
- task = self.prio_map[task1]
- fn = self.taskData.fn_index[self.runq_fnid[task]]
- taskname = self.runq_task[task]
- if bb.build.stamp_is_current(taskname, self.dataCache, fn):
- bb.msg.debug(2, bb.msg.domain.RunQueue, "Stamp current task %s (%s)" % (task, self.get_user_idstring(task)))
- self.runq_running[task] = 1
- self.task_complete(task)
- self.stats.taskCompleted()
- self.stats.taskSkipped()
+ #for task1 in range(len(self.runq_fnid)):
+ # task = self.prio_map[task1]
+ # fn = self.taskData.fn_index[self.runq_fnid[task]]
+ # taskname = self.runq_task[task]
+ # if bb.build.stamp_is_current(taskname, self.dataCache, fn):
+ # bb.msg.debug(2, bb.msg.domain.RunQueue, "Stamp current task %s (%s)" % (task, self.get_user_idstring(task)))
+ # self.runq_running[task] = 1
+ # self.task_complete(task)
+ # self.stats.taskCompleted()
+ # self.stats.taskSkipped()
while True:
- task = self.get_next_task()
+ task = self.sched.next()
if task is not None:
fn = self.taskData.fn_index[self.runq_fnid[task]]
diff --git a/bitbake/lib/bb/shell.py b/bitbake/lib/bb/shell.py
index fc213c3f4a..745091fb7d 100644
--- a/bitbake/lib/bb/shell.py
+++ b/bitbake/lib/bb/shell.py
@@ -68,7 +68,6 @@ leave_mainloop = False
last_exception = None
cooker = None
parsed = False
-initdata = None
debug = os.environ.get( "BBSHELL_DEBUG", "" )
##########################################################################
@@ -156,11 +155,14 @@ class BitBakeShellCommands:
cooker.configuration.cmd = cmd
td = taskdata.TaskData(cooker.configuration.abort)
+ localdata = data.createCopy(cooker.configuration.data)
+ data.update_data(localdata)
+ data.expandKeys(localdata)
try:
tasks = []
for name in names:
- td.add_provider(cooker.configuration.data, cooker.status, name)
+ td.add_provider(localdata, cooker.status, name)
providers = td.get_provider(name)
if len(providers) == 0:
@@ -168,9 +170,9 @@ class BitBakeShellCommands:
tasks.append([name, "do_%s" % cooker.configuration.cmd])
- td.add_unresolved(cooker.configuration.data, cooker.status)
+ td.add_unresolved(localdata, cooker.status)
- rq = runqueue.RunQueue(cooker, cooker.configuration.data, cooker.status, td, tasks)
+ rq = runqueue.RunQueue(cooker, localdata, cooker.status, td, tasks)
rq.prepare_runqueue()
rq.execute_runqueue()
@@ -217,8 +219,8 @@ class BitBakeShellCommands:
edit.usage = "<providee>"
def environment( self, params ):
- """Dump out the outer BitBake environment (see bbread)"""
- data.emit_env(sys.__stdout__, cooker.configuration.data, True)
+ """Dump out the outer BitBake environment"""
+ cooker.showEnvironment()
def exit_( self, params ):
"""Leave the BitBake Shell"""
@@ -241,11 +243,10 @@ class BitBakeShellCommands:
oldcmd = cooker.configuration.cmd
cooker.configuration.cmd = cmd
- thisdata = copy.deepcopy( initdata )
- # Caution: parse.handle modifies thisdata, hence it would
- # lead to pollution cooker.configuration.data, which is
- # why we use it on a safe copy we obtained from cooker right after
- # parsing the initial *.conf files
+ thisdata = data.createCopy(cooker.configuration.data)
+ data.update_data(thisdata)
+ data.expandKeys(thisdata)
+
try:
bbfile_data = parse.handle( bf, thisdata )
except parse.ParseError:
@@ -393,6 +394,11 @@ SRC_URI = ""
os.system( "%s %s/%s" % ( os.environ.get( "EDITOR" ), fulldirname, filename ) )
new.usage = "<directory> <filename>"
+ def package( self, params ):
+ """Execute 'package' on a providee"""
+ self.build( params, "package" )
+ package.usage = "<providee>"
+
def pasteBin( self, params ):
"""Send a command + output buffer to the pastebin at http://rafb.net/paste"""
index = params[0]
@@ -501,8 +507,8 @@ SRC_URI = ""
interpreter.interact( "SHELL: Expert Mode - BitBake Python %s\nType 'help' for more information, press CTRL-D to switch back to BBSHELL." % sys.version )
def showdata( self, params ):
- """Execute 'showdata' on a providee"""
- self.build( params, "showdata" )
+ """Show the parsed metadata for a given providee"""
+ cooker.showEnvironment(None, params)
showdata.usage = "<providee>"
def setVar( self, params ):
@@ -732,10 +738,6 @@ class BitBakeShell:
print __credits__
- # save initial cooker configuration (will be reused in file*** commands)
- global initdata
- initdata = copy.deepcopy( cooker.configuration.data )
-
def cleanup( self ):
"""Write readline history and clean up resources"""
debugOut( "writing command history" )