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)
16 def TARGET_ALIAS(bld, target, alias):
17 '''define an alias for a target name'''
18 cache = LOCAL_CACHE(bld, 'TARGET_ALIAS')
20 Logs.error("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
103 def build_includes(self):
104 '''This builds the right set of includes for a target.
106 One tricky part of this is that the includes= attribute for a
107 target needs to use paths which are relative to that targets
108 declaration directory (which we can get at via t.path).
110 The way this works is the includes list gets added as
111 samba_includes in the main build task declaration. Then this
112 function runs after all of the tasks are declared, and it
113 processes the samba_includes attribute to produce a includes=
117 if getattr(self, 'samba_includes', None) is None:
122 inc_deps = includes_objects(bld, self, set(), {})
126 # maybe add local includes
127 if getattr(self, 'local_include', True) == True and getattr(self, 'local_include_first', True):
130 includes.extend(self.samba_includes_extended)
132 if 'EXTRA_INCLUDES' in bld.env:
133 includes.extend(bld.env['EXTRA_INCLUDES'])
141 t = bld.name_to_obj(d, bld.env)
142 bld.ASSERT(t is not None, "Unable to find dependency %s for %s" % (d, self.sname))
143 inclist = getattr(t, 'samba_includes_extended', [])
144 if getattr(t, 'local_include', True) == True:
148 tpath = t.samba_abspath
150 npath = tpath + '/' + inc
151 if not npath in inc_set:
152 inc_abs.append(npath)
155 mypath = self.path.abspath(bld.env)
157 relpath = os_path_relpath(inc, mypath)
158 includes.append(relpath)
160 if getattr(self, 'local_include', True) == True and not getattr(self, 'local_include_first', True):
163 # now transform the includes list to be relative to the top directory
164 # which is represented by '#' in waf. This allows waf to cache the
165 # includes lists more efficiently
169 # some are already top based
170 includes_top.append(i)
172 absinc = os.path.join(self.path.abspath(), i)
173 relinc = os_path_relpath(absinc, self.bld.srcnode.abspath())
174 includes_top.append('#' + relinc)
176 self.includes = unique_list(includes_top)
177 debug('deps: includes for target %s: includes=%s',
178 self.sname, self.includes)
183 def add_init_functions(self):
184 '''This builds the right set of init functions'''
188 subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
190 # cope with the separated object lists from BINARY and LIBRARY targets
192 if sname.endswith('.objlist'):
196 if sname in subsystems:
197 modules.append(sname)
199 m = getattr(self, 'samba_modules', None)
201 modules.extend(TO_LIST(m))
203 m = getattr(self, 'samba_subsystem', None)
210 sentinal = getattr(self, 'init_function_sentinal', 'NULL')
212 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
214 cflags = getattr(self, 'samba_cflags', [])[:]
216 bld.ASSERT(m in subsystems,
217 "No init_function defined for module '%s' in target '%s'" % (m, self.sname))
219 for d in subsystems[m]:
220 if targets[d['TARGET']] != 'DISABLED':
221 init_fn_list.append(d['INIT_FUNCTION'])
222 if init_fn_list == []:
223 cflags.append('-DSTATIC_%s_MODULES=%s' % (m, sentinal))
225 cflags.append('-DSTATIC_%s_MODULES=%s' % (m, ','.join(init_fn_list) + ',' + sentinal))
226 self.ccflags = cflags
230 def check_duplicate_sources(bld, tgt_list):
231 '''see if we are compiling the same source file into multiple
232 subsystem targets for the same library or binary'''
234 debug('deps: checking for duplicate sources')
236 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
242 obj_sources = getattr(t, 'source', '')
243 tpath = os_path_relpath(t.path.abspath(bld.env), t.env.BUILD_DIRECTORY + '/default')
244 obj_sources = bld.SUBDIR(tpath, obj_sources)
245 t.samba_source_set = set(TO_LIST(obj_sources))
248 if not targets[t.sname] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
252 for obj in t.add_objects:
253 t2 = t.bld.name_to_obj(obj, bld.env)
254 source_set = getattr(t2, 'samba_source_set', set())
255 sources.append( { 'dep':obj, 'src':source_set} )
258 if s['dep'] == s2['dep']: continue
259 common = s['src'].intersection(s2['src'])
260 if common.difference(seen):
261 Logs.error("Target %s has duplicate source files in %s and %s : %s" % (t.sname,
264 seen = seen.union(common)
269 def check_orpaned_targets(bld, tgt_list):
270 '''check if any build targets are orphaned'''
272 target_dict = LOCAL_CACHE(bld, 'TARGET_TYPE')
274 debug('deps: checking for orphaned targets')
277 if getattr(t, 'samba_used', False) == True:
279 type = target_dict[t.sname]
280 if not type in ['BINARY', 'LIBRARY', 'MODULE', 'ET', 'PYTHON']:
281 if re.search('^PIDL_', t.sname) is None:
282 Logs.warn("Target %s of type %s is unused by any other target" % (t.sname, type))
285 def show_final_deps(bld, tgt_list):
286 '''show the final dependencies for all targets'''
288 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
291 if not targets[t.sname] in ['LIBRARY', 'BINARY', 'PYTHON']:
293 debug('deps: final dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
294 t.sname, t.uselib, t.uselib_local, t.add_objects)
297 def add_samba_attributes(bld, tgt_list):
298 '''ensure a target has a the required samba attributes'''
300 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
307 t.samba_type = targets[t.sname]
308 t.samba_abspath = t.path.abspath(bld.env)
309 t.samba_deps_extended = t.samba_deps[:]
310 t.samba_includes_extended = TO_LIST(t.samba_includes)[:]
311 t.ccflags = getattr(t, 'samba_cflags', '')
314 def build_direct_deps(bld, tgt_list):
315 '''build the direct_objects and direct_libs sets for each target'''
317 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
318 syslib_deps = LOCAL_CACHE(bld, 'SYSLIB_DEPS')
319 global_deps = bld.env.GLOBAL_DEPENDENCIES
322 t.direct_objects = set()
323 t.direct_libs = set()
324 t.direct_syslibs = set()
325 deps = t.samba_deps_extended
326 if getattr(t, 'samba_use_global_deps', False):
327 deps.extend(global_deps)
329 d = EXPAND_ALIAS(bld, d)
330 if d == t.sname: continue
332 Logs.error("Unknown dependency %s in %s" % (d, t.sname))
334 if targets[d] in [ 'EMPTY', 'DISABLED' ]:
336 if targets[d] == 'SYSLIB':
337 t.direct_syslibs.add(d)
339 for implied in TO_LIST(syslib_deps[d]):
340 if BUILTIN_LIBRARY(bld, implied):
341 t.direct_objects.add(implied)
342 elif targets[implied] == 'SYSLIB':
343 t.direct_syslibs.add(implied)
344 elif targets[implied] in ['LIBRARY', 'MODULE']:
345 t.direct_libs.add(implied)
347 Logs.error('Implied dependency %s in %s is of type %s' % (
348 implied, t.sname, targets[implied]))
351 t2 = bld.name_to_obj(d, bld.env)
353 Logs.error("no task %s of type %s in %s" % (d, targets[d], t.sname))
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)
496 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
497 Logs.error('Target %s of type %s not found in direct_libs for %s' % (
498 lib, targets[lib], t.sname))
500 r2 = includes_objects(bld, t2, chain, inc_loops)
502 ret = ret.union(t2.direct_objects)
505 t.includes_objects = ret
509 def break_dependency_loops(bld, tgt_list):
510 '''find and break dependency loops'''
514 # build up the list of loops
516 indirect_objects(bld, t, set(), loops)
517 indirect_libs(bld, t, set(), loops)
518 includes_objects(bld, t, set(), inc_loops)
523 for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
524 objs = getattr(t, attr, set())
525 setattr(t, attr, objs.difference(loops[t.sname]))
528 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
530 for loop in inc_loops:
531 debug('deps: Found include loops for target %s : %s', loop, inc_loops[loop])
533 # expand the loops mapping by one level
534 for loop in loops.copy():
535 for tgt in loops[loop]:
537 loops[loop] = loops[loop].union(loops[tgt])
539 for loop in inc_loops.copy():
540 for tgt in inc_loops[loop]:
542 inc_loops[loop] = inc_loops[loop].union(inc_loops[tgt])
545 # expand indirect subsystem and library loops
546 for loop in loops.copy():
547 t = bld.name_to_obj(loop, bld.env)
548 if t.samba_type in ['SUBSYSTEM']:
549 loops[loop] = loops[loop].union(t.indirect_objects)
550 loops[loop] = loops[loop].union(t.direct_objects)
551 if t.samba_type in ['LIBRARY','PYTHON']:
552 loops[loop] = loops[loop].union(t.indirect_libs)
553 loops[loop] = loops[loop].union(t.direct_libs)
554 if loop in loops[loop]:
555 loops[loop].remove(loop)
557 # expand indirect includes loops
558 for loop in inc_loops.copy():
559 t = bld.name_to_obj(loop, bld.env)
560 inc_loops[loop] = inc_loops[loop].union(t.includes_objects)
561 if loop in inc_loops[loop]:
562 inc_loops[loop].remove(loop)
564 # add in the replacement dependencies
567 for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
568 objs = getattr(t, attr, set())
570 diff = loops[loop].difference(objs)
574 debug('deps: Expanded target %s of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
575 objs = objs.union(diff)
576 setattr(t, attr, objs)
578 for loop in inc_loops:
579 objs = getattr(t, 'includes_objects', set())
581 diff = inc_loops[loop].difference(objs)
585 debug('deps: Expanded target %s includes of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
586 objs = objs.union(diff)
587 setattr(t, 'includes_objects', objs)
590 def reduce_objects(bld, tgt_list):
591 '''reduce objects by looking for indirect object dependencies'''
595 t.extended_objects = None
599 for type in ['BINARY', 'PYTHON', 'LIBRARY']:
601 if t.samba_type != type: continue
602 # if we will indirectly link to a target then we don't need it
603 new = t.final_objects.copy()
604 for l in t.final_libs:
605 t2 = bld.name_to_obj(l, bld.env)
606 t2_obj = extended_objects(bld, t2, set())
607 dup = new.intersection(t2_obj)
608 if t.sname in rely_on:
609 dup = dup.difference(rely_on[t.sname])
611 debug('deps: removing dups from %s of type %s: %s also in %s %s',
612 t.sname, t.samba_type, dup, t2.samba_type, l)
613 new = new.difference(dup)
617 rely_on[l] = rely_on[l].union(dup)
618 t.final_objects = new
623 # add back in any objects that were relied upon by the reduction rules
625 t = bld.name_to_obj(r, bld.env)
626 t.final_objects = t.final_objects.union(rely_on[r])
631 def calculate_final_deps(bld, tgt_list, loops):
632 '''calculate the final library and object dependencies'''
634 # start with the maximum possible list
635 t.final_libs = t.direct_libs.union(indirect_libs(bld, t, set(), loops))
636 t.final_objects = t.direct_objects.union(indirect_objects(bld, t, set(), loops))
639 # don't depend on ourselves
640 if t.sname in t.final_libs:
641 t.final_libs.remove(t.sname)
642 if t.sname in t.final_objects:
643 t.final_objects.remove(t.sname)
646 # find any library loops
648 if t.samba_type in ['LIBRARY', 'PYTHON']:
649 for l in t.final_libs.copy():
650 t2 = bld.name_to_obj(l, bld.env)
651 if t.sname in t2.final_libs:
652 # we could break this in either direction. If one of the libraries
653 # has a version number, and will this be distributed publicly, then
654 # we should make it the lower level library in the DAG
655 debug('deps: removing library loop %s from %s', t.sname, t2.sname)
656 dependency_loop(loops, t, t2.sname)
657 t2.final_libs.remove(t.sname)
661 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
663 # we now need to make corrections for any library loops we broke up
664 # any target that depended on the target of the loop and doesn't
665 # depend on the source of the loop needs to get the loop source added
666 for type in ['BINARY','PYTHON','LIBRARY','BINARY']:
668 if t.samba_type != type: continue
670 if loop in t.final_libs:
671 diff = loops[loop].difference(t.final_libs)
676 # make sure we don't recreate the loop again!
677 for d in diff.copy():
678 t2 = bld.name_to_obj(d, bld.env)
679 if t2.samba_type == 'LIBRARY':
680 if t.sname in t2.final_libs:
681 debug('deps: removing expansion %s from %s', d, t.sname)
684 debug('deps: Expanded target %s by loop %s libraries (loop %s) %s', t.sname, loop,
686 t.final_libs = t.final_libs.union(diff)
688 # remove objects that are also available in linked libs
690 while reduce_objects(bld, tgt_list):
693 Logs.warn("WARNING: Unable to remove all inter-target object duplicates")
695 debug('deps: Object reduction took %u iterations', count)
697 # add in any syslib dependencies
699 if not t.samba_type in ['BINARY','PYTHON','LIBRARY']:
702 for d in t.final_objects:
703 t2 = bld.name_to_obj(d, bld.env)
704 syslibs = syslibs.union(t2.direct_syslibs)
705 # this adds the indirect syslibs as well, which may not be needed
706 # depending on the linker flags
707 for d in t.final_libs:
708 t2 = bld.name_to_obj(d, bld.env)
709 syslibs = syslibs.union(t2.direct_syslibs)
710 t.final_syslibs = syslibs
713 # find any unresolved library loops
714 lib_loop_error = False
716 if t.samba_type in ['LIBRARY', 'PYTHON']:
717 for l in t.final_libs.copy():
718 t2 = bld.name_to_obj(l, bld.env)
719 if t.sname in t2.final_libs:
720 Logs.error('ERROR: Unresolved library loop %s from %s' % (t.sname, t2.sname))
721 lib_loop_error = True
725 debug('deps: removed duplicate dependencies')
728 ######################################################################
729 # this provides a way to save our dependency calculations between runs
731 savedeps_inputs = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags', 'source']
732 savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags']
733 savedeps_outenv = ['INC_PATHS']
734 savedeps_caches = ['GLOBAL_DEPENDENCIES', 'TARGET_ALIAS', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
735 savedeps_files = ['buildtools/wafsamba/samba_deps.py']
737 def save_samba_deps(bld, tgt_list):
738 '''save the dependency calculations between builds, to make
739 further builds faster'''
740 denv = Environment.Environment()
742 denv.version = savedeps_version
743 denv.savedeps_inputs = savedeps_inputs
744 denv.savedeps_outputs = savedeps_outputs
751 for f in savedeps_files:
752 denv.files[f] = os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime
754 for c in savedeps_caches:
755 denv.caches[c] = LOCAL_CACHE(bld, c)
758 # save all the input attributes for each target
760 for attr in savedeps_inputs:
761 v = getattr(t, attr, None)
765 denv.input[t.sname] = tdeps
767 # save all the output attributes for each target
769 for attr in savedeps_outputs:
770 v = getattr(t, attr, None)
774 denv.output[t.sname] = tdeps
777 for attr in savedeps_outenv:
779 tdeps[attr] = t.env[attr]
781 denv.outenv[t.sname] = tdeps
783 depsfile = os.path.join(bld.bdir, "sambadeps")
788 def load_samba_deps(bld, tgt_list):
789 '''load a previous set of build dependencies if possible'''
790 depsfile = os.path.join(bld.bdir, "sambadeps")
791 denv = Environment.Environment()
793 debug('deps: checking saved dependencies')
795 if (denv.version != savedeps_version or
796 denv.savedeps_inputs != savedeps_inputs or
797 denv.savedeps_outputs != savedeps_outputs):
802 # check if critical files have changed
803 for f in savedeps_files:
804 if f not in denv.files:
806 if denv.files[f] != os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime:
809 # check if caches are the same
810 for c in savedeps_caches:
811 if c not in denv.caches or denv.caches[c] != LOCAL_CACHE(bld, c):
814 # check inputs are the same
817 for attr in savedeps_inputs:
818 v = getattr(t, attr, None)
821 if t.sname in denv.input:
822 olddeps = denv.input[t.sname]
826 #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
829 # put outputs in place
831 if not t.sname in denv.output: continue
832 tdeps = denv.output[t.sname]
834 setattr(t, a, tdeps[a])
836 # put output env vars in place
838 if not t.sname in denv.outenv: continue
839 tdeps = denv.outenv[t.sname]
843 debug('deps: loaded saved dependencies')
848 def check_project_rules(bld):
849 '''check the project rules - ensuring the targets are sane'''
851 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
855 # build a list of task generators we are interested in
859 if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON']:
861 t = bld.name_to_obj(tgt, bld.env)
863 Logs.error("Target %s of type %s has no task generator" % (tgt, type))
867 add_samba_attributes(bld, tgt_list)
869 if load_samba_deps(bld, tgt_list):
872 Logs.info("Checking project rules ...")
874 debug('deps: project rules checking started')
876 expand_subsystem_deps(bld)
877 build_direct_deps(bld, tgt_list)
878 break_dependency_loops(bld, tgt_list)
879 calculate_final_deps(bld, tgt_list, loops)
881 # run the various attribute generators
882 for f in [ build_dependencies, build_includes, add_init_functions ]:
883 debug('deps: project rules checking %s', f)
884 for t in tgt_list: f(t)
886 debug('deps: project rules stage1 completed')
888 #check_orpaned_targets(bld, tgt_list)
890 if not check_duplicate_sources(bld, tgt_list):
891 Logs.error("Duplicate sources present - aborting")
894 show_final_deps(bld, tgt_list)
896 debug('deps: project rules checking completed - %u targets checked',
899 save_samba_deps(bld, tgt_list)
901 Logs.info("Project rules pass")
904 def CHECK_PROJECT_RULES(bld):
905 '''enable checking of project targets for sanity'''
906 if bld.env.added_project_rules:
908 bld.env.added_project_rules = True
909 bld.add_pre_fun(check_project_rules)
910 Build.BuildContext.CHECK_PROJECT_RULES = CHECK_PROJECT_RULES