1 # Samba automatic dependency handling and project rules
3 import Build, os, re, Environment, Logs
4 from samba_utils import *
5 from samba_autoconf import *
6 from samba_bundled import BUILTIN_LIBRARY
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)
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 def TARGET_ALIAS(bld, target, alias):
23 '''define an alias for a target name'''
24 cache = LOCAL_CACHE(bld, 'TARGET_ALIAS')
26 Logs.error("Target alias %s already set to %s : newalias %s" % (alias, cache[alias], target))
29 Build.BuildContext.TARGET_ALIAS = TARGET_ALIAS
33 def SET_SYSLIB_DEPS(conf, target, deps):
34 '''setup some implied dependencies for a SYSLIB'''
35 cache = LOCAL_CACHE(conf, 'SYSLIB_DEPS')
39 def EXPAND_ALIAS(bld, target):
40 '''expand a target name via an alias'''
41 aliases = LOCAL_CACHE(bld, 'TARGET_ALIAS')
43 return aliases[target]
45 Build.BuildContext.EXPAND_ALIAS = EXPAND_ALIAS
48 def expand_subsystem_deps(bld):
49 '''expand the reverse dependencies resulting from subsystem
50 attributes of modules. This is walking over the complete list
51 of declared subsystems, and expands the samba_deps_extended list for any
52 module<->subsystem dependencies'''
54 subsystem_list = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
55 aliases = LOCAL_CACHE(bld, 'TARGET_ALIAS')
56 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
58 for subsystem_name in subsystem_list:
59 if subsystem_name in aliases:
60 subsystem_name = aliases[subsystem_name]
61 bld.ASSERT(subsystem_name in targets, "Subsystem target %s not declared" % subsystem_name)
62 type = targets[subsystem_name]
63 if type == 'DISABLED' or type == 'EMPTY':
67 # subsystem_name = dcerpc_server (a subsystem)
68 # subsystem = dcerpc_server (a subsystem object)
69 # module_name = rpc_epmapper (a module within the dcerpc_server subsystem)
70 # module = rpc_epmapper (a module object within the dcerpc_server subsystem)
72 subsystem = bld.name_to_obj(subsystem_name, bld.env)
73 for d in subsystem_list[subsystem_name]:
74 module_name = d['TARGET']
75 module_type = targets[module_name]
76 if module_type in ['DISABLED', 'EMPTY']:
78 bld.ASSERT(subsystem is not None,
79 "Subsystem target %s for %s (%s) not found" % (subsystem_name, module_name, module_type))
80 if module_type in ['SUBSYSTEM']:
81 # if a module is a plain object type (not a library) then the
82 # subsystem it is part of needs to have it as a dependency, so targets
83 # that depend on this subsystem get the modules of that subsystem
84 subsystem.samba_deps_extended.append(module_name)
85 module = bld.name_to_obj(module_name, bld.env)
86 module.samba_includes_extended.extend(subsystem.samba_includes_extended)
87 if targets[subsystem_name] in ['SUBSYSTEM']:
88 # if a subsystem is a plain object type (not a library) then any modules
89 # in that subsystem need to depend on the subsystem
90 module.samba_deps_extended.extend(subsystem.samba_deps_extended)
91 subsystem.samba_deps_extended = unique_list(subsystem.samba_deps_extended)
95 def build_dependencies(self):
96 '''This builds the dependency list for a target. It runs after all the targets are declared
98 The reason this is not just done in the SAMBA_*() rules is that we have no way of knowing
99 the full dependency list for a target until we have all of the targets declared.
102 if self.samba_type in ['LIBRARY', 'BINARY', 'PYTHON']:
103 self.uselib = list(self.final_syslibs)
104 self.uselib_local = list(self.final_libs)
105 self.add_objects = list(self.final_objects)
107 # extra link flags from pkg_config
108 libs = self.final_syslibs.copy()
110 (ccflags, ldflags) = library_flags(self, list(libs))
111 new_ldflags = getattr(self, 'ldflags', [])
112 new_ldflags.extend(ldflags)
113 self.ldflags = new_ldflags
115 debug('deps: computed dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
116 self.sname, self.uselib, self.uselib_local, self.add_objects)
118 if self.samba_type in ['SUBSYSTEM']:
119 # this is needed for the ccflags of libs that come from pkg_config
120 self.uselib = list(self.direct_syslibs)
122 if getattr(self, 'uselib', None):
124 for l in self.uselib:
125 up_list.append(l.upper())
126 self.uselib = up_list
128 def build_includes(self):
129 '''This builds the right set of includes for a target.
131 One tricky part of this is that the includes= attribute for a
132 target needs to use paths which are relative to that targets
133 declaration directory (which we can get at via t.path).
135 The way this works is the includes list gets added as
136 samba_includes in the main build task declaration. Then this
137 function runs after all of the tasks are declared, and it
138 processes the samba_includes attribute to produce a includes=
142 if getattr(self, 'samba_includes', None) is None:
147 inc_deps = includes_objects(bld, self, set(), {})
151 # maybe add local includes
152 if getattr(self, 'local_include', True) == True and getattr(self, 'local_include_first', True):
155 includes.extend(self.samba_includes_extended)
157 if 'EXTRA_INCLUDES' in bld.env:
158 includes.extend(bld.env['EXTRA_INCLUDES'])
166 t = bld.name_to_obj(d, bld.env)
167 bld.ASSERT(t is not None, "Unable to find dependency %s for %s" % (d, self.sname))
168 inclist = getattr(t, 'samba_includes_extended', [])
169 if getattr(t, 'local_include', True) == True:
173 tpath = t.samba_abspath
175 npath = tpath + '/' + inc
176 if not npath in inc_set:
177 inc_abs.append(npath)
180 mypath = self.path.abspath(bld.env)
182 relpath = os_path_relpath(inc, mypath)
183 includes.append(relpath)
185 if getattr(self, 'local_include', True) == True and not getattr(self, 'local_include_first', True):
188 # now transform the includes list to be relative to the top directory
189 # which is represented by '#' in waf. This allows waf to cache the
190 # includes lists more efficiently
194 # some are already top based
195 includes_top.append(i)
197 absinc = os.path.join(self.path.abspath(), i)
198 relinc = os_path_relpath(absinc, self.bld.srcnode.abspath())
199 includes_top.append('#' + relinc)
201 self.includes = unique_list(includes_top)
202 debug('deps: includes for target %s: includes=%s',
203 self.sname, self.includes)
208 def add_init_functions(self):
209 '''This builds the right set of init functions'''
213 subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
215 # cope with the separated object lists from BINARY and LIBRARY targets
217 if sname.endswith('.objlist'):
221 if sname in subsystems:
222 modules.append(sname)
224 m = getattr(self, 'samba_modules', None)
226 modules.extend(TO_LIST(m))
228 m = getattr(self, 'samba_subsystem', None)
235 sentinal = getattr(self, 'init_function_sentinal', 'NULL')
237 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
239 cflags = getattr(self, 'samba_cflags', [])[:]
241 bld.ASSERT(m in subsystems,
242 "No init_function defined for module '%s' in target '%s'" % (m, self.sname))
244 for d in subsystems[m]:
245 if targets[d['TARGET']] != 'DISABLED':
246 init_fn_list.append(d['INIT_FUNCTION'])
247 if init_fn_list == []:
248 cflags.append('-DSTATIC_%s_MODULES=%s' % (m, sentinal))
250 cflags.append('-DSTATIC_%s_MODULES=%s' % (m, ','.join(init_fn_list) + ',' + sentinal))
251 self.ccflags = cflags
255 def check_duplicate_sources(bld, tgt_list):
256 '''see if we are compiling the same source file into multiple
257 subsystem targets for the same library or binary'''
259 debug('deps: checking for duplicate sources')
261 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
267 obj_sources = getattr(t, 'source', '')
268 tpath = os.path.normpath(os_path_relpath(t.path.abspath(bld.env), t.env.BUILD_DIRECTORY + '/default'))
269 obj_sources = bld.SUBDIR(tpath, obj_sources)
270 t.samba_source_set = set(TO_LIST(obj_sources))
273 if not targets[t.sname] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
277 for obj in t.add_objects:
278 t2 = t.bld.name_to_obj(obj, bld.env)
279 source_set = getattr(t2, 'samba_source_set', set())
280 sources.append( { 'dep':obj, 'src':source_set} )
283 if s['dep'] == s2['dep']: continue
284 common = s['src'].intersection(s2['src'])
285 if common.difference(seen):
286 Logs.error("Target %s has duplicate source files in %s and %s : %s" % (t.sname,
289 seen = seen.union(common)
294 def check_orpaned_targets(bld, tgt_list):
295 '''check if any build targets are orphaned'''
297 target_dict = LOCAL_CACHE(bld, 'TARGET_TYPE')
299 debug('deps: checking for orphaned targets')
302 if getattr(t, 'samba_used', False) == True:
304 type = target_dict[t.sname]
305 if not type in ['BINARY', 'LIBRARY', 'MODULE', 'ET', 'PYTHON']:
306 if re.search('^PIDL_', t.sname) is None:
307 Logs.warn("Target %s of type %s is unused by any other target" % (t.sname, type))
310 def check_group_ordering(bld, tgt_list):
311 '''see if we have any dependencies that violate the group ordering
313 It is an error for a target to depend on a target from a later
318 tm = bld.task_manager
319 return [x for x in tm.groups_names if id(tm.groups_names[x]) == id(g)][0]
321 for g in bld.task_manager.groups:
322 gname = group_name(g)
323 for t in g.tasks_gen:
324 t.samba_group = gname
328 for g in bld.task_manager.groups:
333 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
337 tdeps = getattr(t, 'add_objects', []) + getattr(t, 'uselib_local', [])
339 t2 = bld.name_to_obj(d, bld.env)
342 map1 = grp_map[t.samba_group]
343 map2 = grp_map[t2.samba_group]
346 Logs.error("Target %r in build group %r depends on target %r from later build group %r" % (
347 t.sname, t.samba_group, t2.sname, t2.samba_group))
353 def show_final_deps(bld, tgt_list):
354 '''show the final dependencies for all targets'''
356 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
359 if not targets[t.sname] in ['LIBRARY', 'BINARY', 'PYTHON']:
361 debug('deps: final dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
362 t.sname, t.uselib, t.uselib_local, t.add_objects)
365 def add_samba_attributes(bld, tgt_list):
366 '''ensure a target has a the required samba attributes'''
368 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
375 t.samba_type = targets[t.sname]
376 t.samba_abspath = t.path.abspath(bld.env)
377 t.samba_deps_extended = t.samba_deps[:]
378 t.samba_includes_extended = TO_LIST(t.samba_includes)[:]
379 t.ccflags = getattr(t, 'samba_cflags', '')
381 def replace_grouping_libraries(bld, tgt_list):
382 '''replace dependencies based on grouping libraries
384 If a library is marked as a grouping library, then any target that
385 depends on a subsystem that is part of that grouping library gets
386 that dependency replaced with a dependency on the grouping library
389 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
393 # find our list of grouping libraries, mapped from the subsystems they depend on
395 if not getattr(t, 'grouping_library', False):
397 for dep in t.samba_deps_extended:
398 if targets[dep] == 'SUBSYSTEM':
399 grouping[dep] = t.sname
401 # now replace any dependencies on elements of grouping libraries
403 for i in range(len(t.samba_deps_extended)):
404 dep = t.samba_deps_extended[i]
406 if t.sname != grouping[dep]:
407 debug("deps: target %s: replacing dependency %s with grouping library %s" % (t.sname, dep, grouping[dep]))
408 t.samba_deps_extended[i] = grouping[dep]
412 def build_direct_deps(bld, tgt_list):
413 '''build the direct_objects and direct_libs sets for each target'''
415 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
416 syslib_deps = LOCAL_CACHE(bld, 'SYSLIB_DEPS')
417 global_deps = bld.env.GLOBAL_DEPENDENCIES
420 t.direct_objects = set()
421 t.direct_libs = set()
422 t.direct_syslibs = set()
423 deps = t.samba_deps_extended[:]
424 if getattr(t, 'samba_use_global_deps', False):
425 deps.extend(global_deps)
427 d = EXPAND_ALIAS(bld, d)
428 if d == t.sname: continue
430 Logs.error("Unknown dependency %s in %s" % (d, t.sname))
432 if targets[d] in [ 'EMPTY', 'DISABLED' ]:
434 if targets[d] == 'SYSLIB':
435 t.direct_syslibs.add(d)
437 for implied in TO_LIST(syslib_deps[d]):
438 if BUILTIN_LIBRARY(bld, implied):
439 t.direct_objects.add(implied)
440 elif targets[implied] == 'SYSLIB':
441 t.direct_syslibs.add(implied)
442 elif targets[implied] in ['LIBRARY', 'MODULE']:
443 t.direct_libs.add(implied)
445 Logs.error('Implied dependency %s in %s is of type %s' % (
446 implied, t.sname, targets[implied]))
449 t2 = bld.name_to_obj(d, bld.env)
451 Logs.error("no task %s of type %s in %s" % (d, targets[d], t.sname))
453 if t2.samba_type in [ 'LIBRARY', 'MODULE' ]:
455 elif t2.samba_type in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]:
456 t.direct_objects.add(d)
457 debug('deps: built direct dependencies')
460 def dependency_loop(loops, t, target):
461 '''add a dependency loop to the loops dictionary'''
462 if t.sname == target:
464 if not target in loops:
465 loops[target] = set()
466 if not t.sname in loops[target]:
467 loops[target].add(t.sname)
470 def indirect_libs(bld, t, chain, loops):
471 '''recursively calculate the indirect library dependencies for a target
473 An indirect library is a library that results from a dependency on
477 ret = getattr(t, 'indirect_libs', None)
482 for obj in t.direct_objects:
484 dependency_loop(loops, t, obj)
487 t2 = bld.name_to_obj(obj, bld.env)
488 r2 = indirect_libs(bld, t2, chain, loops)
490 ret = ret.union(t2.direct_libs)
493 for obj in indirect_objects(bld, t, set(), loops):
495 dependency_loop(loops, t, obj)
498 t2 = bld.name_to_obj(obj, bld.env)
499 r2 = indirect_libs(bld, t2, chain, loops)
501 ret = ret.union(t2.direct_libs)
504 t.indirect_libs = ret
509 def indirect_objects(bld, t, chain, loops):
510 '''recursively calculate the indirect object dependencies for a target
512 indirect objects are the set of objects from expanding the
513 subsystem dependencies
516 ret = getattr(t, 'indirect_objects', None)
517 if ret is not None: return ret
520 for lib in t.direct_objects:
522 dependency_loop(loops, t, lib)
525 t2 = bld.name_to_obj(lib, bld.env)
526 r2 = indirect_objects(bld, t2, chain, loops)
528 ret = ret.union(t2.direct_objects)
531 t.indirect_objects = ret
535 def extended_objects(bld, t, chain):
536 '''recursively calculate the extended object dependencies for a target
538 extended objects are the union of:
541 - direct and indirect objects of all direct and indirect libraries
544 ret = getattr(t, 'extended_objects', None)
545 if ret is not None: return ret
548 ret = ret.union(t.final_objects)
550 for lib in t.final_libs:
553 t2 = bld.name_to_obj(lib, bld.env)
555 r2 = extended_objects(bld, t2, chain)
557 ret = ret.union(t2.final_objects)
560 t.extended_objects = ret
564 def includes_objects(bld, t, chain, inc_loops):
565 '''recursively calculate the includes object dependencies for a target
567 includes dependencies come from either library or object dependencies
569 ret = getattr(t, 'includes_objects', None)
573 ret = t.direct_objects.copy()
574 ret = ret.union(t.direct_libs)
576 for obj in t.direct_objects:
578 dependency_loop(inc_loops, t, obj)
581 t2 = bld.name_to_obj(obj, bld.env)
582 r2 = includes_objects(bld, t2, chain, inc_loops)
584 ret = ret.union(t2.direct_objects)
587 for lib in t.direct_libs:
589 dependency_loop(inc_loops, t, lib)
592 t2 = bld.name_to_obj(lib, bld.env)
594 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
595 Logs.error('Target %s of type %s not found in direct_libs for %s' % (
596 lib, targets[lib], t.sname))
598 r2 = includes_objects(bld, t2, chain, inc_loops)
600 ret = ret.union(t2.direct_objects)
603 t.includes_objects = ret
607 def break_dependency_loops(bld, tgt_list):
608 '''find and break dependency loops'''
612 # build up the list of loops
614 indirect_objects(bld, t, set(), loops)
615 indirect_libs(bld, t, set(), loops)
616 includes_objects(bld, t, set(), inc_loops)
621 for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
622 objs = getattr(t, attr, set())
623 setattr(t, attr, objs.difference(loops[t.sname]))
626 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
628 for loop in inc_loops:
629 debug('deps: Found include loops for target %s : %s', loop, inc_loops[loop])
631 # expand the loops mapping by one level
632 for loop in loops.copy():
633 for tgt in loops[loop]:
635 loops[loop] = loops[loop].union(loops[tgt])
637 for loop in inc_loops.copy():
638 for tgt in inc_loops[loop]:
640 inc_loops[loop] = inc_loops[loop].union(inc_loops[tgt])
643 # expand indirect subsystem and library loops
644 for loop in loops.copy():
645 t = bld.name_to_obj(loop, bld.env)
646 if t.samba_type in ['SUBSYSTEM']:
647 loops[loop] = loops[loop].union(t.indirect_objects)
648 loops[loop] = loops[loop].union(t.direct_objects)
649 if t.samba_type in ['LIBRARY','PYTHON']:
650 loops[loop] = loops[loop].union(t.indirect_libs)
651 loops[loop] = loops[loop].union(t.direct_libs)
652 if loop in loops[loop]:
653 loops[loop].remove(loop)
655 # expand indirect includes loops
656 for loop in inc_loops.copy():
657 t = bld.name_to_obj(loop, bld.env)
658 inc_loops[loop] = inc_loops[loop].union(t.includes_objects)
659 if loop in inc_loops[loop]:
660 inc_loops[loop].remove(loop)
662 # add in the replacement dependencies
665 for attr in ['indirect_objects', 'indirect_libs']:
666 objs = getattr(t, attr, set())
668 diff = loops[loop].difference(objs)
672 debug('deps: Expanded target %s of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
673 objs = objs.union(diff)
674 setattr(t, attr, objs)
676 for loop in inc_loops:
677 objs = getattr(t, 'includes_objects', set())
679 diff = inc_loops[loop].difference(objs)
683 debug('deps: Expanded target %s includes of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
684 objs = objs.union(diff)
685 setattr(t, 'includes_objects', objs)
688 def reduce_objects(bld, tgt_list):
689 '''reduce objects by looking for indirect object dependencies'''
693 t.extended_objects = None
697 for type in ['BINARY', 'PYTHON', 'LIBRARY']:
699 if t.samba_type != type: continue
700 # if we will indirectly link to a target then we don't need it
701 new = t.final_objects.copy()
702 for l in t.final_libs:
703 t2 = bld.name_to_obj(l, bld.env)
704 t2_obj = extended_objects(bld, t2, set())
705 dup = new.intersection(t2_obj)
706 if t.sname in rely_on:
707 dup = dup.difference(rely_on[t.sname])
709 debug('deps: removing dups from %s of type %s: %s also in %s %s',
710 t.sname, t.samba_type, dup, t2.samba_type, l)
711 new = new.difference(dup)
715 rely_on[l] = rely_on[l].union(dup)
716 t.final_objects = new
721 # add back in any objects that were relied upon by the reduction rules
723 t = bld.name_to_obj(r, bld.env)
724 t.final_objects = t.final_objects.union(rely_on[r])
729 def calculate_final_deps(bld, tgt_list, loops):
730 '''calculate the final library and object dependencies'''
732 # start with the maximum possible list
733 t.final_libs = t.direct_libs.union(indirect_libs(bld, t, set(), loops))
734 t.final_objects = t.direct_objects.union(indirect_objects(bld, t, set(), loops))
737 # don't depend on ourselves
738 if t.sname in t.final_libs:
739 t.final_libs.remove(t.sname)
740 if t.sname in t.final_objects:
741 t.final_objects.remove(t.sname)
743 # handle any non-shared binaries
745 if t.samba_type == 'BINARY' and bld.NONSHARED_BINARY(t.sname):
746 # replace lib deps with objlist deps
747 for l in t.final_libs:
748 objname = l + '.objlist'
749 t2 = bld.name_to_obj(objname, bld.env)
751 Logs.error('ERROR: subsystem %s not found' % objname)
753 t.final_objects.add(objname)
754 t.final_objects = t.final_objects.union(extended_objects(bld, t2, set()))
757 # find any library loops
759 if t.samba_type in ['LIBRARY', 'PYTHON']:
760 for l in t.final_libs.copy():
761 t2 = bld.name_to_obj(l, bld.env)
762 if t.sname in t2.final_libs:
763 if getattr(bld.env, "ALLOW_CIRCULAR_LIB_DEPENDENCIES", False):
764 # we could break this in either direction. If one of the libraries
765 # has a version number, and will this be distributed publicly, then
766 # we should make it the lower level library in the DAG
767 Logs.warn('deps: removing library loop %s from %s' % (t.sname, t2.sname))
768 dependency_loop(loops, t, t2.sname)
769 t2.final_libs.remove(t.sname)
771 Logs.error('ERROR: circular library dependency between %s and %s'
772 % (t.sname, t2.sname))
776 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
778 # we now need to make corrections for any library loops we broke up
779 # any target that depended on the target of the loop and doesn't
780 # depend on the source of the loop needs to get the loop source added
781 for type in ['BINARY','PYTHON','LIBRARY','BINARY']:
783 if t.samba_type != type: continue
785 if loop in t.final_libs:
786 diff = loops[loop].difference(t.final_libs)
791 # make sure we don't recreate the loop again!
792 for d in diff.copy():
793 t2 = bld.name_to_obj(d, bld.env)
794 if t2.samba_type == 'LIBRARY':
795 if t.sname in t2.final_libs:
796 debug('deps: removing expansion %s from %s', d, t.sname)
799 debug('deps: Expanded target %s by loop %s libraries (loop %s) %s', t.sname, loop,
801 t.final_libs = t.final_libs.union(diff)
803 # remove objects that are also available in linked libs
805 while reduce_objects(bld, tgt_list):
808 Logs.warn("WARNING: Unable to remove all inter-target object duplicates")
810 debug('deps: Object reduction took %u iterations', count)
812 # add in any syslib dependencies
814 if not t.samba_type in ['BINARY','PYTHON','LIBRARY']:
817 for d in t.final_objects:
818 t2 = bld.name_to_obj(d, bld.env)
819 syslibs = syslibs.union(t2.direct_syslibs)
820 # this adds the indirect syslibs as well, which may not be needed
821 # depending on the linker flags
822 for d in t.final_libs:
823 t2 = bld.name_to_obj(d, bld.env)
824 syslibs = syslibs.union(t2.direct_syslibs)
825 t.final_syslibs = syslibs
828 # find any unresolved library loops
829 lib_loop_error = False
831 if t.samba_type in ['LIBRARY', 'PYTHON']:
832 for l in t.final_libs.copy():
833 t2 = bld.name_to_obj(l, bld.env)
834 if t.sname in t2.final_libs:
835 Logs.error('ERROR: Unresolved library loop %s from %s' % (t.sname, t2.sname))
836 lib_loop_error = True
840 debug('deps: removed duplicate dependencies')
843 def show_dependencies(bld, target, seen):
844 '''recursively show the dependencies of target'''
849 t = bld.name_to_obj(target, bld.env)
851 Logs.error("ERROR: Unable to find target '%s'" % target)
854 Logs.info('%s(OBJECTS): %s' % (target, t.direct_objects))
855 Logs.info('%s(LIBS): %s' % (target, t.direct_libs))
856 Logs.info('%s(SYSLIBS): %s' % (target, t.direct_syslibs))
860 for t2 in t.direct_objects:
861 show_dependencies(bld, t2, seen)
864 def show_object_duplicates(bld, tgt_list):
865 '''show a list of object files that are included in more than
866 one library or binary'''
868 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
872 Logs.info("showing duplicate objects")
875 if not targets[t.sname] in [ 'LIBRARY' ]:
877 for n in getattr(t, 'final_objects', set()):
878 t2 = bld.name_to_obj(n, bld.env)
881 used_by[n].add(t.sname)
884 if len(used_by[n]) > 1:
885 Logs.info("target '%s' is used by %s" % (n, used_by[n]))
887 Logs.info("showing indirect dependency counts (sorted by count)")
889 def indirect_count(t1, t2):
890 return len(t2.indirect_objects) - len(t1.indirect_objects)
892 sorted_list = sorted(tgt_list, cmp=indirect_count)
893 for t in sorted_list:
894 if len(t.indirect_objects) > 1:
895 Logs.info("%s depends on %u indirect objects" % (t.sname, len(t.indirect_objects)))
898 ######################################################################
899 # this provides a way to save our dependency calculations between runs
901 savedeps_inputs = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags', 'source', 'grouping_library']
902 savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags']
903 savedeps_outenv = ['INC_PATHS']
904 savedeps_envvars = ['NONSHARED_BINARIES', 'GLOBAL_DEPENDENCIES']
905 savedeps_caches = ['GLOBAL_DEPENDENCIES', 'TARGET_ALIAS', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
906 savedeps_files = ['buildtools/wafsamba/samba_deps.py']
908 def save_samba_deps(bld, tgt_list):
909 '''save the dependency calculations between builds, to make
910 further builds faster'''
911 denv = Environment.Environment()
913 denv.version = savedeps_version
914 denv.savedeps_inputs = savedeps_inputs
915 denv.savedeps_outputs = savedeps_outputs
923 for f in savedeps_files:
924 denv.files[f] = os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime
926 for c in savedeps_caches:
927 denv.caches[c] = LOCAL_CACHE(bld, c)
929 for e in savedeps_envvars:
930 denv.envvar[e] = bld.env[e]
933 # save all the input attributes for each target
935 for attr in savedeps_inputs:
936 v = getattr(t, attr, None)
940 denv.input[t.sname] = tdeps
942 # save all the output attributes for each target
944 for attr in savedeps_outputs:
945 v = getattr(t, attr, None)
949 denv.output[t.sname] = tdeps
952 for attr in savedeps_outenv:
954 tdeps[attr] = t.env[attr]
956 denv.outenv[t.sname] = tdeps
958 depsfile = os.path.join(bld.bdir, "sambadeps")
963 def load_samba_deps(bld, tgt_list):
964 '''load a previous set of build dependencies if possible'''
965 depsfile = os.path.join(bld.bdir, "sambadeps")
966 denv = Environment.Environment()
968 debug('deps: checking saved dependencies')
970 if (denv.version != savedeps_version or
971 denv.savedeps_inputs != savedeps_inputs or
972 denv.savedeps_outputs != savedeps_outputs):
977 # check if critical files have changed
978 for f in savedeps_files:
979 if f not in denv.files:
981 if denv.files[f] != os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime:
984 # check if caches are the same
985 for c in savedeps_caches:
986 if c not in denv.caches or denv.caches[c] != LOCAL_CACHE(bld, c):
989 # check if caches are the same
990 for e in savedeps_envvars:
991 if e not in denv.envvar or denv.envvar[e] != bld.env[e]:
994 # check inputs are the same
997 for attr in savedeps_inputs:
998 v = getattr(t, attr, None)
1001 if t.sname in denv.input:
1002 olddeps = denv.input[t.sname]
1005 if tdeps != olddeps:
1006 #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
1009 # put outputs in place
1011 if not t.sname in denv.output: continue
1012 tdeps = denv.output[t.sname]
1014 setattr(t, a, tdeps[a])
1016 # put output env vars in place
1018 if not t.sname in denv.outenv: continue
1019 tdeps = denv.outenv[t.sname]
1023 debug('deps: loaded saved dependencies')
1028 def check_project_rules(bld):
1029 '''check the project rules - ensuring the targets are sane'''
1031 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
1035 # build a list of task generators we are interested in
1039 if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON']:
1041 t = bld.name_to_obj(tgt, bld.env)
1043 Logs.error("Target %s of type %s has no task generator" % (tgt, type))
1047 add_samba_attributes(bld, tgt_list)
1049 force_project_rules = (Options.options.SHOWDEPS or
1050 Options.options.SHOW_DUPLICATES)
1052 if not force_project_rules and load_samba_deps(bld, tgt_list):
1055 bld.new_rules = True
1056 Logs.info("Checking project rules ...")
1058 debug('deps: project rules checking started')
1060 expand_subsystem_deps(bld)
1061 replace_grouping_libraries(bld, tgt_list)
1062 build_direct_deps(bld, tgt_list)
1064 break_dependency_loops(bld, tgt_list)
1065 calculate_final_deps(bld, tgt_list, loops)
1067 if Options.options.SHOWDEPS:
1068 show_dependencies(bld, Options.options.SHOWDEPS, set())
1070 if Options.options.SHOW_DUPLICATES:
1071 show_object_duplicates(bld, tgt_list)
1073 # run the various attribute generators
1074 for f in [ build_dependencies, build_includes, add_init_functions ]:
1075 debug('deps: project rules checking %s', f)
1076 for t in tgt_list: f(t)
1078 debug('deps: project rules stage1 completed')
1080 #check_orpaned_targets(bld, tgt_list)
1082 if not check_duplicate_sources(bld, tgt_list):
1083 Logs.error("Duplicate sources present - aborting")
1086 if not check_group_ordering(bld, tgt_list):
1087 Logs.error("Bad group ordering - aborting")
1090 show_final_deps(bld, tgt_list)
1092 debug('deps: project rules checking completed - %u targets checked',
1095 if not bld.is_install:
1096 save_samba_deps(bld, tgt_list)
1098 Logs.info("Project rules pass")
1101 def CHECK_PROJECT_RULES(bld):
1102 '''enable checking of project targets for sanity'''
1103 if bld.env.added_project_rules:
1105 bld.env.added_project_rules = True
1106 bld.add_pre_fun(check_project_rules)
1107 Build.BuildContext.CHECK_PROJECT_RULES = CHECK_PROJECT_RULES