ldb:ldb_dn_explode - point out that on error cases "data" is implicitly free'd
[Samba/gebeck_regimport.git] / buildtools / wafsamba / samba_deps.py
blob91737d587357c5dd595e048880259e4e3625e64a
1 # Samba automatic dependency handling and project rules
3 import Build, os, re, Environment, Logs, time
4 from samba_utils import *
5 from samba_autoconf import *
6 from samba_bundled import BUILTIN_LIBRARY
8 @conf
9 def ADD_GLOBAL_DEPENDENCY(ctx, dep):
10 '''add a dependency for all binaries and libraries'''
11 if not 'GLOBAL_DEPENDENCIES' in ctx.env:
12 ctx.env.GLOBAL_DEPENDENCIES = []
13 ctx.env.GLOBAL_DEPENDENCIES.append(dep)
16 @conf
17 def BREAK_CIRCULAR_LIBRARY_DEPENDENCIES(ctx):
18 '''indicate that circular dependencies between libraries should be broken.'''
19 ctx.env.ALLOW_CIRCULAR_LIB_DEPENDENCIES = True
22 @conf
23 def SET_SYSLIB_DEPS(conf, target, deps):
24 '''setup some implied dependencies for a SYSLIB'''
25 cache = LOCAL_CACHE(conf, 'SYSLIB_DEPS')
26 cache[target] = deps
29 def expand_subsystem_deps(bld):
30 '''expand the reverse dependencies resulting from subsystem
31 attributes of modules. This is walking over the complete list
32 of declared subsystems, and expands the samba_deps_extended list for any
33 module<->subsystem dependencies'''
35 subsystem_list = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
36 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
38 for subsystem_name in subsystem_list:
39 bld.ASSERT(subsystem_name in targets, "Subsystem target %s not declared" % subsystem_name)
40 type = targets[subsystem_name]
41 if type == 'DISABLED' or type == 'EMPTY':
42 continue
44 # for example,
45 # subsystem_name = dcerpc_server (a subsystem)
46 # subsystem = dcerpc_server (a subsystem object)
47 # module_name = rpc_epmapper (a module within the dcerpc_server subsystem)
48 # module = rpc_epmapper (a module object within the dcerpc_server subsystem)
50 subsystem = bld.name_to_obj(subsystem_name, bld.env)
51 bld.ASSERT(subsystem is not None, "Unable to find subsystem %s" % subsystem_name)
52 for d in subsystem_list[subsystem_name]:
53 module_name = d['TARGET']
54 module_type = targets[module_name]
55 if module_type in ['DISABLED', 'EMPTY']:
56 continue
57 bld.ASSERT(subsystem is not None,
58 "Subsystem target %s for %s (%s) not found" % (subsystem_name, module_name, module_type))
59 if module_type in ['SUBSYSTEM']:
60 # if a module is a plain object type (not a library) then the
61 # subsystem it is part of needs to have it as a dependency, so targets
62 # that depend on this subsystem get the modules of that subsystem
63 subsystem.samba_deps_extended.append(module_name)
64 subsystem.samba_deps_extended = unique_list(subsystem.samba_deps_extended)
68 def build_dependencies(self):
69 '''This builds the dependency list for a target. It runs after all the targets are declared
71 The reason this is not just done in the SAMBA_*() rules is that we have no way of knowing
72 the full dependency list for a target until we have all of the targets declared.
73 '''
75 if self.samba_type in ['LIBRARY', 'BINARY', 'PYTHON']:
76 self.uselib = list(self.final_syslibs)
77 self.uselib_local = list(self.final_libs)
78 self.add_objects = list(self.final_objects)
80 # extra link flags from pkg_config
81 libs = self.final_syslibs.copy()
83 (ccflags, ldflags) = library_flags(self, list(libs))
84 new_ldflags = getattr(self, 'ldflags', [])
85 new_ldflags.extend(ldflags)
86 self.ldflags = new_ldflags
88 debug('deps: computed dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
89 self.sname, self.uselib, self.uselib_local, self.add_objects)
91 if self.samba_type in ['SUBSYSTEM']:
92 # this is needed for the ccflags of libs that come from pkg_config
93 self.uselib = list(self.final_syslibs)
94 self.uselib.extend(list(self.direct_syslibs))
95 for lib in self.final_libs:
96 t = self.bld.name_to_obj(lib, self.bld.env)
97 self.uselib.extend(list(t.final_syslibs))
98 self.uselib = unique_list(self.uselib)
100 if getattr(self, 'uselib', None):
101 up_list = []
102 for l in self.uselib:
103 up_list.append(l.upper())
104 self.uselib = up_list
107 def build_includes(self):
108 '''This builds the right set of includes for a target.
110 One tricky part of this is that the includes= attribute for a
111 target needs to use paths which are relative to that targets
112 declaration directory (which we can get at via t.path).
114 The way this works is the includes list gets added as
115 samba_includes in the main build task declaration. Then this
116 function runs after all of the tasks are declared, and it
117 processes the samba_includes attribute to produce a includes=
118 attribute
121 if getattr(self, 'samba_includes', None) is None:
122 return
124 bld = self.bld
126 inc_deps = includes_objects(bld, self, set(), {})
128 includes = []
130 # maybe add local includes
131 if getattr(self, 'local_include', True) == True and getattr(self, 'local_include_first', True):
132 includes.append('.')
134 includes.extend(self.samba_includes_extended)
136 if 'EXTRA_INCLUDES' in bld.env:
137 includes.extend(bld.env['EXTRA_INCLUDES'])
139 includes.append('#')
141 inc_set = set()
142 inc_abs = []
144 for d in inc_deps:
145 t = bld.name_to_obj(d, bld.env)
146 bld.ASSERT(t is not None, "Unable to find dependency %s for %s" % (d, self.sname))
147 inclist = getattr(t, 'samba_includes_extended', [])[:]
148 if getattr(t, 'local_include', True) == True:
149 inclist.append('.')
150 if inclist == []:
151 continue
152 tpath = t.samba_abspath
153 for inc in inclist:
154 npath = tpath + '/' + inc
155 if not npath in inc_set:
156 inc_abs.append(npath)
157 inc_set.add(npath)
159 mypath = self.path.abspath(bld.env)
160 for inc in inc_abs:
161 relpath = os_path_relpath(inc, mypath)
162 includes.append(relpath)
164 if getattr(self, 'local_include', True) == True and not getattr(self, 'local_include_first', True):
165 includes.append('.')
167 # now transform the includes list to be relative to the top directory
168 # which is represented by '#' in waf. This allows waf to cache the
169 # includes lists more efficiently
170 includes_top = []
171 for i in includes:
172 if i[0] == '#':
173 # some are already top based
174 includes_top.append(i)
175 continue
176 absinc = os.path.join(self.path.abspath(), i)
177 relinc = os_path_relpath(absinc, self.bld.srcnode.abspath())
178 includes_top.append('#' + relinc)
180 self.includes = unique_list(includes_top)
181 debug('deps: includes for target %s: includes=%s',
182 self.sname, self.includes)
187 def add_init_functions(self):
188 '''This builds the right set of init functions'''
190 bld = self.bld
192 subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
194 # cope with the separated object lists from BINARY and LIBRARY targets
195 sname = self.sname
196 if sname.endswith('.objlist'):
197 sname = sname[0:-8]
199 modules = []
200 if sname in subsystems:
201 modules.append(sname)
203 m = getattr(self, 'samba_modules', None)
204 if m is not None:
205 modules.extend(TO_LIST(m))
207 m = getattr(self, 'samba_subsystem', None)
208 if m is not None:
209 modules.append(m)
211 sentinal = getattr(self, 'init_function_sentinal', 'NULL')
213 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
214 cflags = getattr(self, 'samba_cflags', [])[:]
216 if modules == []:
217 cflags.append('-DSTATIC_%s_MODULES=%s' % (sname.replace('-','_'), sentinal))
218 if sentinal == 'NULL':
219 cflags.append('-DSTATIC_%s_MODULES_PROTO' % sname.replace('-','_'))
220 self.ccflags = cflags
221 return
223 for m in modules:
224 bld.ASSERT(m in subsystems,
225 "No init_function defined for module '%s' in target '%s'" % (m, self.sname))
226 init_fn_list = []
227 for d in subsystems[m]:
228 if targets[d['TARGET']] != 'DISABLED':
229 init_fn_list.append(d['INIT_FUNCTION'])
230 if init_fn_list == []:
231 cflags.append('-DSTATIC_%s_MODULES=%s' % (m, sentinal))
232 if sentinal == 'NULL':
233 cflags.append('-DSTATIC_%s_MODULES_PROTO' % m)
234 else:
235 cflags.append('-DSTATIC_%s_MODULES=%s' % (m, ','.join(init_fn_list) + ',' + sentinal))
236 proto=''
237 for f in init_fn_list:
238 proto = proto + '_MODULE_PROTO(%s)' % f
239 cflags.append('-DSTATIC_%s_MODULES_PROTO=%s' % (m, proto))
240 self.ccflags = cflags
244 def check_duplicate_sources(bld, tgt_list):
245 '''see if we are compiling the same source file more than once
246 without an allow_duplicates attribute'''
248 debug('deps: checking for duplicate sources')
250 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
251 ret = True
253 global tstart
255 for t in tgt_list:
256 source_list = TO_LIST(getattr(t, 'source', ''))
257 tpath = os.path.normpath(os_path_relpath(t.path.abspath(bld.env), t.env.BUILD_DIRECTORY + '/default'))
258 obj_sources = set()
259 for s in source_list:
260 p = os.path.normpath(os.path.join(tpath, s))
261 if p in obj_sources:
262 Logs.error("ERROR: source %s appears twice in target '%s'" % (p, t.sname))
263 sys.exit(1)
264 obj_sources.add(p)
265 t.samba_source_set = obj_sources
267 subsystems = {}
269 # build a list of targets that each source file is part of
270 for t in tgt_list:
271 sources = []
272 if not targets[t.sname] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
273 continue
274 for obj in t.add_objects:
275 t2 = t.bld.name_to_obj(obj, bld.env)
276 source_set = getattr(t2, 'samba_source_set', set())
277 for s in source_set:
278 if not s in subsystems:
279 subsystems[s] = {}
280 if not t.sname in subsystems[s]:
281 subsystems[s][t.sname] = []
282 subsystems[s][t.sname].append(t2.sname)
284 for s in subsystems:
285 if len(subsystems[s]) > 1 and Options.options.SHOW_DUPLICATES:
286 Logs.warn("WARNING: source %s is in more than one target: %s" % (s, subsystems[s].keys()))
287 for tname in subsystems[s]:
288 if len(subsystems[s][tname]) > 1:
289 Logs.error("ERROR: source %s is in more than one subsystem of target '%s': %s" % (s, tname, subsystems[s][tname]))
290 sys.exit(1)
292 return ret
295 def check_orpaned_targets(bld, tgt_list):
296 '''check if any build targets are orphaned'''
298 target_dict = LOCAL_CACHE(bld, 'TARGET_TYPE')
300 debug('deps: checking for orphaned targets')
302 for t in tgt_list:
303 if getattr(t, 'samba_used', False) == True:
304 continue
305 type = target_dict[t.sname]
306 if not type in ['BINARY', 'LIBRARY', 'MODULE', 'ET', 'PYTHON']:
307 if re.search('^PIDL_', t.sname) is None:
308 Logs.warn("Target %s of type %s is unused by any other target" % (t.sname, type))
311 def check_group_ordering(bld, tgt_list):
312 '''see if we have any dependencies that violate the group ordering
314 It is an error for a target to depend on a target from a later
315 build group
318 def group_name(g):
319 tm = bld.task_manager
320 return [x for x in tm.groups_names if id(tm.groups_names[x]) == id(g)][0]
322 for g in bld.task_manager.groups:
323 gname = group_name(g)
324 for t in g.tasks_gen:
325 t.samba_group = gname
327 grp_map = {}
328 idx = 0
329 for g in bld.task_manager.groups:
330 name = group_name(g)
331 grp_map[name] = idx
332 idx += 1
334 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
336 ret = True
337 for t in tgt_list:
338 tdeps = getattr(t, 'add_objects', []) + getattr(t, 'uselib_local', [])
339 for d in tdeps:
340 t2 = bld.name_to_obj(d, bld.env)
341 if t2 is None:
342 continue
343 map1 = grp_map[t.samba_group]
344 map2 = grp_map[t2.samba_group]
346 if map2 > map1:
347 Logs.error("Target %r in build group %r depends on target %r from later build group %r" % (
348 t.sname, t.samba_group, t2.sname, t2.samba_group))
349 ret = False
351 return ret
354 def show_final_deps(bld, tgt_list):
355 '''show the final dependencies for all targets'''
357 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
359 for t in tgt_list:
360 if not targets[t.sname] in ['LIBRARY', 'BINARY', 'PYTHON', 'SUBSYSTEM']:
361 continue
362 debug('deps: final dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
363 t.sname, t.uselib, getattr(t, 'uselib_local', []), getattr(t, 'add_objects', []))
366 def add_samba_attributes(bld, tgt_list):
367 '''ensure a target has a the required samba attributes'''
369 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
371 for t in tgt_list:
372 if t.name != '':
373 t.sname = t.name
374 else:
375 t.sname = t.target
376 t.samba_type = targets[t.sname]
377 t.samba_abspath = t.path.abspath(bld.env)
378 t.samba_deps_extended = t.samba_deps[:]
379 t.samba_includes_extended = TO_LIST(t.samba_includes)[:]
380 t.ccflags = getattr(t, 'samba_cflags', '')
382 def replace_grouping_libraries(bld, tgt_list):
383 '''replace dependencies based on grouping libraries
385 If a library is marked as a grouping library, then any target that
386 depends on a subsystem that is part of that grouping library gets
387 that dependency replaced with a dependency on the grouping library
390 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
392 grouping = {}
394 # find our list of grouping libraries, mapped from the subsystems they depend on
395 for t in tgt_list:
396 if not getattr(t, 'grouping_library', False):
397 continue
398 for dep in t.samba_deps_extended:
399 bld.ASSERT(dep in targets, "grouping library target %s not declared in %s" % (dep, t.sname))
400 if targets[dep] == 'SUBSYSTEM':
401 grouping[dep] = t.sname
403 # now replace any dependencies on elements of grouping libraries
404 for t in tgt_list:
405 for i in range(len(t.samba_deps_extended)):
406 dep = t.samba_deps_extended[i]
407 if dep in grouping:
408 if t.sname != grouping[dep]:
409 debug("deps: target %s: replacing dependency %s with grouping library %s" % (t.sname, dep, grouping[dep]))
410 t.samba_deps_extended[i] = grouping[dep]
414 def build_direct_deps(bld, tgt_list):
415 '''build the direct_objects and direct_libs sets for each target'''
417 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
418 syslib_deps = LOCAL_CACHE(bld, 'SYSLIB_DEPS')
420 global_deps = bld.env.GLOBAL_DEPENDENCIES
421 global_deps_exclude = set()
422 for dep in global_deps:
423 t = bld.name_to_obj(dep, bld.env)
424 for d in t.samba_deps:
425 # prevent loops from the global dependencies list
426 global_deps_exclude.add(d)
427 global_deps_exclude.add(d + '.objlist')
429 for t in tgt_list:
430 t.direct_objects = set()
431 t.direct_libs = set()
432 t.direct_syslibs = set()
433 deps = t.samba_deps_extended[:]
434 if getattr(t, 'samba_use_global_deps', False) and not t.sname in global_deps_exclude:
435 deps.extend(global_deps)
436 for d in deps:
437 if d == t.sname: continue
438 if not d in targets:
439 Logs.error("Unknown dependency '%s' in '%s'" % (d, t.sname))
440 sys.exit(1)
441 if targets[d] in [ 'EMPTY', 'DISABLED' ]:
442 continue
443 if targets[d] == 'PYTHON' and targets[t.sname] != 'PYTHON' and t.sname.find('.objlist') == -1:
444 # this check should be more restrictive, but for now we have pidl-generated python
445 # code that directly depends on other python modules
446 Logs.error('ERROR: Target %s has dependency on python module %s' % (t.sname, d))
447 sys.exit(1)
448 if targets[d] == 'SYSLIB':
449 t.direct_syslibs.add(d)
450 if d in syslib_deps:
451 for implied in TO_LIST(syslib_deps[d]):
452 if BUILTIN_LIBRARY(bld, implied):
453 t.direct_objects.add(implied)
454 elif targets[implied] == 'SYSLIB':
455 t.direct_syslibs.add(implied)
456 elif targets[implied] in ['LIBRARY', 'MODULE']:
457 t.direct_libs.add(implied)
458 else:
459 Logs.error('Implied dependency %s in %s is of type %s' % (
460 implied, t.sname, targets[implied]))
461 sys.exit(1)
462 continue
463 t2 = bld.name_to_obj(d, bld.env)
464 if t2 is None:
465 Logs.error("no task %s of type %s in %s" % (d, targets[d], t.sname))
466 sys.exit(1)
467 if t2.samba_type in [ 'LIBRARY', 'MODULE' ]:
468 t.direct_libs.add(d)
469 elif t2.samba_type in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]:
470 t.direct_objects.add(d)
471 debug('deps: built direct dependencies')
474 def dependency_loop(loops, t, target):
475 '''add a dependency loop to the loops dictionary'''
476 if t.sname == target:
477 return
478 if not target in loops:
479 loops[target] = set()
480 if not t.sname in loops[target]:
481 loops[target].add(t.sname)
484 def indirect_libs(bld, t, chain, loops):
485 '''recursively calculate the indirect library dependencies for a target
487 An indirect library is a library that results from a dependency on
488 a subsystem
491 ret = getattr(t, 'indirect_libs', None)
492 if ret is not None:
493 return ret
495 ret = set()
496 for obj in t.direct_objects:
497 if obj in chain:
498 dependency_loop(loops, t, obj)
499 continue
500 chain.add(obj)
501 t2 = bld.name_to_obj(obj, bld.env)
502 r2 = indirect_libs(bld, t2, chain, loops)
503 chain.remove(obj)
504 ret = ret.union(t2.direct_libs)
505 ret = ret.union(r2)
507 for obj in indirect_objects(bld, t, set(), loops):
508 if obj in chain:
509 dependency_loop(loops, t, obj)
510 continue
511 chain.add(obj)
512 t2 = bld.name_to_obj(obj, bld.env)
513 r2 = indirect_libs(bld, t2, chain, loops)
514 chain.remove(obj)
515 ret = ret.union(t2.direct_libs)
516 ret = ret.union(r2)
518 t.indirect_libs = ret
520 return ret
523 def indirect_objects(bld, t, chain, loops):
524 '''recursively calculate the indirect object dependencies for a target
526 indirect objects are the set of objects from expanding the
527 subsystem dependencies
530 ret = getattr(t, 'indirect_objects', None)
531 if ret is not None: return ret
533 ret = set()
534 for lib in t.direct_objects:
535 if lib in chain:
536 dependency_loop(loops, t, lib)
537 continue
538 chain.add(lib)
539 t2 = bld.name_to_obj(lib, bld.env)
540 r2 = indirect_objects(bld, t2, chain, loops)
541 chain.remove(lib)
542 ret = ret.union(t2.direct_objects)
543 ret = ret.union(r2)
545 t.indirect_objects = ret
546 return ret
549 def extended_objects(bld, t, chain):
550 '''recursively calculate the extended object dependencies for a target
552 extended objects are the union of:
553 - direct objects
554 - indirect objects
555 - direct and indirect objects of all direct and indirect libraries
558 ret = getattr(t, 'extended_objects', None)
559 if ret is not None: return ret
561 ret = set()
562 ret = ret.union(t.final_objects)
564 for lib in t.final_libs:
565 if lib in chain:
566 continue
567 t2 = bld.name_to_obj(lib, bld.env)
568 chain.add(lib)
569 r2 = extended_objects(bld, t2, chain)
570 chain.remove(lib)
571 ret = ret.union(t2.final_objects)
572 ret = ret.union(r2)
574 t.extended_objects = ret
575 return ret
578 def includes_objects(bld, t, chain, inc_loops):
579 '''recursively calculate the includes object dependencies for a target
581 includes dependencies come from either library or object dependencies
583 ret = getattr(t, 'includes_objects', None)
584 if ret is not None:
585 return ret
587 ret = t.direct_objects.copy()
588 ret = ret.union(t.direct_libs)
590 for obj in t.direct_objects:
591 if obj in chain:
592 dependency_loop(inc_loops, t, obj)
593 continue
594 chain.add(obj)
595 t2 = bld.name_to_obj(obj, bld.env)
596 r2 = includes_objects(bld, t2, chain, inc_loops)
597 chain.remove(obj)
598 ret = ret.union(t2.direct_objects)
599 ret = ret.union(r2)
601 for lib in t.direct_libs:
602 if lib in chain:
603 dependency_loop(inc_loops, t, lib)
604 continue
605 chain.add(lib)
606 t2 = bld.name_to_obj(lib, bld.env)
607 if t2 is None:
608 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
609 Logs.error('Target %s of type %s not found in direct_libs for %s' % (
610 lib, targets[lib], t.sname))
611 sys.exit(1)
612 r2 = includes_objects(bld, t2, chain, inc_loops)
613 chain.remove(lib)
614 ret = ret.union(t2.direct_objects)
615 ret = ret.union(r2)
617 t.includes_objects = ret
618 return ret
621 def break_dependency_loops(bld, tgt_list):
622 '''find and break dependency loops'''
623 loops = {}
624 inc_loops = {}
626 # build up the list of loops
627 for t in tgt_list:
628 indirect_objects(bld, t, set(), loops)
629 indirect_libs(bld, t, set(), loops)
630 includes_objects(bld, t, set(), inc_loops)
632 # break the loops
633 for t in tgt_list:
634 if t.sname in loops:
635 for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
636 objs = getattr(t, attr, set())
637 setattr(t, attr, objs.difference(loops[t.sname]))
639 for loop in loops:
640 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
642 for loop in inc_loops:
643 debug('deps: Found include loops for target %s : %s', loop, inc_loops[loop])
645 # expand the loops mapping by one level
646 for loop in loops.copy():
647 for tgt in loops[loop]:
648 if tgt in loops:
649 loops[loop] = loops[loop].union(loops[tgt])
651 for loop in inc_loops.copy():
652 for tgt in inc_loops[loop]:
653 if tgt in inc_loops:
654 inc_loops[loop] = inc_loops[loop].union(inc_loops[tgt])
657 # expand indirect subsystem and library loops
658 for loop in loops.copy():
659 t = bld.name_to_obj(loop, bld.env)
660 if t.samba_type in ['SUBSYSTEM']:
661 loops[loop] = loops[loop].union(t.indirect_objects)
662 loops[loop] = loops[loop].union(t.direct_objects)
663 if t.samba_type in ['LIBRARY','PYTHON']:
664 loops[loop] = loops[loop].union(t.indirect_libs)
665 loops[loop] = loops[loop].union(t.direct_libs)
666 if loop in loops[loop]:
667 loops[loop].remove(loop)
669 # expand indirect includes loops
670 for loop in inc_loops.copy():
671 t = bld.name_to_obj(loop, bld.env)
672 inc_loops[loop] = inc_loops[loop].union(t.includes_objects)
673 if loop in inc_loops[loop]:
674 inc_loops[loop].remove(loop)
676 # add in the replacement dependencies
677 for t in tgt_list:
678 for loop in loops:
679 for attr in ['indirect_objects', 'indirect_libs']:
680 objs = getattr(t, attr, set())
681 if loop in objs:
682 diff = loops[loop].difference(objs)
683 if t.sname in diff:
684 diff.remove(t.sname)
685 if diff:
686 debug('deps: Expanded target %s of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
687 objs = objs.union(diff)
688 setattr(t, attr, objs)
690 for loop in inc_loops:
691 objs = getattr(t, 'includes_objects', set())
692 if loop in objs:
693 diff = inc_loops[loop].difference(objs)
694 if t.sname in diff:
695 diff.remove(t.sname)
696 if diff:
697 debug('deps: Expanded target %s includes of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
698 objs = objs.union(diff)
699 setattr(t, 'includes_objects', objs)
702 def reduce_objects(bld, tgt_list):
703 '''reduce objects by looking for indirect object dependencies'''
704 rely_on = {}
706 for t in tgt_list:
707 t.extended_objects = None
709 changed = False
711 for type in ['BINARY', 'PYTHON', 'LIBRARY']:
712 for t in tgt_list:
713 if t.samba_type != type: continue
714 # if we will indirectly link to a target then we don't need it
715 new = t.final_objects.copy()
716 for l in t.final_libs:
717 t2 = bld.name_to_obj(l, bld.env)
718 t2_obj = extended_objects(bld, t2, set())
719 dup = new.intersection(t2_obj)
720 if t.sname in rely_on:
721 dup = dup.difference(rely_on[t.sname])
722 if dup:
723 debug('deps: removing dups from %s of type %s: %s also in %s %s',
724 t.sname, t.samba_type, dup, t2.samba_type, l)
725 new = new.difference(dup)
726 changed = True
727 if not l in rely_on:
728 rely_on[l] = set()
729 rely_on[l] = rely_on[l].union(dup)
730 t.final_objects = new
732 if not changed:
733 return False
735 # add back in any objects that were relied upon by the reduction rules
736 for r in rely_on:
737 t = bld.name_to_obj(r, bld.env)
738 t.final_objects = t.final_objects.union(rely_on[r])
740 return True
743 def show_library_loop(bld, lib1, lib2, path, seen):
744 '''show the detailed path of a library loop between lib1 and lib2'''
746 t = bld.name_to_obj(lib1, bld.env)
747 if not lib2 in getattr(t, 'final_libs', set()):
748 return
750 for d in t.samba_deps_extended:
751 if d in seen:
752 continue
753 seen.add(d)
754 path2 = path + '=>' + d
755 if d == lib2:
756 Logs.warn('library loop path: ' + path2)
757 return
758 show_library_loop(bld, d, lib2, path2, seen)
759 seen.remove(d)
762 def calculate_final_deps(bld, tgt_list, loops):
763 '''calculate the final library and object dependencies'''
764 for t in tgt_list:
765 # start with the maximum possible list
766 t.final_libs = t.direct_libs.union(indirect_libs(bld, t, set(), loops))
767 t.final_objects = t.direct_objects.union(indirect_objects(bld, t, set(), loops))
769 for t in tgt_list:
770 # don't depend on ourselves
771 if t.sname in t.final_libs:
772 t.final_libs.remove(t.sname)
773 if t.sname in t.final_objects:
774 t.final_objects.remove(t.sname)
776 # handle any non-shared binaries
777 for t in tgt_list:
778 if t.samba_type == 'BINARY' and bld.NONSHARED_BINARY(t.sname):
779 subsystem_list = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
780 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
782 # replace lib deps with objlist deps
783 for l in t.final_libs:
784 objname = l + '.objlist'
785 t2 = bld.name_to_obj(objname, bld.env)
786 if t2 is None:
787 Logs.error('ERROR: subsystem %s not found' % objname)
788 sys.exit(1)
789 t.final_objects.add(objname)
790 t.final_objects = t.final_objects.union(extended_objects(bld, t2, set()))
791 if l in subsystem_list:
792 # its a subsystem - we also need the contents of any modules
793 for d in subsystem_list[l]:
794 module_name = d['TARGET']
795 if targets[module_name] == 'LIBRARY':
796 objname = module_name + '.objlist'
797 elif targets[module_name] == 'SUBSYSTEM':
798 objname = module_name
799 else:
800 continue
801 t2 = bld.name_to_obj(objname, bld.env)
802 if t2 is None:
803 Logs.error('ERROR: subsystem %s not found' % objname)
804 sys.exit(1)
805 t.final_objects.add(objname)
806 t.final_objects = t.final_objects.union(extended_objects(bld, t2, set()))
807 t.final_libs = set()
809 # find any library loops
810 for t in tgt_list:
811 if t.samba_type in ['LIBRARY', 'PYTHON']:
812 for l in t.final_libs.copy():
813 t2 = bld.name_to_obj(l, bld.env)
814 if t.sname in t2.final_libs:
815 if getattr(bld.env, "ALLOW_CIRCULAR_LIB_DEPENDENCIES", False):
816 # we could break this in either direction. If one of the libraries
817 # has a version number, and will this be distributed publicly, then
818 # we should make it the lower level library in the DAG
819 Logs.warn('deps: removing library loop %s from %s' % (t.sname, t2.sname))
820 dependency_loop(loops, t, t2.sname)
821 t2.final_libs.remove(t.sname)
822 else:
823 Logs.error('ERROR: circular library dependency between %s and %s'
824 % (t.sname, t2.sname))
825 show_library_loop(bld, t.sname, t2.sname, t.sname, set())
826 show_library_loop(bld, t2.sname, t.sname, t2.sname, set())
827 sys.exit(1)
829 for loop in loops:
830 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
832 # we now need to make corrections for any library loops we broke up
833 # any target that depended on the target of the loop and doesn't
834 # depend on the source of the loop needs to get the loop source added
835 for type in ['BINARY','PYTHON','LIBRARY','BINARY']:
836 for t in tgt_list:
837 if t.samba_type != type: continue
838 for loop in loops:
839 if loop in t.final_libs:
840 diff = loops[loop].difference(t.final_libs)
841 if t.sname in diff:
842 diff.remove(t.sname)
843 if t.sname in diff:
844 diff.remove(t.sname)
845 # make sure we don't recreate the loop again!
846 for d in diff.copy():
847 t2 = bld.name_to_obj(d, bld.env)
848 if t2.samba_type == 'LIBRARY':
849 if t.sname in t2.final_libs:
850 debug('deps: removing expansion %s from %s', d, t.sname)
851 diff.remove(d)
852 if diff:
853 debug('deps: Expanded target %s by loop %s libraries (loop %s) %s', t.sname, loop,
854 loops[loop], diff)
855 t.final_libs = t.final_libs.union(diff)
857 # remove objects that are also available in linked libs
858 count = 0
859 while reduce_objects(bld, tgt_list):
860 count += 1
861 if count > 100:
862 Logs.warn("WARNING: Unable to remove all inter-target object duplicates")
863 break
864 debug('deps: Object reduction took %u iterations', count)
866 # add in any syslib dependencies
867 for t in tgt_list:
868 if not t.samba_type in ['BINARY','PYTHON','LIBRARY','SUBSYSTEM']:
869 continue
870 syslibs = set()
871 for d in t.final_objects:
872 t2 = bld.name_to_obj(d, bld.env)
873 syslibs = syslibs.union(t2.direct_syslibs)
874 # this adds the indirect syslibs as well, which may not be needed
875 # depending on the linker flags
876 for d in t.final_libs:
877 t2 = bld.name_to_obj(d, bld.env)
878 syslibs = syslibs.union(t2.direct_syslibs)
879 t.final_syslibs = syslibs
882 # find any unresolved library loops
883 lib_loop_error = False
884 for t in tgt_list:
885 if t.samba_type in ['LIBRARY', 'PYTHON']:
886 for l in t.final_libs.copy():
887 t2 = bld.name_to_obj(l, bld.env)
888 if t.sname in t2.final_libs:
889 Logs.error('ERROR: Unresolved library loop %s from %s' % (t.sname, t2.sname))
890 lib_loop_error = True
891 if lib_loop_error:
892 sys.exit(1)
894 debug('deps: removed duplicate dependencies')
897 def show_dependencies(bld, target, seen):
898 '''recursively show the dependencies of target'''
900 if target in seen:
901 return
903 t = bld.name_to_obj(target, bld.env)
904 if t is None:
905 Logs.error("ERROR: Unable to find target '%s'" % target)
906 sys.exit(1)
908 Logs.info('%s(OBJECTS): %s' % (target, t.direct_objects))
909 Logs.info('%s(LIBS): %s' % (target, t.direct_libs))
910 Logs.info('%s(SYSLIBS): %s' % (target, t.direct_syslibs))
912 seen.add(target)
914 for t2 in t.direct_objects:
915 show_dependencies(bld, t2, seen)
918 def show_object_duplicates(bld, tgt_list):
919 '''show a list of object files that are included in more than
920 one library or binary'''
922 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
924 used_by = {}
926 Logs.info("showing duplicate objects")
928 for t in tgt_list:
929 if not targets[t.sname] in [ 'LIBRARY', 'PYTHON' ]:
930 continue
931 for n in getattr(t, 'final_objects', set()):
932 t2 = bld.name_to_obj(n, bld.env)
933 if not n in used_by:
934 used_by[n] = set()
935 used_by[n].add(t.sname)
937 for n in used_by:
938 if len(used_by[n]) > 1:
939 Logs.info("target '%s' is used by %s" % (n, used_by[n]))
941 Logs.info("showing indirect dependency counts (sorted by count)")
943 def indirect_count(t1, t2):
944 return len(t2.indirect_objects) - len(t1.indirect_objects)
946 sorted_list = sorted(tgt_list, cmp=indirect_count)
947 for t in sorted_list:
948 if len(t.indirect_objects) > 1:
949 Logs.info("%s depends on %u indirect objects" % (t.sname, len(t.indirect_objects)))
952 ######################################################################
953 # this provides a way to save our dependency calculations between runs
954 savedeps_version = 3
955 savedeps_inputs = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags', 'source', 'grouping_library']
956 savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags', 'ldflags', 'samba_deps_extended']
957 savedeps_outenv = ['INC_PATHS']
958 savedeps_envvars = ['NONSHARED_BINARIES', 'GLOBAL_DEPENDENCIES', 'EXTRA_CFLAGS', 'EXTRA_LDFLAGS' ]
959 savedeps_caches = ['GLOBAL_DEPENDENCIES', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
960 savedeps_files = ['buildtools/wafsamba/samba_deps.py']
962 def save_samba_deps(bld, tgt_list):
963 '''save the dependency calculations between builds, to make
964 further builds faster'''
965 denv = Environment.Environment()
967 denv.version = savedeps_version
968 denv.savedeps_inputs = savedeps_inputs
969 denv.savedeps_outputs = savedeps_outputs
970 denv.input = {}
971 denv.output = {}
972 denv.outenv = {}
973 denv.caches = {}
974 denv.envvar = {}
975 denv.files = {}
977 for f in savedeps_files:
978 denv.files[f] = os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime
980 for c in savedeps_caches:
981 denv.caches[c] = LOCAL_CACHE(bld, c)
983 for e in savedeps_envvars:
984 denv.envvar[e] = bld.env[e]
986 for t in tgt_list:
987 # save all the input attributes for each target
988 tdeps = {}
989 for attr in savedeps_inputs:
990 v = getattr(t, attr, None)
991 if v is not None:
992 tdeps[attr] = v
993 if tdeps != {}:
994 denv.input[t.sname] = tdeps
996 # save all the output attributes for each target
997 tdeps = {}
998 for attr in savedeps_outputs:
999 v = getattr(t, attr, None)
1000 if v is not None:
1001 tdeps[attr] = v
1002 if tdeps != {}:
1003 denv.output[t.sname] = tdeps
1005 tdeps = {}
1006 for attr in savedeps_outenv:
1007 if attr in t.env:
1008 tdeps[attr] = t.env[attr]
1009 if tdeps != {}:
1010 denv.outenv[t.sname] = tdeps
1012 depsfile = os.path.join(bld.bdir, "sambadeps")
1013 denv.store(depsfile)
1017 def load_samba_deps(bld, tgt_list):
1018 '''load a previous set of build dependencies if possible'''
1019 depsfile = os.path.join(bld.bdir, "sambadeps")
1020 denv = Environment.Environment()
1021 try:
1022 debug('deps: checking saved dependencies')
1023 denv.load(depsfile)
1024 if (denv.version != savedeps_version or
1025 denv.savedeps_inputs != savedeps_inputs or
1026 denv.savedeps_outputs != savedeps_outputs):
1027 return False
1028 except:
1029 return False
1031 # check if critical files have changed
1032 for f in savedeps_files:
1033 if f not in denv.files:
1034 return False
1035 if denv.files[f] != os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime:
1036 return False
1038 # check if caches are the same
1039 for c in savedeps_caches:
1040 if c not in denv.caches or denv.caches[c] != LOCAL_CACHE(bld, c):
1041 return False
1043 # check if caches are the same
1044 for e in savedeps_envvars:
1045 if e not in denv.envvar or denv.envvar[e] != bld.env[e]:
1046 return False
1048 # check inputs are the same
1049 for t in tgt_list:
1050 tdeps = {}
1051 for attr in savedeps_inputs:
1052 v = getattr(t, attr, None)
1053 if v is not None:
1054 tdeps[attr] = v
1055 if t.sname in denv.input:
1056 olddeps = denv.input[t.sname]
1057 else:
1058 olddeps = {}
1059 if tdeps != olddeps:
1060 #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
1061 return False
1063 # put outputs in place
1064 for t in tgt_list:
1065 if not t.sname in denv.output: continue
1066 tdeps = denv.output[t.sname]
1067 for a in tdeps:
1068 setattr(t, a, tdeps[a])
1070 # put output env vars in place
1071 for t in tgt_list:
1072 if not t.sname in denv.outenv: continue
1073 tdeps = denv.outenv[t.sname]
1074 for a in tdeps:
1075 t.env[a] = tdeps[a]
1077 debug('deps: loaded saved dependencies')
1078 return True
1082 def check_project_rules(bld):
1083 '''check the project rules - ensuring the targets are sane'''
1085 loops = {}
1086 inc_loops = {}
1088 tgt_list = get_tgt_list(bld)
1090 add_samba_attributes(bld, tgt_list)
1092 force_project_rules = (Options.options.SHOWDEPS or
1093 Options.options.SHOW_DUPLICATES)
1095 if not force_project_rules and load_samba_deps(bld, tgt_list):
1096 return
1098 global tstart
1099 tstart = time.clock()
1101 bld.new_rules = True
1102 Logs.info("Checking project rules ...")
1104 debug('deps: project rules checking started')
1106 expand_subsystem_deps(bld)
1108 debug("deps: expand_subsystem_deps: %f" % (time.clock() - tstart))
1110 replace_grouping_libraries(bld, tgt_list)
1112 debug("deps: replace_grouping_libraries: %f" % (time.clock() - tstart))
1114 build_direct_deps(bld, tgt_list)
1116 debug("deps: build_direct_deps: %f" % (time.clock() - tstart))
1118 break_dependency_loops(bld, tgt_list)
1120 debug("deps: break_dependency_loops: %f" % (time.clock() - tstart))
1122 if Options.options.SHOWDEPS:
1123 show_dependencies(bld, Options.options.SHOWDEPS, set())
1125 calculate_final_deps(bld, tgt_list, loops)
1127 debug("deps: calculate_final_deps: %f" % (time.clock() - tstart))
1129 if Options.options.SHOW_DUPLICATES:
1130 show_object_duplicates(bld, tgt_list)
1132 # run the various attribute generators
1133 for f in [ build_dependencies, build_includes, add_init_functions ]:
1134 debug('deps: project rules checking %s', f)
1135 for t in tgt_list: f(t)
1136 debug("deps: %s: %f" % (f, time.clock() - tstart))
1138 debug('deps: project rules stage1 completed')
1140 #check_orpaned_targets(bld, tgt_list)
1142 if not check_duplicate_sources(bld, tgt_list):
1143 Logs.error("Duplicate sources present - aborting")
1144 sys.exit(1)
1146 debug("deps: check_duplicate_sources: %f" % (time.clock() - tstart))
1148 if not check_group_ordering(bld, tgt_list):
1149 Logs.error("Bad group ordering - aborting")
1150 sys.exit(1)
1152 debug("deps: check_group_ordering: %f" % (time.clock() - tstart))
1154 show_final_deps(bld, tgt_list)
1156 debug("deps: show_final_deps: %f" % (time.clock() - tstart))
1158 debug('deps: project rules checking completed - %u targets checked',
1159 len(tgt_list))
1161 if not bld.is_install:
1162 save_samba_deps(bld, tgt_list)
1164 debug("deps: save_samba_deps: %f" % (time.clock() - tstart))
1166 Logs.info("Project rules pass")
1169 def CHECK_PROJECT_RULES(bld):
1170 '''enable checking of project targets for sanity'''
1171 if bld.env.added_project_rules:
1172 return
1173 bld.env.added_project_rules = True
1174 bld.add_pre_fun(check_project_rules)
1175 Build.BuildContext.CHECK_PROJECT_RULES = CHECK_PROJECT_RULES