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', '')
382 def build_direct_deps(bld, tgt_list):
383 '''build the direct_objects and direct_libs sets for each target'''
385 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
386 syslib_deps = LOCAL_CACHE(bld, 'SYSLIB_DEPS')
387 global_deps = bld.env.GLOBAL_DEPENDENCIES
390 t.direct_objects = set()
391 t.direct_libs = set()
392 t.direct_syslibs = set()
393 deps = t.samba_deps_extended
394 if getattr(t, 'samba_use_global_deps', False):
395 deps.extend(global_deps)
397 d = EXPAND_ALIAS(bld, d)
398 if d == t.sname: continue
400 Logs.error("Unknown dependency %s in %s" % (d, t.sname))
402 if targets[d] in [ 'EMPTY', 'DISABLED' ]:
404 if targets[d] == 'SYSLIB':
405 t.direct_syslibs.add(d)
407 for implied in TO_LIST(syslib_deps[d]):
408 if BUILTIN_LIBRARY(bld, implied):
409 t.direct_objects.add(implied)
410 elif targets[implied] == 'SYSLIB':
411 t.direct_syslibs.add(implied)
412 elif targets[implied] in ['LIBRARY', 'MODULE']:
413 t.direct_libs.add(implied)
415 Logs.error('Implied dependency %s in %s is of type %s' % (
416 implied, t.sname, targets[implied]))
419 t2 = bld.name_to_obj(d, bld.env)
421 Logs.error("no task %s of type %s in %s" % (d, targets[d], t.sname))
423 if t2.samba_type in [ 'LIBRARY', 'MODULE' ]:
425 elif t2.samba_type in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]:
426 t.direct_objects.add(d)
427 debug('deps: built direct dependencies')
430 def dependency_loop(loops, t, target):
431 '''add a dependency loop to the loops dictionary'''
432 if t.sname == target:
434 if not target in loops:
435 loops[target] = set()
436 if not t.sname in loops[target]:
437 loops[target].add(t.sname)
440 def indirect_libs(bld, t, chain, loops):
441 '''recursively calculate the indirect library dependencies for a target
443 An indirect library is a library that results from a dependency on
447 ret = getattr(t, 'indirect_libs', None)
452 for obj in t.direct_objects:
454 dependency_loop(loops, t, obj)
457 t2 = bld.name_to_obj(obj, bld.env)
458 r2 = indirect_libs(bld, t2, chain, loops)
460 ret = ret.union(t2.direct_libs)
463 for obj in indirect_objects(bld, t, set(), loops):
465 dependency_loop(loops, t, obj)
468 t2 = bld.name_to_obj(obj, bld.env)
469 r2 = indirect_libs(bld, t2, chain, loops)
471 ret = ret.union(t2.direct_libs)
474 t.indirect_libs = ret
479 def indirect_objects(bld, t, chain, loops):
480 '''recursively calculate the indirect object dependencies for a target
482 indirect objects are the set of objects from expanding the
483 subsystem dependencies
486 ret = getattr(t, 'indirect_objects', None)
487 if ret is not None: return ret
490 for lib in t.direct_objects:
492 dependency_loop(loops, t, lib)
495 t2 = bld.name_to_obj(lib, bld.env)
496 r2 = indirect_objects(bld, t2, chain, loops)
498 ret = ret.union(t2.direct_objects)
501 t.indirect_objects = ret
505 def extended_objects(bld, t, chain):
506 '''recursively calculate the extended object dependencies for a target
508 extended objects are the union of:
511 - direct and indirect objects of all direct and indirect libraries
514 ret = getattr(t, 'extended_objects', None)
515 if ret is not None: return ret
518 ret = ret.union(t.final_objects)
520 for lib in t.final_libs:
523 t2 = bld.name_to_obj(lib, bld.env)
525 r2 = extended_objects(bld, t2, chain)
527 ret = ret.union(t2.final_objects)
530 t.extended_objects = ret
534 def includes_objects(bld, t, chain, inc_loops):
535 '''recursively calculate the includes object dependencies for a target
537 includes dependencies come from either library or object dependencies
539 ret = getattr(t, 'includes_objects', None)
543 ret = t.direct_objects.copy()
544 ret = ret.union(t.direct_libs)
546 for obj in t.direct_objects:
548 dependency_loop(inc_loops, t, obj)
551 t2 = bld.name_to_obj(obj, bld.env)
552 r2 = includes_objects(bld, t2, chain, inc_loops)
554 ret = ret.union(t2.direct_objects)
557 for lib in t.direct_libs:
559 dependency_loop(inc_loops, t, lib)
562 t2 = bld.name_to_obj(lib, bld.env)
564 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
565 Logs.error('Target %s of type %s not found in direct_libs for %s' % (
566 lib, targets[lib], t.sname))
568 r2 = includes_objects(bld, t2, chain, inc_loops)
570 ret = ret.union(t2.direct_objects)
573 t.includes_objects = ret
577 def break_dependency_loops(bld, tgt_list):
578 '''find and break dependency loops'''
582 # build up the list of loops
584 indirect_objects(bld, t, set(), loops)
585 indirect_libs(bld, t, set(), loops)
586 includes_objects(bld, t, set(), inc_loops)
591 for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
592 objs = getattr(t, attr, set())
593 setattr(t, attr, objs.difference(loops[t.sname]))
596 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
598 for loop in inc_loops:
599 debug('deps: Found include loops for target %s : %s', loop, inc_loops[loop])
601 # expand the loops mapping by one level
602 for loop in loops.copy():
603 for tgt in loops[loop]:
605 loops[loop] = loops[loop].union(loops[tgt])
607 for loop in inc_loops.copy():
608 for tgt in inc_loops[loop]:
610 inc_loops[loop] = inc_loops[loop].union(inc_loops[tgt])
613 # expand indirect subsystem and library loops
614 for loop in loops.copy():
615 t = bld.name_to_obj(loop, bld.env)
616 if t.samba_type in ['SUBSYSTEM']:
617 loops[loop] = loops[loop].union(t.indirect_objects)
618 loops[loop] = loops[loop].union(t.direct_objects)
619 if t.samba_type in ['LIBRARY','PYTHON']:
620 loops[loop] = loops[loop].union(t.indirect_libs)
621 loops[loop] = loops[loop].union(t.direct_libs)
622 if loop in loops[loop]:
623 loops[loop].remove(loop)
625 # expand indirect includes loops
626 for loop in inc_loops.copy():
627 t = bld.name_to_obj(loop, bld.env)
628 inc_loops[loop] = inc_loops[loop].union(t.includes_objects)
629 if loop in inc_loops[loop]:
630 inc_loops[loop].remove(loop)
632 # add in the replacement dependencies
635 for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
636 objs = getattr(t, attr, set())
638 diff = loops[loop].difference(objs)
642 debug('deps: Expanded target %s of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
643 objs = objs.union(diff)
644 setattr(t, attr, objs)
646 for loop in inc_loops:
647 objs = getattr(t, 'includes_objects', set())
649 diff = inc_loops[loop].difference(objs)
653 debug('deps: Expanded target %s includes of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
654 objs = objs.union(diff)
655 setattr(t, 'includes_objects', objs)
658 def reduce_objects(bld, tgt_list):
659 '''reduce objects by looking for indirect object dependencies'''
663 t.extended_objects = None
667 for type in ['BINARY', 'PYTHON', 'LIBRARY']:
669 if t.samba_type != type: continue
670 # if we will indirectly link to a target then we don't need it
671 new = t.final_objects.copy()
672 for l in t.final_libs:
673 t2 = bld.name_to_obj(l, bld.env)
674 t2_obj = extended_objects(bld, t2, set())
675 dup = new.intersection(t2_obj)
676 if t.sname in rely_on:
677 dup = dup.difference(rely_on[t.sname])
679 debug('deps: removing dups from %s of type %s: %s also in %s %s',
680 t.sname, t.samba_type, dup, t2.samba_type, l)
681 new = new.difference(dup)
685 rely_on[l] = rely_on[l].union(dup)
686 t.final_objects = new
691 # add back in any objects that were relied upon by the reduction rules
693 t = bld.name_to_obj(r, bld.env)
694 t.final_objects = t.final_objects.union(rely_on[r])
699 def calculate_final_deps(bld, tgt_list, loops):
700 '''calculate the final library and object dependencies'''
702 # start with the maximum possible list
703 t.final_libs = t.direct_libs.union(indirect_libs(bld, t, set(), loops))
704 t.final_objects = t.direct_objects.union(indirect_objects(bld, t, set(), loops))
707 # don't depend on ourselves
708 if t.sname in t.final_libs:
709 t.final_libs.remove(t.sname)
710 if t.sname in t.final_objects:
711 t.final_objects.remove(t.sname)
713 # handle any non-shared binaries
715 if t.samba_type == 'BINARY' and bld.NONSHARED_BINARY(t.sname):
716 # replace lib deps with objlist deps
717 for l in t.final_libs:
718 objname = l + '.objlist'
719 t2 = bld.name_to_obj(objname, bld.env)
721 Logs.error('ERROR: subsystem %s not found' % objname)
723 t.final_objects.add(objname)
724 t.final_objects = t.final_objects.union(extended_objects(bld, t2, set()))
727 # find any library loops
729 if t.samba_type in ['LIBRARY', 'PYTHON']:
730 for l in t.final_libs.copy():
731 t2 = bld.name_to_obj(l, bld.env)
732 if t.sname in t2.final_libs:
733 if getattr(bld.env, "ALLOW_CIRCULAR_LIB_DEPENDENCIES", False):
734 # we could break this in either direction. If one of the libraries
735 # has a version number, and will this be distributed publicly, then
736 # we should make it the lower level library in the DAG
737 Logs.warn('deps: removing library loop %s from %s' % (t.sname, t2.sname))
738 dependency_loop(loops, t, t2.sname)
739 t2.final_libs.remove(t.sname)
741 Logs.error('ERROR: circular library dependency between %s and %s'
742 % (t.sname, t2.sname))
746 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
748 # we now need to make corrections for any library loops we broke up
749 # any target that depended on the target of the loop and doesn't
750 # depend on the source of the loop needs to get the loop source added
751 for type in ['BINARY','PYTHON','LIBRARY','BINARY']:
753 if t.samba_type != type: continue
755 if loop in t.final_libs:
756 diff = loops[loop].difference(t.final_libs)
761 # make sure we don't recreate the loop again!
762 for d in diff.copy():
763 t2 = bld.name_to_obj(d, bld.env)
764 if t2.samba_type == 'LIBRARY':
765 if t.sname in t2.final_libs:
766 debug('deps: removing expansion %s from %s', d, t.sname)
769 debug('deps: Expanded target %s by loop %s libraries (loop %s) %s', t.sname, loop,
771 t.final_libs = t.final_libs.union(diff)
773 # remove objects that are also available in linked libs
775 while reduce_objects(bld, tgt_list):
778 Logs.warn("WARNING: Unable to remove all inter-target object duplicates")
780 debug('deps: Object reduction took %u iterations', count)
782 # add in any syslib dependencies
784 if not t.samba_type in ['BINARY','PYTHON','LIBRARY']:
787 for d in t.final_objects:
788 t2 = bld.name_to_obj(d, bld.env)
789 syslibs = syslibs.union(t2.direct_syslibs)
790 # this adds the indirect syslibs as well, which may not be needed
791 # depending on the linker flags
792 for d in t.final_libs:
793 t2 = bld.name_to_obj(d, bld.env)
794 syslibs = syslibs.union(t2.direct_syslibs)
795 t.final_syslibs = syslibs
798 # find any unresolved library loops
799 lib_loop_error = False
801 if t.samba_type in ['LIBRARY', 'PYTHON']:
802 for l in t.final_libs.copy():
803 t2 = bld.name_to_obj(l, bld.env)
804 if t.sname in t2.final_libs:
805 Logs.error('ERROR: Unresolved library loop %s from %s' % (t.sname, t2.sname))
806 lib_loop_error = True
810 debug('deps: removed duplicate dependencies')
813 def show_dependencies(bld, target, seen):
814 '''recursively show the dependencies of target'''
819 t = bld.name_to_obj(target, bld.env)
821 Logs.error("ERROR: Unable to find target '%s'" % target)
824 Logs.info('%s(OBJECTS): %s' % (target, t.direct_objects))
825 Logs.info('%s(LIBS): %s' % (target, t.direct_libs))
826 Logs.info('%s(SYSLIBS): %s' % (target, t.direct_syslibs))
830 for t2 in t.direct_objects:
831 show_dependencies(bld, t2, seen)
834 def show_object_duplicates(bld, tgt_list):
835 '''show a list of object files that are included in more than
836 one library or binary'''
838 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
842 Logs.info("showing duplicate objects")
845 if not targets[t.sname] in [ 'LIBRARY' ]:
847 for n in getattr(t, 'final_objects', set()):
848 t2 = bld.name_to_obj(n, bld.env)
851 used_by[n].add(t.sname)
854 if len(used_by[n]) > 1:
855 Logs.info("target '%s' is used by %s" % (n, used_by[n]))
857 Logs.info("showing indirect dependency counts (sorted by count)")
859 def indirect_count(t1, t2):
860 return len(t2.indirect_objects) - len(t1.indirect_objects)
862 sorted_list = sorted(tgt_list, cmp=indirect_count)
863 for t in sorted_list:
864 if len(t.indirect_objects) > 1:
865 Logs.info("%s depends on %u indirect objects" % (t.sname, len(t.indirect_objects)))
868 ######################################################################
869 # this provides a way to save our dependency calculations between runs
871 savedeps_inputs = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags', 'source']
872 savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags']
873 savedeps_outenv = ['INC_PATHS']
874 savedeps_envvars = ['NONSHARED_BINARIES', 'GLOBAL_DEPENDENCIES']
875 savedeps_caches = ['GLOBAL_DEPENDENCIES', 'TARGET_ALIAS', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
876 savedeps_files = ['buildtools/wafsamba/samba_deps.py']
878 def save_samba_deps(bld, tgt_list):
879 '''save the dependency calculations between builds, to make
880 further builds faster'''
881 denv = Environment.Environment()
883 denv.version = savedeps_version
884 denv.savedeps_inputs = savedeps_inputs
885 denv.savedeps_outputs = savedeps_outputs
893 for f in savedeps_files:
894 denv.files[f] = os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime
896 for c in savedeps_caches:
897 denv.caches[c] = LOCAL_CACHE(bld, c)
899 for e in savedeps_envvars:
900 denv.envvar[e] = bld.env[e]
903 # save all the input attributes for each target
905 for attr in savedeps_inputs:
906 v = getattr(t, attr, None)
910 denv.input[t.sname] = tdeps
912 # save all the output attributes for each target
914 for attr in savedeps_outputs:
915 v = getattr(t, attr, None)
919 denv.output[t.sname] = tdeps
922 for attr in savedeps_outenv:
924 tdeps[attr] = t.env[attr]
926 denv.outenv[t.sname] = tdeps
928 depsfile = os.path.join(bld.bdir, "sambadeps")
933 def load_samba_deps(bld, tgt_list):
934 '''load a previous set of build dependencies if possible'''
935 depsfile = os.path.join(bld.bdir, "sambadeps")
936 denv = Environment.Environment()
938 debug('deps: checking saved dependencies')
940 if (denv.version != savedeps_version or
941 denv.savedeps_inputs != savedeps_inputs or
942 denv.savedeps_outputs != savedeps_outputs):
947 # check if critical files have changed
948 for f in savedeps_files:
949 if f not in denv.files:
951 if denv.files[f] != os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime:
954 # check if caches are the same
955 for c in savedeps_caches:
956 if c not in denv.caches or denv.caches[c] != LOCAL_CACHE(bld, c):
959 # check if caches are the same
960 for e in savedeps_envvars:
961 if e not in denv.envvar or denv.envvar[e] != bld.env[e]:
964 # check inputs are the same
967 for attr in savedeps_inputs:
968 v = getattr(t, attr, None)
971 if t.sname in denv.input:
972 olddeps = denv.input[t.sname]
976 #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
979 # put outputs in place
981 if not t.sname in denv.output: continue
982 tdeps = denv.output[t.sname]
984 setattr(t, a, tdeps[a])
986 # put output env vars in place
988 if not t.sname in denv.outenv: continue
989 tdeps = denv.outenv[t.sname]
993 debug('deps: loaded saved dependencies')
998 def check_project_rules(bld):
999 '''check the project rules - ensuring the targets are sane'''
1001 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
1005 # build a list of task generators we are interested in
1009 if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON']:
1011 t = bld.name_to_obj(tgt, bld.env)
1013 Logs.error("Target %s of type %s has no task generator" % (tgt, type))
1017 add_samba_attributes(bld, tgt_list)
1019 force_project_rules = (Options.options.SHOWDEPS or
1020 Options.options.SHOW_DUPLICATES)
1022 if not force_project_rules and load_samba_deps(bld, tgt_list):
1025 bld.new_rules = True
1026 Logs.info("Checking project rules ...")
1028 debug('deps: project rules checking started')
1030 expand_subsystem_deps(bld)
1031 build_direct_deps(bld, tgt_list)
1033 break_dependency_loops(bld, tgt_list)
1034 calculate_final_deps(bld, tgt_list, loops)
1036 if Options.options.SHOWDEPS:
1037 show_dependencies(bld, Options.options.SHOWDEPS, set())
1039 if Options.options.SHOW_DUPLICATES:
1040 show_object_duplicates(bld, tgt_list)
1042 # run the various attribute generators
1043 for f in [ build_dependencies, build_includes, add_init_functions ]:
1044 debug('deps: project rules checking %s', f)
1045 for t in tgt_list: f(t)
1047 debug('deps: project rules stage1 completed')
1049 #check_orpaned_targets(bld, tgt_list)
1051 if not check_duplicate_sources(bld, tgt_list):
1052 Logs.error("Duplicate sources present - aborting")
1055 if not check_group_ordering(bld, tgt_list):
1056 Logs.error("Bad group ordering - aborting")
1059 show_final_deps(bld, tgt_list)
1061 debug('deps: project rules checking completed - %u targets checked',
1064 if not bld.is_install:
1065 save_samba_deps(bld, tgt_list)
1067 Logs.info("Project rules pass")
1070 def CHECK_PROJECT_RULES(bld):
1071 '''enable checking of project targets for sanity'''
1072 if bld.env.added_project_rules:
1074 bld.env.added_project_rules = True
1075 bld.add_pre_fun(check_project_rules)
1076 Build.BuildContext.CHECK_PROJECT_RULES = CHECK_PROJECT_RULES