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.normpath(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 check_group_ordering(bld, tgt_list):
286 '''see if we have any dependencies that violate the group ordering
288 It is an error for a target to depend on a target from a later
293 tm = bld.task_manager
294 return [x for x in tm.groups_names if id(tm.groups_names[x]) == id(g)][0]
296 for g in bld.task_manager.groups:
297 gname = group_name(g)
298 for t in g.tasks_gen:
299 t.samba_group = gname
303 for g in bld.task_manager.groups:
308 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
312 tdeps = getattr(t, 'add_objects', []) + getattr(t, 'uselib_local', [])
314 t2 = bld.name_to_obj(d, bld.env)
317 map1 = grp_map[t.samba_group]
318 map2 = grp_map[t2.samba_group]
321 Logs.error("Target %r in build group %r depends on target %r from later build group %r" % (
322 t.sname, t.samba_group, t2.sname, t2.samba_group))
328 def show_final_deps(bld, tgt_list):
329 '''show the final dependencies for all targets'''
331 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
334 if not targets[t.sname] in ['LIBRARY', 'BINARY', 'PYTHON']:
336 debug('deps: final dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
337 t.sname, t.uselib, t.uselib_local, t.add_objects)
340 def add_samba_attributes(bld, tgt_list):
341 '''ensure a target has a the required samba attributes'''
343 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
350 t.samba_type = targets[t.sname]
351 t.samba_abspath = t.path.abspath(bld.env)
352 t.samba_deps_extended = t.samba_deps[:]
353 t.samba_includes_extended = TO_LIST(t.samba_includes)[:]
354 t.ccflags = getattr(t, 'samba_cflags', '')
357 def build_direct_deps(bld, tgt_list):
358 '''build the direct_objects and direct_libs sets for each target'''
360 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
361 syslib_deps = LOCAL_CACHE(bld, 'SYSLIB_DEPS')
362 global_deps = bld.env.GLOBAL_DEPENDENCIES
365 t.direct_objects = set()
366 t.direct_libs = set()
367 t.direct_syslibs = set()
368 deps = t.samba_deps_extended
369 if getattr(t, 'samba_use_global_deps', False):
370 deps.extend(global_deps)
372 d = EXPAND_ALIAS(bld, d)
373 if d == t.sname: continue
375 Logs.error("Unknown dependency %s in %s" % (d, t.sname))
377 if targets[d] in [ 'EMPTY', 'DISABLED' ]:
379 if targets[d] == 'SYSLIB':
380 t.direct_syslibs.add(d)
382 for implied in TO_LIST(syslib_deps[d]):
383 if BUILTIN_LIBRARY(bld, implied):
384 t.direct_objects.add(implied)
385 elif targets[implied] == 'SYSLIB':
386 t.direct_syslibs.add(implied)
387 elif targets[implied] in ['LIBRARY', 'MODULE']:
388 t.direct_libs.add(implied)
390 Logs.error('Implied dependency %s in %s is of type %s' % (
391 implied, t.sname, targets[implied]))
394 t2 = bld.name_to_obj(d, bld.env)
396 Logs.error("no task %s of type %s in %s" % (d, targets[d], t.sname))
398 if t2.samba_type in [ 'LIBRARY', 'MODULE' ]:
400 elif t2.samba_type in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]:
401 t.direct_objects.add(d)
402 debug('deps: built direct dependencies')
405 def dependency_loop(loops, t, target):
406 '''add a dependency loop to the loops dictionary'''
407 if t.sname == target:
409 if not target in loops:
410 loops[target] = set()
411 if not t.sname in loops[target]:
412 loops[target].add(t.sname)
415 def indirect_libs(bld, t, chain, loops):
416 '''recursively calculate the indirect library dependencies for a target
418 An indirect library is a library that results from a dependency on
422 ret = getattr(t, 'indirect_libs', None)
427 for obj in t.direct_objects:
429 dependency_loop(loops, t, obj)
432 t2 = bld.name_to_obj(obj, bld.env)
433 r2 = indirect_libs(bld, t2, chain, loops)
435 ret = ret.union(t2.direct_libs)
438 for obj in indirect_objects(bld, t, set(), loops):
440 dependency_loop(loops, t, obj)
443 t2 = bld.name_to_obj(obj, bld.env)
444 r2 = indirect_libs(bld, t2, chain, loops)
446 ret = ret.union(t2.direct_libs)
449 t.indirect_libs = ret
454 def indirect_objects(bld, t, chain, loops):
455 '''recursively calculate the indirect object dependencies for a target
457 indirect objects are the set of objects from expanding the
458 subsystem dependencies
461 ret = getattr(t, 'indirect_objects', None)
462 if ret is not None: return ret
465 for lib in t.direct_objects:
467 dependency_loop(loops, t, lib)
470 t2 = bld.name_to_obj(lib, bld.env)
471 r2 = indirect_objects(bld, t2, chain, loops)
473 ret = ret.union(t2.direct_objects)
476 t.indirect_objects = ret
480 def extended_objects(bld, t, chain):
481 '''recursively calculate the extended object dependencies for a target
483 extended objects are the union of:
486 - direct and indirect objects of all direct and indirect libraries
489 ret = getattr(t, 'extended_objects', None)
490 if ret is not None: return ret
493 ret = ret.union(t.final_objects)
495 for lib in t.final_libs:
498 t2 = bld.name_to_obj(lib, bld.env)
500 r2 = extended_objects(bld, t2, chain)
502 ret = ret.union(t2.final_objects)
505 t.extended_objects = ret
509 def includes_objects(bld, t, chain, inc_loops):
510 '''recursively calculate the includes object dependencies for a target
512 includes dependencies come from either library or object dependencies
514 ret = getattr(t, 'includes_objects', None)
518 ret = t.direct_objects.copy()
519 ret = ret.union(t.direct_libs)
521 for obj in t.direct_objects:
523 dependency_loop(inc_loops, t, obj)
526 t2 = bld.name_to_obj(obj, bld.env)
527 r2 = includes_objects(bld, t2, chain, inc_loops)
529 ret = ret.union(t2.direct_objects)
532 for lib in t.direct_libs:
534 dependency_loop(inc_loops, t, lib)
537 t2 = bld.name_to_obj(lib, bld.env)
539 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
540 Logs.error('Target %s of type %s not found in direct_libs for %s' % (
541 lib, targets[lib], t.sname))
543 r2 = includes_objects(bld, t2, chain, inc_loops)
545 ret = ret.union(t2.direct_objects)
548 t.includes_objects = ret
552 def break_dependency_loops(bld, tgt_list):
553 '''find and break dependency loops'''
557 # build up the list of loops
559 indirect_objects(bld, t, set(), loops)
560 indirect_libs(bld, t, set(), loops)
561 includes_objects(bld, t, set(), inc_loops)
566 for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
567 objs = getattr(t, attr, set())
568 setattr(t, attr, objs.difference(loops[t.sname]))
571 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
573 for loop in inc_loops:
574 debug('deps: Found include loops for target %s : %s', loop, inc_loops[loop])
576 # expand the loops mapping by one level
577 for loop in loops.copy():
578 for tgt in loops[loop]:
580 loops[loop] = loops[loop].union(loops[tgt])
582 for loop in inc_loops.copy():
583 for tgt in inc_loops[loop]:
585 inc_loops[loop] = inc_loops[loop].union(inc_loops[tgt])
588 # expand indirect subsystem and library loops
589 for loop in loops.copy():
590 t = bld.name_to_obj(loop, bld.env)
591 if t.samba_type in ['SUBSYSTEM']:
592 loops[loop] = loops[loop].union(t.indirect_objects)
593 loops[loop] = loops[loop].union(t.direct_objects)
594 if t.samba_type in ['LIBRARY','PYTHON']:
595 loops[loop] = loops[loop].union(t.indirect_libs)
596 loops[loop] = loops[loop].union(t.direct_libs)
597 if loop in loops[loop]:
598 loops[loop].remove(loop)
600 # expand indirect includes loops
601 for loop in inc_loops.copy():
602 t = bld.name_to_obj(loop, bld.env)
603 inc_loops[loop] = inc_loops[loop].union(t.includes_objects)
604 if loop in inc_loops[loop]:
605 inc_loops[loop].remove(loop)
607 # add in the replacement dependencies
610 for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
611 objs = getattr(t, attr, set())
613 diff = loops[loop].difference(objs)
617 debug('deps: Expanded target %s of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
618 objs = objs.union(diff)
619 setattr(t, attr, objs)
621 for loop in inc_loops:
622 objs = getattr(t, 'includes_objects', set())
624 diff = inc_loops[loop].difference(objs)
628 debug('deps: Expanded target %s includes of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
629 objs = objs.union(diff)
630 setattr(t, 'includes_objects', objs)
633 def reduce_objects(bld, tgt_list):
634 '''reduce objects by looking for indirect object dependencies'''
638 t.extended_objects = None
642 for type in ['BINARY', 'PYTHON', 'LIBRARY']:
644 if t.samba_type != type: continue
645 # if we will indirectly link to a target then we don't need it
646 new = t.final_objects.copy()
647 for l in t.final_libs:
648 t2 = bld.name_to_obj(l, bld.env)
649 t2_obj = extended_objects(bld, t2, set())
650 dup = new.intersection(t2_obj)
651 if t.sname in rely_on:
652 dup = dup.difference(rely_on[t.sname])
654 debug('deps: removing dups from %s of type %s: %s also in %s %s',
655 t.sname, t.samba_type, dup, t2.samba_type, l)
656 new = new.difference(dup)
660 rely_on[l] = rely_on[l].union(dup)
661 t.final_objects = new
666 # add back in any objects that were relied upon by the reduction rules
668 t = bld.name_to_obj(r, bld.env)
669 t.final_objects = t.final_objects.union(rely_on[r])
674 def calculate_final_deps(bld, tgt_list, loops):
675 '''calculate the final library and object dependencies'''
677 # start with the maximum possible list
678 t.final_libs = t.direct_libs.union(indirect_libs(bld, t, set(), loops))
679 t.final_objects = t.direct_objects.union(indirect_objects(bld, t, set(), loops))
682 # don't depend on ourselves
683 if t.sname in t.final_libs:
684 t.final_libs.remove(t.sname)
685 if t.sname in t.final_objects:
686 t.final_objects.remove(t.sname)
688 # handle any non-shared binaries
690 if t.samba_type == 'BINARY' and bld.NONSHARED_BINARY(t.sname):
691 # replace lib deps with objlist deps
692 for l in t.final_libs:
693 objname = l + '.objlist'
694 t2 = bld.name_to_obj(objname, bld.env)
696 Logs.error('ERROR: subsystem %s not found' % objname)
698 t.final_objects.add(objname)
699 t.final_objects = t.final_objects.union(extended_objects(bld, t2, set()))
702 # find any library loops
704 if t.samba_type in ['LIBRARY', 'PYTHON']:
705 for l in t.final_libs.copy():
706 t2 = bld.name_to_obj(l, bld.env)
707 if t.sname in t2.final_libs:
708 # we could break this in either direction. If one of the libraries
709 # has a version number, and will this be distributed publicly, then
710 # we should make it the lower level library in the DAG
711 debug('deps: removing library loop %s from %s', t.sname, t2.sname)
712 dependency_loop(loops, t, t2.sname)
713 t2.final_libs.remove(t.sname)
717 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
719 # we now need to make corrections for any library loops we broke up
720 # any target that depended on the target of the loop and doesn't
721 # depend on the source of the loop needs to get the loop source added
722 for type in ['BINARY','PYTHON','LIBRARY','BINARY']:
724 if t.samba_type != type: continue
726 if loop in t.final_libs:
727 diff = loops[loop].difference(t.final_libs)
732 # make sure we don't recreate the loop again!
733 for d in diff.copy():
734 t2 = bld.name_to_obj(d, bld.env)
735 if t2.samba_type == 'LIBRARY':
736 if t.sname in t2.final_libs:
737 debug('deps: removing expansion %s from %s', d, t.sname)
740 debug('deps: Expanded target %s by loop %s libraries (loop %s) %s', t.sname, loop,
742 t.final_libs = t.final_libs.union(diff)
744 # remove objects that are also available in linked libs
746 while reduce_objects(bld, tgt_list):
749 Logs.warn("WARNING: Unable to remove all inter-target object duplicates")
751 debug('deps: Object reduction took %u iterations', count)
753 # add in any syslib dependencies
755 if not t.samba_type in ['BINARY','PYTHON','LIBRARY']:
758 for d in t.final_objects:
759 t2 = bld.name_to_obj(d, bld.env)
760 syslibs = syslibs.union(t2.direct_syslibs)
761 # this adds the indirect syslibs as well, which may not be needed
762 # depending on the linker flags
763 for d in t.final_libs:
764 t2 = bld.name_to_obj(d, bld.env)
765 syslibs = syslibs.union(t2.direct_syslibs)
766 t.final_syslibs = syslibs
769 # find any unresolved library loops
770 lib_loop_error = False
772 if t.samba_type in ['LIBRARY', 'PYTHON']:
773 for l in t.final_libs.copy():
774 t2 = bld.name_to_obj(l, bld.env)
775 if t.sname in t2.final_libs:
776 Logs.error('ERROR: Unresolved library loop %s from %s' % (t.sname, t2.sname))
777 lib_loop_error = True
781 debug('deps: removed duplicate dependencies')
784 ######################################################################
785 # this provides a way to save our dependency calculations between runs
787 savedeps_inputs = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags', 'source']
788 savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags']
789 savedeps_outenv = ['INC_PATHS']
790 savedeps_envvars = ['NONSHARED_BINARIES', 'GLOBAL_DEPENDENCIES']
791 savedeps_caches = ['GLOBAL_DEPENDENCIES', 'TARGET_ALIAS', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
792 savedeps_files = ['buildtools/wafsamba/samba_deps.py']
794 def save_samba_deps(bld, tgt_list):
795 '''save the dependency calculations between builds, to make
796 further builds faster'''
797 denv = Environment.Environment()
799 denv.version = savedeps_version
800 denv.savedeps_inputs = savedeps_inputs
801 denv.savedeps_outputs = savedeps_outputs
809 for f in savedeps_files:
810 denv.files[f] = os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime
812 for c in savedeps_caches:
813 denv.caches[c] = LOCAL_CACHE(bld, c)
815 for e in savedeps_envvars:
816 denv.envvar[e] = bld.env[e]
819 # save all the input attributes for each target
821 for attr in savedeps_inputs:
822 v = getattr(t, attr, None)
826 denv.input[t.sname] = tdeps
828 # save all the output attributes for each target
830 for attr in savedeps_outputs:
831 v = getattr(t, attr, None)
835 denv.output[t.sname] = tdeps
838 for attr in savedeps_outenv:
840 tdeps[attr] = t.env[attr]
842 denv.outenv[t.sname] = tdeps
844 depsfile = os.path.join(bld.bdir, "sambadeps")
849 def load_samba_deps(bld, tgt_list):
850 '''load a previous set of build dependencies if possible'''
851 depsfile = os.path.join(bld.bdir, "sambadeps")
852 denv = Environment.Environment()
854 debug('deps: checking saved dependencies')
856 if (denv.version != savedeps_version or
857 denv.savedeps_inputs != savedeps_inputs or
858 denv.savedeps_outputs != savedeps_outputs):
863 # check if critical files have changed
864 for f in savedeps_files:
865 if f not in denv.files:
867 if denv.files[f] != os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime:
870 # check if caches are the same
871 for c in savedeps_caches:
872 if c not in denv.caches or denv.caches[c] != LOCAL_CACHE(bld, c):
875 # check if caches are the same
876 for e in savedeps_envvars:
877 if e not in denv.envvar or denv.envvar[e] != bld.env[e]:
880 # check inputs are the same
883 for attr in savedeps_inputs:
884 v = getattr(t, attr, None)
887 if t.sname in denv.input:
888 olddeps = denv.input[t.sname]
892 #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
895 # put outputs in place
897 if not t.sname in denv.output: continue
898 tdeps = denv.output[t.sname]
900 setattr(t, a, tdeps[a])
902 # put output env vars in place
904 if not t.sname in denv.outenv: continue
905 tdeps = denv.outenv[t.sname]
909 debug('deps: loaded saved dependencies')
914 def check_project_rules(bld):
915 '''check the project rules - ensuring the targets are sane'''
917 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
921 # build a list of task generators we are interested in
925 if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON']:
927 t = bld.name_to_obj(tgt, bld.env)
929 Logs.error("Target %s of type %s has no task generator" % (tgt, type))
933 add_samba_attributes(bld, tgt_list)
935 if load_samba_deps(bld, tgt_list):
938 Logs.info("Checking project rules ...")
940 debug('deps: project rules checking started')
942 expand_subsystem_deps(bld)
943 build_direct_deps(bld, tgt_list)
944 break_dependency_loops(bld, tgt_list)
945 calculate_final_deps(bld, tgt_list, loops)
947 # run the various attribute generators
948 for f in [ build_dependencies, build_includes, add_init_functions ]:
949 debug('deps: project rules checking %s', f)
950 for t in tgt_list: f(t)
952 debug('deps: project rules stage1 completed')
954 #check_orpaned_targets(bld, tgt_list)
956 if not check_duplicate_sources(bld, tgt_list):
957 Logs.error("Duplicate sources present - aborting")
960 if not check_group_ordering(bld, tgt_list):
961 Logs.error("Bad group ordering - aborting")
964 show_final_deps(bld, tgt_list)
966 debug('deps: project rules checking completed - %u targets checked',
969 save_samba_deps(bld, tgt_list)
971 Logs.info("Project rules pass")
974 def CHECK_PROJECT_RULES(bld):
975 '''enable checking of project targets for sanity'''
976 if bld.env.added_project_rules:
978 bld.env.added_project_rules = True
979 bld.add_pre_fun(check_project_rules)
980 Build.BuildContext.CHECK_PROJECT_RULES = CHECK_PROJECT_RULES