summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/taskdata.py
diff options
context:
space:
mode:
authorRichard Purdie <richard@openedhand.com>2006-11-16 15:02:15 +0000
committerRichard Purdie <richard@openedhand.com>2006-11-16 15:02:15 +0000
commit306b7c7a9757ead077363074e7bbac2e5c03e7c5 (patch)
tree6935017a9af749c46816881c86258f514384ba1c /bitbake/lib/bb/taskdata.py
parent65930a38e415ae4a0182e1cea1be838e0ada50ee (diff)
downloadpoky-306b7c7a9757ead077363074e7bbac2e5c03e7c5.tar.gz
bitbake: Upgrade from 1.4 -> 1.7.4ish
git-svn-id: https://svn.o-hand.com/repos/poky/trunk@863 311d38ba-8fff-0310-9ca6-ca027cbcb966
Diffstat (limited to 'bitbake/lib/bb/taskdata.py')
-rw-r--r--bitbake/lib/bb/taskdata.py558
1 files changed, 558 insertions, 0 deletions
diff --git a/bitbake/lib/bb/taskdata.py b/bitbake/lib/bb/taskdata.py
new file mode 100644
index 0000000000..181bb5e35b
--- /dev/null
+++ b/bitbake/lib/bb/taskdata.py
@@ -0,0 +1,558 @@
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"""
5BitBake 'TaskData' implementation
6
7Task data collection and handling
8
9Copyright (C) 2006 Richard Purdie
10
11This program is free software; you can redistribute it and/or modify it under
12the terms of the GNU General Public License version 2 as published by the Free
13Software Foundation
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License along with
20"""
21
22from bb import data, fetch, event, mkdirhier, utils
23import bb, os
24
25class TaskData:
26 """
27 BitBake Task Data implementation
28 """
29 def __init__(self, abort = True):
30 self.build_names_index = []
31 self.run_names_index = []
32 self.fn_index = []
33
34 self.build_targets = {}
35 self.run_targets = {}
36
37 self.external_targets = []
38
39 self.tasks_fnid = []
40 self.tasks_name = []
41 self.tasks_tdepends = []
42 # Cache to speed up task ID lookups
43 self.tasks_lookup = {}
44
45 self.depids = {}
46 self.rdepids = {}
47
48 self.consider_msgs_cache = []
49
50 self.failed_deps = []
51 self.failed_rdeps = []
52 self.failed_fnids = []
53
54 self.abort = abort
55
56 def getbuild_id(self, name):
57 """
58 Return an ID number for the build target name.
59 If it doesn't exist, create one.
60 """
61 if not name in self.build_names_index:
62 self.build_names_index.append(name)
63 return len(self.build_names_index) - 1
64
65 return self.build_names_index.index(name)
66
67 def getrun_id(self, name):
68 """
69 Return an ID number for the run target name.
70 If it doesn't exist, create one.
71 """
72 if not name in self.run_names_index:
73 self.run_names_index.append(name)
74 return len(self.run_names_index) - 1
75
76 return self.run_names_index.index(name)
77
78 def getfn_id(self, name):
79 """
80 Return an ID number for the filename.
81 If it doesn't exist, create one.
82 """
83 if not name in self.fn_index:
84 self.fn_index.append(name)
85 return len(self.fn_index) - 1
86
87 return self.fn_index.index(name)
88
89 def gettask_id(self, fn, task):
90 """
91 Return an ID number for the task matching fn and task.
92 If it doesn't exist, create one.
93 """
94 fnid = self.getfn_id(fn)
95
96 if fnid in self.tasks_lookup:
97 if task in self.tasks_lookup[fnid]:
98 return self.tasks_lookup[fnid][task]
99
100 self.tasks_name.append(task)
101 self.tasks_fnid.append(fnid)
102 self.tasks_tdepends.append([])
103
104 listid = len(self.tasks_name) - 1
105
106 if fnid not in self.tasks_lookup:
107 self.tasks_lookup[fnid] = {}
108 self.tasks_lookup[fnid][task] = listid
109
110 return listid
111
112 def add_tasks(self, fn, dataCache):
113 """
114 Add tasks for a given fn to the database
115 """
116
117 task_graph = dataCache.task_queues[fn]
118 task_deps = dataCache.task_deps[fn]
119
120 fnid = self.getfn_id(fn)
121
122 if fnid in self.failed_fnids:
123 bb.msg.fatal(bb.msg.domain.TaskData, "Trying to re-add a failed file? Something is broken...")
124
125 # Check if we've already seen this fn
126 if fnid in self.tasks_fnid:
127 return
128
129 # Work out task dependencies
130 for task in task_graph.allnodes():
131 parentids = []
132 for dep in task_graph.getparents(task):
133 parentid = self.gettask_id(fn, dep)
134 parentids.append(parentid)
135 taskid = self.gettask_id(fn, task)
136 self.tasks_tdepends[taskid].extend(parentids)
137
138 # Work out build dependencies
139 if not fnid in self.depids:
140 dependids = {}
141 for depend in dataCache.deps[fn]:
142 bb.msg.debug(2, bb.msg.domain.TaskData, "Added dependency %s for %s" % (depend, fn))
143 dependids[self.getbuild_id(depend)] = None
144 self.depids[fnid] = dependids.keys()
145
146 # Work out runtime dependencies
147 if not fnid in self.rdepids:
148 rdependids = {}
149 rdepends = dataCache.rundeps[fn]
150 rrecs = dataCache.runrecs[fn]
151 for package in rdepends:
152 for rdepend in rdepends[package]:
153 bb.msg.debug(2, bb.msg.domain.TaskData, "Added runtime dependency %s for %s" % (rdepend, fn))
154 rdependids[self.getrun_id(rdepend)] = None
155 for package in rrecs:
156 for rdepend in rrecs[package]:
157 bb.msg.debug(2, bb.msg.domain.TaskData, "Added runtime recommendation %s for %s" % (rdepend, fn))
158 rdependids[self.getrun_id(rdepend)] = None
159 self.rdepids[fnid] = rdependids.keys()
160
161 for dep in self.depids[fnid]:
162 if dep in self.failed_deps:
163 self.fail_fnid(fnid)
164 return
165 for dep in self.rdepids[fnid]:
166 if dep in self.failed_rdeps:
167 self.fail_fnid(fnid)
168 return
169
170 def have_build_target(self, target):
171 """
172 Have we a build target matching this name?
173 """
174 targetid = self.getbuild_id(target)
175
176 if targetid in self.build_targets:
177 return True
178 return False
179
180 def have_runtime_target(self, target):
181 """
182 Have we a runtime target matching this name?
183 """
184 targetid = self.getrun_id(target)
185
186 if targetid in self.run_targets:
187 return True
188 return False
189
190 def add_build_target(self, fn, item):
191 """
192 Add a build target.
193 If already present, append the provider fn to the list
194 """
195 targetid = self.getbuild_id(item)
196 fnid = self.getfn_id(fn)
197
198 if targetid in self.build_targets:
199 if fnid in self.build_targets[targetid]:
200 return
201 self.build_targets[targetid].append(fnid)
202 return
203 self.build_targets[targetid] = [fnid]
204
205 def add_runtime_target(self, fn, item):
206 """
207 Add a runtime target.
208 If already present, append the provider fn to the list
209 """
210 targetid = self.getrun_id(item)
211 fnid = self.getfn_id(fn)
212
213 if targetid in self.run_targets:
214 if fnid in self.run_targets[targetid]:
215 return
216 self.run_targets[targetid].append(fnid)
217 return
218 self.run_targets[targetid] = [fnid]
219
220 def mark_external_target(self, item):
221 """
222 Mark a build target as being externally requested
223 """
224 targetid = self.getbuild_id(item)
225
226 if targetid not in self.external_targets:
227 self.external_targets.append(targetid)
228
229 def get_unresolved_build_targets(self, dataCache):
230 """
231 Return a list of build targets who's providers
232 are unknown.
233 """
234 unresolved = []
235 for target in self.build_names_index:
236 if target in dataCache.ignored_dependencies:
237 continue
238 if self.build_names_index.index(target) in self.failed_deps:
239 continue
240 if not self.have_build_target(target):
241 unresolved.append(target)
242 return unresolved
243
244 def get_unresolved_run_targets(self, dataCache):
245 """
246 Return a list of runtime targets who's providers
247 are unknown.
248 """
249 unresolved = []
250 for target in self.run_names_index:
251 if target in dataCache.ignored_dependencies:
252 continue
253 if self.run_names_index.index(target) in self.failed_rdeps:
254 continue
255 if not self.have_runtime_target(target):
256 unresolved.append(target)
257 return unresolved
258
259 def get_provider(self, item):
260 """
261 Return a list of providers of item
262 """
263 targetid = self.getbuild_id(item)
264
265 return self.build_targets[targetid]
266
267 def get_dependees(self, itemid):
268 """
269 Return a list of targets which depend on item
270 """
271 dependees = []
272 for fnid in self.depids:
273 if itemid in self.depids[fnid]:
274 dependees.append(fnid)
275 return dependees
276
277 def get_dependees_str(self, item):
278 """
279 Return a list of targets which depend on item as a user readable string
280 """
281 itemid = self.getbuild_id(item)
282 dependees = []
283 for fnid in self.depids:
284 if itemid in self.depids[fnid]:
285 dependees.append(self.fn_index[fnid])
286 return dependees
287
288 def get_rdependees(self, itemid):
289 """
290 Return a list of targets which depend on runtime item
291 """
292 dependees = []
293 for fnid in self.rdepids:
294 if itemid in self.rdepids[fnid]:
295 dependees.append(fnid)
296 return dependees
297
298 def get_rdependees_str(self, item):
299 """
300 Return a list of targets which depend on runtime item as a user readable string
301 """
302 itemid = self.getrun_id(item)
303 dependees = []
304 for fnid in self.rdepids:
305 if itemid in self.rdepids[fnid]:
306 dependees.append(self.fn_index[fnid])
307 return dependees
308
309 def add_provider(self, cfgData, dataCache, item):
310 try:
311 self.add_provider_internal(cfgData, dataCache, item)
312 except bb.providers.NoProvider:
313 if self.abort:
314 bb.msg.error(bb.msg.domain.Provider, "No providers of build target %s (for %s)" % (item, self.get_dependees_str(item)))
315 raise
316 targetid = self.getbuild_id(item)
317 self.remove_buildtarget(targetid)
318
319 self.mark_external_target(item)
320
321 def add_provider_internal(self, cfgData, dataCache, item):
322 """
323 Add the providers of item to the task data
324 Mark entries were specifically added externally as against dependencies
325 added internally during dependency resolution
326 """
327
328 if item in dataCache.ignored_dependencies:
329 return
330
331 if not item in dataCache.providers:
332 bb.msg.debug(1, bb.msg.domain.Provider, "No providers of build target %s (for %s)" % (item, self.get_dependees_str(item)))
333 bb.event.fire(bb.event.NoProvider(item, cfgData))
334 raise bb.providers.NoProvider(item)
335
336 if self.have_build_target(item):
337 return
338
339 all_p = dataCache.providers[item]
340
341 eligible = bb.providers.filterProviders(all_p, item, cfgData, dataCache)
342
343 for p in eligible:
344 fnid = self.getfn_id(p)
345 if fnid in self.failed_fnids:
346 eligible.remove(p)
347
348 if not eligible:
349 bb.msg.debug(1, bb.msg.domain.Provider, "No providers of build target %s after filtering (for %s)" % (item, self.get_dependees_str(item)))
350 bb.event.fire(bb.event.NoProvider(item, cfgData))
351 raise bb.providers.NoProvider(item)
352
353 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, cfgData, 1)
354 if prefervar:
355 dataCache.preferred[item] = prefervar
356
357 discriminated = False
358 if item in dataCache.preferred:
359 for p in eligible:
360 pn = dataCache.pkg_fn[p]
361 if dataCache.preferred[item] == pn:
362 bb.msg.note(2, bb.msg.domain.Provider, "selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
363 eligible.remove(p)
364 eligible = [p] + eligible
365 discriminated = True
366 break
367
368 if len(eligible) > 1 and discriminated == False:
369 if item not in self.consider_msgs_cache:
370 providers_list = []
371 for fn in eligible:
372 providers_list.append(dataCache.pkg_fn[fn])
373 bb.msg.note(1, bb.msg.domain.Provider, "multiple providers are available for %s (%s);" % (item, ", ".join(providers_list)))
374 bb.msg.note(1, bb.msg.domain.Provider, "consider defining PREFERRED_PROVIDER_%s" % item)
375 bb.event.fire(bb.event.MultipleProviders(item,providers_list,cfgData))
376 self.consider_msgs_cache.append(item)
377
378 for fn in eligible:
379 fnid = self.getfn_id(fn)
380 if fnid in self.failed_fnids:
381 continue
382 bb.msg.debug(2, bb.msg.domain.Provider, "adding %s to satisfy %s" % (fn, item))
383 self.add_build_target(fn, item)
384 self.add_tasks(fn, dataCache)
385
386
387 #item = dataCache.pkg_fn[fn]
388
389 def add_rprovider(self, cfgData, dataCache, item):
390 """
391 Add the runtime providers of item to the task data
392 (takes item names from RDEPENDS/PACKAGES namespace)
393 """
394
395 if item in dataCache.ignored_dependencies:
396 return
397
398 if self.have_runtime_target(item):
399 return
400
401 all_p = bb.providers.getRuntimeProviders(dataCache, item)
402
403 if not all_p:
404 bb.msg.error(bb.msg.domain.Provider, "No providers of runtime build target %s (for %s)" % (item, self.get_rdependees_str(item)))
405 bb.event.fire(bb.event.NoProvider(item, cfgData, runtime=True))
406 raise bb.providers.NoRProvider(item)
407
408 eligible = bb.providers.filterProviders(all_p, item, cfgData, dataCache)
409
410 for p in eligible:
411 fnid = self.getfn_id(p)
412 if fnid in self.failed_fnids:
413 eligible.remove(p)
414
415 if not eligible:
416 bb.msg.error(bb.msg.domain.Provider, "No providers of runtime build target %s after filtering (for %s)" % (item, self.get_rdependees_str(item)))
417 bb.event.fire(bb.event.NoProvider(item, cfgData, runtime=True))
418 raise bb.providers.NoRProvider(item)
419
420 # Should use dataCache.preferred here?
421 preferred = []
422 for p in eligible:
423 pn = dataCache.pkg_fn[p]
424 provides = dataCache.pn_provides[pn]
425 for provide in provides:
426 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, cfgData, 1)
427 if prefervar == pn:
428 bb.msg.note(2, bb.msg.domain.Provider, "selecting %s to satisfy runtime %s due to PREFERRED_PROVIDERS" % (pn, item))
429 eligible.remove(p)
430 eligible = [p] + eligible
431 preferred.append(p)
432
433 if len(eligible) > 1 and len(preferred) == 0:
434 if item not in self.consider_msgs_cache:
435 providers_list = []
436 for fn in eligible:
437 providers_list.append(dataCache.pkg_fn[fn])
438 bb.msg.note(2, bb.msg.domain.Provider, "multiple providers are available for runtime %s (%s);" % (item, ", ".join(providers_list)))
439 bb.msg.note(2, bb.msg.domain.Provider, "consider defining a PREFERRED_PROVIDER entry to match runtime %s" % item)
440 bb.event.fire(bb.event.MultipleProviders(item,providers_list, cfgData, runtime=True))
441 self.consider_msgs_cache.append(item)
442
443 if len(preferred) > 1:
444 if item not in self.consider_msgs_cache:
445 providers_list = []
446 for fn in preferred:
447 providers_list.append(dataCache.pkg_fn[fn])
448 bb.msg.note(2, bb.msg.domain.Provider, "multiple preferred providers are available for runtime %s (%s);" % (item, ", ".join(providers_list)))
449 bb.msg.note(2, bb.msg.domain.Provider, "consider defining only one PREFERRED_PROVIDER entry to match runtime %s" % item)
450 bb.event.fire(bb.event.MultipleProviders(item,providers_list, cfgData, runtime=True))
451 self.consider_msgs_cache.append(item)
452
453 # run through the list until we find one that we can build
454 for fn in eligible:
455 fnid = self.getfn_id(fn)
456 if fnid in self.failed_fnids:
457 continue
458 bb.msg.debug(2, bb.msg.domain.Provider, "adding %s to satisfy runtime %s" % (fn, item))
459 self.add_runtime_target(fn, item)
460 self.add_tasks(fn, dataCache)
461
462 def fail_fnid(self, fnid):
463 """
464 Mark a file as failed (unbuildable)
465 Remove any references from build and runtime provider lists
466 """
467 if fnid in self.failed_fnids:
468 return
469 bb.msg.debug(1, bb.msg.domain.Provider, "Removing failed file %s" % self.fn_index[fnid])
470 self.failed_fnids.append(fnid)
471 for target in self.build_targets:
472 if fnid in self.build_targets[target]:
473 self.build_targets[target].remove(fnid)
474 if len(self.build_targets[target]) == 0:
475 self.remove_buildtarget(target)
476 for target in self.run_targets:
477 if fnid in self.run_targets[target]:
478 self.run_targets[target].remove(fnid)
479 if len(self.run_targets[target]) == 0:
480 self.remove_runtarget(target)
481
482 def remove_buildtarget(self, targetid):
483 """
484 Mark a build target as failed (unbuildable)
485 Trigger removal of any files that have this as a dependency
486 """
487 bb.msg.debug(1, bb.msg.domain.Provider, "Removing failed build target %s" % self.build_names_index[targetid])
488 self.failed_deps.append(targetid)
489 dependees = self.get_dependees(targetid)
490 for fnid in dependees:
491 self.fail_fnid(fnid)
492 if self.abort and targetid in self.external_targets:
493 bb.msg.error(bb.msg.domain.Provider, "No buildable providers available for required build target %s" % self.build_names_index[targetid])
494 raise bb.providers.NoProvider
495
496 def remove_runtarget(self, targetid):
497 """
498 Mark a run target as failed (unbuildable)
499 Trigger removal of any files that have this as a dependency
500 """
501 bb.msg.note(1, bb.msg.domain.Provider, "Removing failed runtime build target %s" % self.run_names_index[targetid])
502 self.failed_rdeps.append(targetid)
503 dependees = self.get_rdependees(targetid)
504 for fnid in dependees:
505 self.fail_fnid(fnid)
506
507 def add_unresolved(self, cfgData, dataCache):
508 """
509 Resolve all unresolved build and runtime targets
510 """
511 bb.msg.note(1, bb.msg.domain.TaskData, "Resolving missing task queue dependencies")
512 while 1:
513 added = 0
514 for target in self.get_unresolved_build_targets(dataCache):
515 try:
516 self.add_provider_internal(cfgData, dataCache, target)
517 added = added + 1
518 except bb.providers.NoProvider:
519 targetid = self.getbuild_id(target)
520 if self.abort and targetid in self.external_targets:
521 raise
522 self.remove_buildtarget(targetid)
523 for target in self.get_unresolved_run_targets(dataCache):
524 try:
525 self.add_rprovider(cfgData, dataCache, target)
526 added = added + 1
527 except bb.providers.NoRProvider:
528 self.remove_runtarget(self.getrun_id(target))
529 bb.msg.debug(1, bb.msg.domain.TaskData, "Resolved " + str(added) + " extra dependecies")
530 if added == 0:
531 break
532
533 def dump_data(self):
534 """
535 Dump some debug information on the internal data structures
536 """
537 bb.msg.debug(3, bb.msg.domain.TaskData, "build_names:")
538 bb.msg.debug(3, bb.msg.domain.TaskData, ", ".join(self.build_names_index))
539 bb.msg.debug(3, bb.msg.domain.TaskData, "run_names:")
540 bb.msg.debug(3, bb.msg.domain.TaskData, ", ".join(self.run_names_index))
541 bb.msg.debug(3, bb.msg.domain.TaskData, "build_targets:")
542 for target in self.build_targets.keys():
543 bb.msg.debug(3, bb.msg.domain.TaskData, " %s: %s" % (self.build_names_index[target], self.build_targets[target]))
544 bb.msg.debug(3, bb.msg.domain.TaskData, "run_targets:")
545 for target in self.run_targets.keys():
546 bb.msg.debug(3, bb.msg.domain.TaskData, " %s: %s" % (self.run_names_index[target], self.run_targets[target]))
547 bb.msg.debug(3, bb.msg.domain.TaskData, "tasks:")
548 for task in range(len(self.tasks_name)):
549 bb.msg.debug(3, bb.msg.domain.TaskData, " (%s)%s - %s: %s" % (
550 task,
551 self.fn_index[self.tasks_fnid[task]],
552 self.tasks_name[task],
553 self.tasks_tdepends[task]))
554 bb.msg.debug(3, bb.msg.domain.TaskData, "runtime ids (per fn):")
555 for fnid in self.rdepids:
556 bb.msg.debug(3, bb.msg.domain.TaskData, " %s %s: %s" % (fnid, self.fn_index[fnid], self.rdepids[fnid]))
557
558