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)
645 # handle any non-shared binaries
647 if t.samba_type == 'BINARY' and bld.NONSHARED_BINARY(t.sname):
648 # replace lib deps with objlist deps
649 for l in t.final_libs:
650 objname = l + '.objlist'
651 t2 = bld.name_to_obj(objname, bld.env)
653 Logs.error('ERROR: subsystem %s not found' % objname)
655 t.final_objects.add(objname)
656 t.final_objects = t.final_objects.union(extended_objects(bld, t2, set()))
659 # find any library loops
661 if t.samba_type in ['LIBRARY', 'PYTHON']:
662 for l in t.final_libs.copy():
663 t2 = bld.name_to_obj(l, bld.env)
664 if t.sname in t2.final_libs:
665 # we could break this in either direction. If one of the libraries
666 # has a version number, and will this be distributed publicly, then
667 # we should make it the lower level library in the DAG
668 debug('deps: removing library loop %s from %s', t.sname, t2.sname)
669 dependency_loop(loops, t, t2.sname)
670 t2.final_libs.remove(t.sname)
674 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
676 # we now need to make corrections for any library loops we broke up
677 # any target that depended on the target of the loop and doesn't
678 # depend on the source of the loop needs to get the loop source added
679 for type in ['BINARY','PYTHON','LIBRARY','BINARY']:
681 if t.samba_type != type: continue
683 if loop in t.final_libs:
684 diff = loops[loop].difference(t.final_libs)
689 # make sure we don't recreate the loop again!
690 for d in diff.copy():
691 t2 = bld.name_to_obj(d, bld.env)
692 if t2.samba_type == 'LIBRARY':
693 if t.sname in t2.final_libs:
694 debug('deps: removing expansion %s from %s', d, t.sname)
697 debug('deps: Expanded target %s by loop %s libraries (loop %s) %s', t.sname, loop,
699 t.final_libs = t.final_libs.union(diff)
701 # remove objects that are also available in linked libs
703 while reduce_objects(bld, tgt_list):
706 Logs.warn("WARNING: Unable to remove all inter-target object duplicates")
708 debug('deps: Object reduction took %u iterations', count)
710 # add in any syslib dependencies
712 if not t.samba_type in ['BINARY','PYTHON','LIBRARY']:
715 for d in t.final_objects:
716 t2 = bld.name_to_obj(d, bld.env)
717 syslibs = syslibs.union(t2.direct_syslibs)
718 # this adds the indirect syslibs as well, which may not be needed
719 # depending on the linker flags
720 for d in t.final_libs:
721 t2 = bld.name_to_obj(d, bld.env)
722 syslibs = syslibs.union(t2.direct_syslibs)
723 t.final_syslibs = syslibs
726 # find any unresolved library loops
727 lib_loop_error = False
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 Logs.error('ERROR: Unresolved library loop %s from %s' % (t.sname, t2.sname))
734 lib_loop_error = True
738 debug('deps: removed duplicate dependencies')
741 ######################################################################
742 # this provides a way to save our dependency calculations between runs
744 savedeps_inputs = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags', 'source']
745 savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags']
746 savedeps_outenv = ['INC_PATHS']
747 savedeps_caches = ['GLOBAL_DEPENDENCIES', 'TARGET_ALIAS', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
748 savedeps_files = ['buildtools/wafsamba/samba_deps.py']
750 def save_samba_deps(bld, tgt_list):
751 '''save the dependency calculations between builds, to make
752 further builds faster'''
753 denv = Environment.Environment()
755 denv.version = savedeps_version
756 denv.savedeps_inputs = savedeps_inputs
757 denv.savedeps_outputs = savedeps_outputs
764 for f in savedeps_files:
765 denv.files[f] = os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime
767 for c in savedeps_caches:
768 denv.caches[c] = LOCAL_CACHE(bld, c)
771 # save all the input attributes for each target
773 for attr in savedeps_inputs:
774 v = getattr(t, attr, None)
778 denv.input[t.sname] = tdeps
780 # save all the output attributes for each target
782 for attr in savedeps_outputs:
783 v = getattr(t, attr, None)
787 denv.output[t.sname] = tdeps
790 for attr in savedeps_outenv:
792 tdeps[attr] = t.env[attr]
794 denv.outenv[t.sname] = tdeps
796 depsfile = os.path.join(bld.bdir, "sambadeps")
801 def load_samba_deps(bld, tgt_list):
802 '''load a previous set of build dependencies if possible'''
803 depsfile = os.path.join(bld.bdir, "sambadeps")
804 denv = Environment.Environment()
806 debug('deps: checking saved dependencies')
808 if (denv.version != savedeps_version or
809 denv.savedeps_inputs != savedeps_inputs or
810 denv.savedeps_outputs != savedeps_outputs):
815 # check if critical files have changed
816 for f in savedeps_files:
817 if f not in denv.files:
819 if denv.files[f] != os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime:
822 # check if caches are the same
823 for c in savedeps_caches:
824 if c not in denv.caches or denv.caches[c] != LOCAL_CACHE(bld, c):
827 # check inputs are the same
830 for attr in savedeps_inputs:
831 v = getattr(t, attr, None)
834 if t.sname in denv.input:
835 olddeps = denv.input[t.sname]
839 #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
842 # put outputs in place
844 if not t.sname in denv.output: continue
845 tdeps = denv.output[t.sname]
847 setattr(t, a, tdeps[a])
849 # put output env vars in place
851 if not t.sname in denv.outenv: continue
852 tdeps = denv.outenv[t.sname]
856 debug('deps: loaded saved dependencies')
861 def check_project_rules(bld):
862 '''check the project rules - ensuring the targets are sane'''
864 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
868 # build a list of task generators we are interested in
872 if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON']:
874 t = bld.name_to_obj(tgt, bld.env)
876 Logs.error("Target %s of type %s has no task generator" % (tgt, type))
880 add_samba_attributes(bld, tgt_list)
882 if load_samba_deps(bld, tgt_list):
885 Logs.info("Checking project rules ...")
887 debug('deps: project rules checking started')
889 expand_subsystem_deps(bld)
890 build_direct_deps(bld, tgt_list)
891 break_dependency_loops(bld, tgt_list)
892 calculate_final_deps(bld, tgt_list, loops)
894 # run the various attribute generators
895 for f in [ build_dependencies, build_includes, add_init_functions ]:
896 debug('deps: project rules checking %s', f)
897 for t in tgt_list: f(t)
899 debug('deps: project rules stage1 completed')
901 #check_orpaned_targets(bld, tgt_list)
903 if not check_duplicate_sources(bld, tgt_list):
904 Logs.error("Duplicate sources present - aborting")
907 show_final_deps(bld, tgt_list)
909 debug('deps: project rules checking completed - %u targets checked',
912 save_samba_deps(bld, tgt_list)
914 Logs.info("Project rules pass")
917 def CHECK_PROJECT_RULES(bld):
918 '''enable checking of project targets for sanity'''
919 if bld.env.added_project_rules:
921 bld.env.added_project_rules = True
922 bld.add_pre_fun(check_project_rules)
923 Build.BuildContext.CHECK_PROJECT_RULES = CHECK_PROJECT_RULES