1 # Samba automatic dependency handling and project rules
3 import Build, os, re, Environment
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)
16 def TARGET_ALIAS(bld, target, alias):
17 '''define an alias for a target name'''
18 cache = LOCAL_CACHE(bld, 'TARGET_ALIAS')
20 print("Target alias %s already set to %s : newalias %s" % (alias, cache[alias], target))
23 Build.BuildContext.TARGET_ALIAS = TARGET_ALIAS
27 def SET_SYSLIB_DEPS(conf, target, deps):
28 '''setup some implied dependencies for a SYSLIB'''
29 cache = LOCAL_CACHE(conf, 'SYSLIB_DEPS')
33 def EXPAND_ALIAS(bld, target):
34 '''expand a target name via an alias'''
35 aliases = LOCAL_CACHE(bld, 'TARGET_ALIAS')
37 return aliases[target]
39 Build.BuildContext.EXPAND_ALIAS = EXPAND_ALIAS
42 def expand_subsystem_deps(bld):
43 '''expand the reverse dependencies resulting from subsystem
44 attributes of modules'''
45 subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
46 aliases = LOCAL_CACHE(bld, 'TARGET_ALIAS')
47 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
52 bld.ASSERT(s in targets, "Subsystem target %s not declared" % s)
54 if type == 'DISABLED' or type == 'EMPTY':
57 t = bld.name_to_obj(s, bld.env)
58 bld.ASSERT(t is not None, "Subsystem target %s not found" % s)
59 for d in subsystems[s]:
60 type = targets[d['TARGET']]
61 if type != 'DISABLED' and type != 'EMPTY':
62 t.samba_deps_extended.append(d['TARGET'])
63 t2 = bld.name_to_obj(d['TARGET'], bld.env)
64 t2.samba_includes_extended.extend(t.samba_includes_extended)
65 t2.samba_deps_extended.extend(t.samba_deps_extended)
66 t.samba_deps_extended = unique_list(t.samba_deps_extended)
70 def build_dependencies(self):
71 '''This builds the dependency list for a target. It runs after all the targets are declared
73 The reason this is not just done in the SAMBA_*() rules is that we have no way of knowing
74 the full dependency list for a target until we have all of the targets declared.
77 if self.samba_type in ['LIBRARY', 'BINARY', 'PYTHON']:
78 self.uselib = list(self.final_syslibs)
79 self.uselib_local = list(self.final_libs)
80 self.add_objects = list(self.final_objects)
82 # extra link flags from pkg_config
83 libs = self.final_syslibs.copy()
85 (ccflags, ldflags) = library_flags(self, list(libs))
86 new_ldflags = getattr(self, 'ldflags', [])
87 new_ldflags.extend(ldflags)
88 self.ldflags = new_ldflags
90 debug('deps: computed dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
91 self.sname, self.uselib, self.uselib_local, self.add_objects)
93 if self.samba_type in ['SUBSYSTEM']:
94 # this is needed for the ccflags of libs that come from pkg_config
95 self.uselib = list(self.direct_syslibs)
97 if getattr(self, 'uselib', None):
100 up_list.append(l.upper())
101 self.uselib = up_list
104 def build_includes(self):
105 '''This builds the right set of includes for a target.
107 One tricky part of this is that the includes= attribute for a
108 target needs to use paths which are relative to that targets
109 declaration directory (which we can get at via t.path).
111 The way this works is the includes list gets added as
112 samba_includes in the main build task declaration. Then this
113 function runs after all of the tasks are declared, and it
114 processes the samba_includes attribute to produce a includes=
118 if getattr(self, 'samba_includes', None) is None:
123 inc_deps = includes_objects(bld, self, set(), {})
127 # maybe add local includes
128 if getattr(self, 'local_include', True) == True and getattr(self, 'local_include_first', True):
131 includes.extend(self.samba_includes_extended)
133 if 'EXTRA_INCLUDES' in bld.env:
134 includes.extend(bld.env['EXTRA_INCLUDES'])
142 t = bld.name_to_obj(d, bld.env)
143 bld.ASSERT(t is not None, "Unable to find dependency %s for %s" % (d, self.sname))
144 inclist = getattr(t, 'samba_includes_extended', [])
145 if getattr(t, 'local_include', True) == True:
149 tpath = t.samba_abspath
151 npath = tpath + '/' + inc
152 if not npath in inc_set:
153 inc_abs.append(npath)
156 mypath = self.path.abspath(bld.env)
158 relpath = os_path_relpath(inc, mypath)
159 includes.append(relpath)
161 if getattr(self, 'local_include', True) == True and not getattr(self, 'local_include_first', True):
164 # now transform the includes list to be relative to the top directory
165 # which is represented by '#' in waf. This allows waf to cache the
166 # includes lists more efficiently
170 # some are already top based
171 includes_top.append(i)
173 absinc = os.path.join(self.path.abspath(), i)
174 relinc = os_path_relpath(absinc, self.bld.srcnode.abspath())
175 includes_top.append('#' + relinc)
177 self.includes = unique_list(includes_top)
178 debug('deps: includes for target %s: includes=%s',
179 self.sname, self.includes)
184 def add_init_functions(self):
185 '''This builds the right set of init functions'''
189 subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
191 # cope with the separated object lists from BINARY and LIBRARY targets
193 if sname.endswith('.objlist'):
197 if sname in subsystems:
198 modules.append(sname)
200 m = getattr(self, 'samba_modules', None)
202 modules.extend(TO_LIST(m))
204 m = getattr(self, 'samba_subsystem', None)
211 sentinal = getattr(self, 'init_function_sentinal', 'NULL')
213 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
215 cflags = getattr(self, 'samba_cflags', [])[:]
217 bld.ASSERT(m in subsystems,
218 "No init_function defined for module '%s' in target '%s'" % (m, self.sname))
220 for d in subsystems[m]:
221 if targets[d['TARGET']] != 'DISABLED':
222 init_fn_list.append(d['INIT_FUNCTION'])
223 if init_fn_list == []:
224 cflags.append('-DSTATIC_%s_MODULES=%s' % (m, sentinal))
226 cflags.append('-DSTATIC_%s_MODULES=%s' % (m, ','.join(init_fn_list) + ',' + sentinal))
227 self.ccflags = cflags
231 def check_duplicate_sources(bld, tgt_list):
232 '''see if we are compiling the same source file into multiple
233 subsystem targets for the same library or binary'''
235 debug('deps: checking for duplicate sources')
237 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
243 obj_sources = getattr(t, 'source', '')
244 tpath = os_path_relpath(t.path.abspath(bld.env), t.env['BUILD_DIRECTORY'] + '/default')
245 obj_sources = bld.SUBDIR(tpath, obj_sources)
246 t.samba_source_set = set(TO_LIST(obj_sources))
249 if not targets[t.sname] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
253 for obj in t.add_objects:
254 t2 = t.bld.name_to_obj(obj, bld.env)
255 source_set = getattr(t2, 'samba_source_set', set())
256 sources.append( { 'dep':obj, 'src':source_set} )
259 if s['dep'] == s2['dep']: continue
260 common = s['src'].intersection(s2['src'])
261 if common.difference(seen):
262 print("Target %s has duplicate source files in %s and %s : %s" % (t.sname,
265 seen = seen.union(common)
270 def check_orpaned_targets(bld, tgt_list):
271 '''check if any build targets are orphaned'''
273 target_dict = LOCAL_CACHE(bld, 'TARGET_TYPE')
275 debug('deps: checking for orphaned targets')
278 if getattr(t, 'samba_used', False) == True:
280 type = target_dict[t.sname]
281 if not type in ['BINARY', 'LIBRARY', 'MODULE', 'ET', 'PYTHON']:
282 if re.search('^PIDL_', t.sname) is None:
283 print "Target %s of type %s is unused by any other target" % (t.sname, type)
286 def show_final_deps(bld, tgt_list):
287 '''show the final dependencies for all targets'''
289 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
292 if not targets[t.sname] in ['LIBRARY', 'BINARY', 'PYTHON']:
294 debug('deps: final dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
295 t.sname, t.uselib, t.uselib_local, t.add_objects)
298 def add_samba_attributes(bld, tgt_list):
299 '''ensure a target has a the required samba attributes'''
301 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
308 t.samba_type = targets[t.sname]
309 t.samba_abspath = t.path.abspath(bld.env)
310 t.samba_deps_extended = t.samba_deps[:]
311 t.samba_includes_extended = TO_LIST(t.samba_includes)[:]
312 t.ccflags = getattr(t, 'samba_cflags', '')
313 install_target = getattr(t, 'install_target', None)
315 t2 = bld.name_to_obj(install_target, bld.env)
316 t2.sname = install_target
317 t2.samba_type = t.samba_type
318 t2.samba_abspath = t2.path.abspath(bld.env)
319 t2.ccflags = t.ccflags
322 def build_direct_deps(bld, tgt_list):
323 '''build the direct_objects and direct_libs sets for each target'''
325 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
326 syslib_deps = LOCAL_CACHE(bld, 'SYSLIB_DEPS')
327 global_deps = bld.env.GLOBAL_DEPENDENCIES
330 t.direct_objects = set()
331 t.direct_libs = set()
332 t.direct_syslibs = set()
333 deps = t.samba_deps_extended
334 deps.extend(global_deps)
336 d = EXPAND_ALIAS(bld, d)
337 if d == t.sname: continue
339 print "Unknown dependency %s in %s" % (d, t.sname)
341 if targets[d] in [ 'EMPTY', 'DISABLED' ]:
343 if targets[d] == 'SYSLIB':
344 t.direct_syslibs.add(d)
346 for implied in TO_LIST(syslib_deps[d]):
347 if BUILTIN_LIBRARY(bld, implied):
348 t.direct_objects.add(implied)
350 t.direct_libs.add(implied)
352 t2 = bld.name_to_obj(d, bld.env)
354 print "no task %s type %s" % (d, targets[d])
355 if t2.samba_type in [ 'LIBRARY', 'MODULE' ]:
357 elif t2.samba_type in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]:
358 t.direct_objects.add(d)
359 debug('deps: built direct dependencies')
362 def dependency_loop(loops, t, target):
363 '''add a dependency loop to the loops dictionary'''
364 if t.sname == target:
366 if not target in loops:
367 loops[target] = set()
368 if not t.sname in loops[target]:
369 loops[target].add(t.sname)
372 def indirect_libs(bld, t, chain, loops):
373 '''recursively calculate the indirect library dependencies for a target
375 An indirect library is a library that results from a dependency on
379 ret = getattr(t, 'indirect_libs', None)
384 for obj in t.direct_objects:
386 dependency_loop(loops, t, obj)
389 t2 = bld.name_to_obj(obj, bld.env)
390 r2 = indirect_libs(bld, t2, chain, loops)
392 ret = ret.union(t2.direct_libs)
395 for obj in indirect_objects(bld, t, set(), loops):
397 dependency_loop(loops, t, obj)
400 t2 = bld.name_to_obj(obj, bld.env)
401 r2 = indirect_libs(bld, t2, chain, loops)
403 ret = ret.union(t2.direct_libs)
406 t.indirect_libs = ret
411 def indirect_objects(bld, t, chain, loops):
412 '''recursively calculate the indirect object dependencies for a target
414 indirect objects are the set of objects from expanding the
415 subsystem dependencies
418 ret = getattr(t, 'indirect_objects', None)
419 if ret is not None: return ret
422 for lib in t.direct_objects:
424 dependency_loop(loops, t, lib)
427 t2 = bld.name_to_obj(lib, bld.env)
428 r2 = indirect_objects(bld, t2, chain, loops)
430 ret = ret.union(t2.direct_objects)
433 t.indirect_objects = ret
437 def extended_objects(bld, t, chain):
438 '''recursively calculate the extended object dependencies for a target
440 extended objects are the union of:
443 - direct and indirect objects of all direct and indirect libraries
446 ret = getattr(t, 'extended_objects', None)
447 if ret is not None: return ret
450 ret = ret.union(t.final_objects)
452 for lib in t.final_libs:
455 t2 = bld.name_to_obj(lib, bld.env)
457 r2 = extended_objects(bld, t2, chain)
459 ret = ret.union(t2.final_objects)
462 t.extended_objects = ret
466 def includes_objects(bld, t, chain, inc_loops):
467 '''recursively calculate the includes object dependencies for a target
469 includes dependencies come from either library or object dependencies
471 ret = getattr(t, 'includes_objects', None)
475 ret = t.direct_objects.copy()
476 ret = ret.union(t.direct_libs)
478 for obj in t.direct_objects:
480 dependency_loop(inc_loops, t, obj)
483 t2 = bld.name_to_obj(obj, bld.env)
484 r2 = includes_objects(bld, t2, chain, inc_loops)
486 ret = ret.union(t2.direct_objects)
489 for lib in t.direct_libs:
491 dependency_loop(inc_loops, t, lib)
494 t2 = bld.name_to_obj(lib, bld.env)
495 r2 = includes_objects(bld, t2, chain, inc_loops)
497 ret = ret.union(t2.direct_objects)
500 t.includes_objects = ret
504 def break_dependency_loops(bld, tgt_list):
505 '''find and break dependency loops'''
509 # build up the list of loops
511 indirect_objects(bld, t, set(), loops)
512 indirect_libs(bld, t, set(), loops)
513 includes_objects(bld, t, set(), inc_loops)
518 for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
519 objs = getattr(t, attr, set())
520 setattr(t, attr, objs.difference(loops[t.sname]))
523 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
525 for loop in inc_loops:
526 debug('deps: Found include loops for target %s : %s', loop, inc_loops[loop])
528 # expand the loops mapping by one level
529 for loop in loops.copy():
530 for tgt in loops[loop]:
532 loops[loop] = loops[loop].union(loops[tgt])
534 for loop in inc_loops.copy():
535 for tgt in inc_loops[loop]:
537 inc_loops[loop] = inc_loops[loop].union(inc_loops[tgt])
540 # expand indirect subsystem and library loops
541 for loop in loops.copy():
542 t = bld.name_to_obj(loop, bld.env)
543 if t.samba_type in ['SUBSYSTEM']:
544 loops[loop] = loops[loop].union(t.indirect_objects)
545 loops[loop] = loops[loop].union(t.direct_objects)
546 if t.samba_type in ['LIBRARY','PYTHON']:
547 loops[loop] = loops[loop].union(t.indirect_libs)
548 loops[loop] = loops[loop].union(t.direct_libs)
549 if loop in loops[loop]:
550 loops[loop].remove(loop)
552 # expand indirect includes loops
553 for loop in inc_loops.copy():
554 t = bld.name_to_obj(loop, bld.env)
555 inc_loops[loop] = inc_loops[loop].union(t.includes_objects)
556 if loop in inc_loops[loop]:
557 inc_loops[loop].remove(loop)
559 # add in the replacement dependencies
562 for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
563 objs = getattr(t, attr, set())
565 diff = loops[loop].difference(objs)
569 debug('deps: Expanded target %s of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
570 objs = objs.union(diff)
571 setattr(t, attr, objs)
573 for loop in inc_loops:
574 objs = getattr(t, 'includes_objects', set())
576 diff = inc_loops[loop].difference(objs)
580 debug('deps: Expanded target %s includes of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
581 objs = objs.union(diff)
582 setattr(t, 'includes_objects', objs)
585 def reduce_objects(bld, tgt_list):
586 '''reduce objects by looking for indirect object dependencies'''
590 t.extended_objects = None
592 for type in ['BINARY', 'PYTHON', 'LIBRARY']:
594 if t.samba_type != type: continue
595 # if we will indirectly link to a target then we don't need it
596 new = t.final_objects.copy()
597 for l in t.final_libs:
598 t2 = bld.name_to_obj(l, bld.env)
599 t2_obj = extended_objects(bld, t2, set())
600 dup = new.intersection(t2_obj)
602 debug('deps: removing dups from %s of type %s: %s also in %s %s',
603 t.sname, t.samba_type, dup, t2.samba_type, l)
604 new = new.difference(dup)
608 rely_on[l] = rely_on[l].union(dup)
609 t.final_objects = new
611 # add back in any objects that were relied upon by the reduction rules
613 t = bld.name_to_obj(r, bld.env)
614 t.final_objects = t.final_objects.union(rely_on[r])
617 def calculate_final_deps(bld, tgt_list, loops):
618 '''calculate the final library and object dependencies'''
620 # start with the maximum possible list
621 t.final_libs = t.direct_libs.union(indirect_libs(bld, t, set(), loops))
622 t.final_objects = t.direct_objects.union(indirect_objects(bld, t, set(), loops))
625 # don't depend on ourselves
626 if t.sname in t.final_libs:
627 t.final_libs.remove(t.sname)
628 if t.sname in t.final_objects:
629 t.final_objects.remove(t.sname)
632 # find any library loops
634 if t.samba_type in ['LIBRARY', 'PYTHON']:
635 for l in t.final_libs.copy():
636 t2 = bld.name_to_obj(l, bld.env)
637 if t.sname in t2.final_libs:
638 # we could break this in either direction. If one of the libraries
639 # has a version number, and will this be distributed publicly, then
640 # we should make it the lower level library in the DAG
641 debug('deps: removing library loop %s from %s', t.sname, t2.sname)
642 dependency_loop(loops, t, t2.sname)
643 t2.final_libs.remove(t.sname)
647 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
649 # we now need to make corrections for any library loops we broke up
650 # any target that depended on the target of the loop and doesn't
651 # depend on the source of the loop needs to get the loop source added
652 for type in ['BINARY','PYTHON','LIBRARY','BINARY']:
654 if t.samba_type != type: continue
656 if loop in t.final_libs:
657 diff = loops[loop].difference(t.final_libs)
661 debug('deps: Expanded target %s by loop %s libraries %s', t.sname, loop, diff)
662 t.final_libs = t.final_libs.union(diff)
664 # remove objects that are also available in linked libs
665 reduce_objects(bld, tgt_list)
667 # add in any syslib dependencies
669 if not t.samba_type in ['BINARY','PYTHON','LIBRARY']:
672 for d in t.final_objects:
673 t2 = bld.name_to_obj(d, bld.env)
674 syslibs = syslibs.union(t2.direct_syslibs)
675 # this adds the indirect syslibs as well, which may not be needed
676 # depending on the linker flags
677 for d in t.final_libs:
678 t2 = bld.name_to_obj(d, bld.env)
679 syslibs = syslibs.union(t2.direct_syslibs)
680 t.final_syslibs = syslibs
682 debug('deps: removed duplicate dependencies')
685 ######################################################################
686 # this provides a way to save our dependency calculations between runs
688 savedeps_inputs = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags', 'source']
689 savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags']
690 savedeps_outenv = ['INC_PATHS']
691 savedeps_caches = ['GLOBAL_DEPENDENCIES', 'TARGET_ALIAS', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
692 savedeps_files = ['buildtools/wafsamba/samba_deps.py']
694 def save_samba_deps(bld, tgt_list):
695 '''save the dependency calculations between builds, to make
696 further builds faster'''
697 denv = Environment.Environment()
699 denv.version = savedeps_version
700 denv.savedeps_inputs = savedeps_inputs
701 denv.savedeps_outputs = savedeps_outputs
708 for f in savedeps_files:
709 denv.files[f] = os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime
711 for c in savedeps_caches:
712 denv.caches[c] = LOCAL_CACHE(bld, c)
715 # save all the input attributes for each target
717 for attr in savedeps_inputs:
718 v = getattr(t, attr, None)
722 denv.input[t.sname] = tdeps
724 # save all the output attributes for each target
726 for attr in savedeps_outputs:
727 v = getattr(t, attr, None)
731 denv.output[t.sname] = tdeps
734 for attr in savedeps_outenv:
736 tdeps[attr] = t.env[attr]
738 denv.outenv[t.sname] = tdeps
740 depsfile = os.path.join(bld.bdir, "sambadeps")
745 def load_samba_deps(bld, tgt_list):
746 '''load a previous set of build dependencies if possible'''
747 depsfile = os.path.join(bld.bdir, "sambadeps")
748 denv = Environment.Environment()
750 debug('deps: checking saved dependencies')
752 if (denv.version != savedeps_version or
753 denv.savedeps_inputs != savedeps_inputs or
754 denv.savedeps_outputs != savedeps_outputs):
759 # check if critical files have changed
760 for f in savedeps_files:
761 if f not in denv.files:
763 if denv.files[f] != os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime:
766 # check if caches are the same
767 for c in savedeps_caches:
768 if c not in denv.caches or denv.caches[c] != LOCAL_CACHE(bld, c):
771 # check inputs are the same
774 for attr in savedeps_inputs:
775 v = getattr(t, attr, None)
778 if t.sname in denv.input:
779 olddeps = denv.input[t.sname]
783 #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
786 tgt_list_extended = tgt_list[:]
788 install_target = getattr(t, 'install_target', None)
790 t2 = bld.name_to_obj(install_target, bld.env)
791 tgt_list_extended.append(t2)
793 # put outputs in place
794 for t in tgt_list_extended:
795 if not t.sname in denv.output: continue
796 tdeps = denv.output[t.sname]
798 setattr(t, a, tdeps[a])
800 # put output env vars in place
801 for t in tgt_list_extended:
802 if not t.sname in denv.outenv: continue
803 tdeps = denv.outenv[t.sname]
807 debug('deps: loaded saved dependencies')
812 def add_install_deps(bld, tgt_list):
813 '''add attributes for install libs/binaries
815 This ensures that all the install targets have identical dependencies
816 to the build targets.
818 for t in tgt_list[:]:
819 install_target = getattr(t, 'install_target', None)
821 t2 = bld.name_to_obj(install_target, bld.env)
823 print('install_target %s not found for %s' % (install_target, t.sname))
826 for attr in savedeps_outputs:
827 v = getattr(t, attr, None)
830 for attr in savedeps_outenv:
832 t2.env[attr] = t.env[attr]
835 def check_project_rules(bld):
836 '''check the project rules - ensuring the targets are sane'''
838 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
842 # build a list of task generators we are interested in
845 if tgt.endswith('.inst'):
848 if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON']:
850 t = bld.name_to_obj(tgt, bld.env)
852 print "Target %s of type %s has no task generator" % (tgt, type)
856 add_samba_attributes(bld, tgt_list)
858 if load_samba_deps(bld, tgt_list):
859 add_install_deps(bld, tgt_list)
862 print "Checking project rules ..."
864 debug('deps: project rules checking started')
866 expand_subsystem_deps(bld)
867 build_direct_deps(bld, tgt_list)
868 break_dependency_loops(bld, tgt_list)
869 calculate_final_deps(bld, tgt_list, loops)
871 # run the various attribute generators
872 for f in [ build_dependencies, build_includes, add_init_functions ]:
873 debug('deps: project rules checking %s', f)
874 for t in tgt_list: f(t)
876 debug('deps: project rules stage1 completed')
878 #check_orpaned_targets(bld, tgt_list)
880 if not check_duplicate_sources(bld, tgt_list):
881 print "Duplicate sources present - aborting"
884 show_final_deps(bld, tgt_list)
886 debug('deps: project rules checking completed - %u targets checked',
889 save_samba_deps(bld, tgt_list)
891 add_install_deps(bld, tgt_list)
893 print "Project rules pass"
896 def CHECK_PROJECT_RULES(bld):
897 '''enable checking of project targets for sanity'''
898 if bld.env.added_project_rules:
900 bld.env.added_project_rules = True
901 bld.add_pre_fun(check_project_rules)
902 Build.BuildContext.CHECK_PROJECT_RULES = CHECK_PROJECT_RULES