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