1 # Samba automatic dependency handling and project rules
3 import Build, os, re, Environment, Logs
4 from samba_utils import *
5 from samba_autoconf import *
6 from samba_bundled import BUILTIN_LIBRARY
9 def ADD_GLOBAL_DEPENDENCY(ctx, dep):
10 '''add a dependency for all binaries and libraries'''
11 if not 'GLOBAL_DEPENDENCIES' in ctx.env:
12 ctx.env.GLOBAL_DEPENDENCIES = []
13 ctx.env.GLOBAL_DEPENDENCIES.append(dep)
17 def BREAK_CIRCULAR_LIBRARY_DEPENDENCIES(ctx):
18 '''indicate that circular dependencies between libraries should be broken.'''
19 ctx.env.ALLOW_CIRCULAR_LIB_DEPENDENCIES = True
22 def TARGET_ALIAS(bld, target, alias):
23 '''define an alias for a target name'''
24 cache = LOCAL_CACHE(bld, 'TARGET_ALIAS')
26 Logs.error("Target alias %s already set to %s : newalias %s" % (alias, cache[alias], target))
29 Build.BuildContext.TARGET_ALIAS = TARGET_ALIAS
33 def SET_SYSLIB_DEPS(conf, target, deps):
34 '''setup some implied dependencies for a SYSLIB'''
35 cache = LOCAL_CACHE(conf, 'SYSLIB_DEPS')
39 def EXPAND_ALIAS(bld, target):
40 '''expand a target name via an alias'''
41 aliases = LOCAL_CACHE(bld, 'TARGET_ALIAS')
43 return aliases[target]
45 Build.BuildContext.EXPAND_ALIAS = EXPAND_ALIAS
48 def expand_subsystem_deps(bld):
49 '''expand the reverse dependencies resulting from subsystem
50 attributes of modules'''
51 subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
52 aliases = LOCAL_CACHE(bld, 'TARGET_ALIAS')
53 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
58 bld.ASSERT(s in targets, "Subsystem target %s not declared" % s)
60 if type == 'DISABLED' or type == 'EMPTY':
63 t = bld.name_to_obj(s, bld.env)
64 for d in subsystems[s]:
65 type = targets[d['TARGET']]
66 if type != 'DISABLED' and type != 'EMPTY':
67 bld.ASSERT(t is not None,
68 "Subsystem target %s for %s (%s) not found" % (s, d['TARGET'], type))
69 t.samba_deps_extended.append(d['TARGET'])
70 t2 = bld.name_to_obj(d['TARGET'], bld.env)
71 t2.samba_includes_extended.extend(t.samba_includes_extended)
72 t2.samba_deps_extended.extend(t.samba_deps_extended)
73 t.samba_deps_extended = unique_list(t.samba_deps_extended)
77 def build_dependencies(self):
78 '''This builds the dependency list for a target. It runs after all the targets are declared
80 The reason this is not just done in the SAMBA_*() rules is that we have no way of knowing
81 the full dependency list for a target until we have all of the targets declared.
84 if self.samba_type in ['LIBRARY', 'BINARY', 'PYTHON']:
85 self.uselib = list(self.final_syslibs)
86 self.uselib_local = list(self.final_libs)
87 self.add_objects = list(self.final_objects)
89 # extra link flags from pkg_config
90 libs = self.final_syslibs.copy()
92 (ccflags, ldflags) = library_flags(self, list(libs))
93 new_ldflags = getattr(self, 'ldflags', [])
94 new_ldflags.extend(ldflags)
95 self.ldflags = new_ldflags
97 debug('deps: computed dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
98 self.sname, self.uselib, self.uselib_local, self.add_objects)
100 if self.samba_type in ['SUBSYSTEM']:
101 # this is needed for the ccflags of libs that come from pkg_config
102 self.uselib = list(self.direct_syslibs)
104 if getattr(self, 'uselib', None):
106 for l in self.uselib:
107 up_list.append(l.upper())
108 self.uselib = up_list
110 def build_includes(self):
111 '''This builds the right set of includes for a target.
113 One tricky part of this is that the includes= attribute for a
114 target needs to use paths which are relative to that targets
115 declaration directory (which we can get at via t.path).
117 The way this works is the includes list gets added as
118 samba_includes in the main build task declaration. Then this
119 function runs after all of the tasks are declared, and it
120 processes the samba_includes attribute to produce a includes=
124 if getattr(self, 'samba_includes', None) is None:
129 inc_deps = includes_objects(bld, self, set(), {})
133 # maybe add local includes
134 if getattr(self, 'local_include', True) == True and getattr(self, 'local_include_first', True):
137 includes.extend(self.samba_includes_extended)
139 if 'EXTRA_INCLUDES' in bld.env:
140 includes.extend(bld.env['EXTRA_INCLUDES'])
148 t = bld.name_to_obj(d, bld.env)
149 bld.ASSERT(t is not None, "Unable to find dependency %s for %s" % (d, self.sname))
150 inclist = getattr(t, 'samba_includes_extended', [])
151 if getattr(t, 'local_include', True) == True:
155 tpath = t.samba_abspath
157 npath = tpath + '/' + inc
158 if not npath in inc_set:
159 inc_abs.append(npath)
162 mypath = self.path.abspath(bld.env)
164 relpath = os_path_relpath(inc, mypath)
165 includes.append(relpath)
167 if getattr(self, 'local_include', True) == True and not getattr(self, 'local_include_first', True):
170 # now transform the includes list to be relative to the top directory
171 # which is represented by '#' in waf. This allows waf to cache the
172 # includes lists more efficiently
176 # some are already top based
177 includes_top.append(i)
179 absinc = os.path.join(self.path.abspath(), i)
180 relinc = os_path_relpath(absinc, self.bld.srcnode.abspath())
181 includes_top.append('#' + relinc)
183 self.includes = unique_list(includes_top)
184 debug('deps: includes for target %s: includes=%s',
185 self.sname, self.includes)
190 def add_init_functions(self):
191 '''This builds the right set of init functions'''
195 subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
197 # cope with the separated object lists from BINARY and LIBRARY targets
199 if sname.endswith('.objlist'):
203 if sname in subsystems:
204 modules.append(sname)
206 m = getattr(self, 'samba_modules', None)
208 modules.extend(TO_LIST(m))
210 m = getattr(self, 'samba_subsystem', None)
217 sentinal = getattr(self, 'init_function_sentinal', 'NULL')
219 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
221 cflags = getattr(self, 'samba_cflags', [])[:]
223 bld.ASSERT(m in subsystems,
224 "No init_function defined for module '%s' in target '%s'" % (m, self.sname))
226 for d in subsystems[m]:
227 if targets[d['TARGET']] != 'DISABLED':
228 init_fn_list.append(d['INIT_FUNCTION'])
229 if init_fn_list == []:
230 cflags.append('-DSTATIC_%s_MODULES=%s' % (m, sentinal))
232 cflags.append('-DSTATIC_%s_MODULES=%s' % (m, ','.join(init_fn_list) + ',' + sentinal))
233 self.ccflags = cflags
237 def check_duplicate_sources(bld, tgt_list):
238 '''see if we are compiling the same source file into multiple
239 subsystem targets for the same library or binary'''
241 debug('deps: checking for duplicate sources')
243 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
249 obj_sources = getattr(t, 'source', '')
250 tpath = os.path.normpath(os_path_relpath(t.path.abspath(bld.env), t.env.BUILD_DIRECTORY + '/default'))
251 obj_sources = bld.SUBDIR(tpath, obj_sources)
252 t.samba_source_set = set(TO_LIST(obj_sources))
255 if not targets[t.sname] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
259 for obj in t.add_objects:
260 t2 = t.bld.name_to_obj(obj, bld.env)
261 source_set = getattr(t2, 'samba_source_set', set())
262 sources.append( { 'dep':obj, 'src':source_set} )
265 if s['dep'] == s2['dep']: continue
266 common = s['src'].intersection(s2['src'])
267 if common.difference(seen):
268 Logs.error("Target %s has duplicate source files in %s and %s : %s" % (t.sname,
271 seen = seen.union(common)
276 def check_orpaned_targets(bld, tgt_list):
277 '''check if any build targets are orphaned'''
279 target_dict = LOCAL_CACHE(bld, 'TARGET_TYPE')
281 debug('deps: checking for orphaned targets')
284 if getattr(t, 'samba_used', False) == True:
286 type = target_dict[t.sname]
287 if not type in ['BINARY', 'LIBRARY', 'MODULE', 'ET', 'PYTHON']:
288 if re.search('^PIDL_', t.sname) is None:
289 Logs.warn("Target %s of type %s is unused by any other target" % (t.sname, type))
292 def check_group_ordering(bld, tgt_list):
293 '''see if we have any dependencies that violate the group ordering
295 It is an error for a target to depend on a target from a later
300 tm = bld.task_manager
301 return [x for x in tm.groups_names if id(tm.groups_names[x]) == id(g)][0]
303 for g in bld.task_manager.groups:
304 gname = group_name(g)
305 for t in g.tasks_gen:
306 t.samba_group = gname
310 for g in bld.task_manager.groups:
315 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
319 tdeps = getattr(t, 'add_objects', []) + getattr(t, 'uselib_local', [])
321 t2 = bld.name_to_obj(d, bld.env)
324 map1 = grp_map[t.samba_group]
325 map2 = grp_map[t2.samba_group]
328 Logs.error("Target %r in build group %r depends on target %r from later build group %r" % (
329 t.sname, t.samba_group, t2.sname, t2.samba_group))
335 def show_final_deps(bld, tgt_list):
336 '''show the final dependencies for all targets'''
338 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
341 if not targets[t.sname] in ['LIBRARY', 'BINARY', 'PYTHON']:
343 debug('deps: final dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
344 t.sname, t.uselib, t.uselib_local, t.add_objects)
347 def add_samba_attributes(bld, tgt_list):
348 '''ensure a target has a the required samba attributes'''
350 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
357 t.samba_type = targets[t.sname]
358 t.samba_abspath = t.path.abspath(bld.env)
359 t.samba_deps_extended = t.samba_deps[:]
360 t.samba_includes_extended = TO_LIST(t.samba_includes)[:]
361 t.ccflags = getattr(t, 'samba_cflags', '')
364 def build_direct_deps(bld, tgt_list):
365 '''build the direct_objects and direct_libs sets for each target'''
367 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
368 syslib_deps = LOCAL_CACHE(bld, 'SYSLIB_DEPS')
369 global_deps = bld.env.GLOBAL_DEPENDENCIES
372 t.direct_objects = set()
373 t.direct_libs = set()
374 t.direct_syslibs = set()
375 deps = t.samba_deps_extended
376 if getattr(t, 'samba_use_global_deps', False):
377 deps.extend(global_deps)
379 d = EXPAND_ALIAS(bld, d)
380 if d == t.sname: continue
382 Logs.error("Unknown dependency %s in %s" % (d, t.sname))
384 if targets[d] in [ 'EMPTY', 'DISABLED' ]:
386 if targets[d] == 'SYSLIB':
387 t.direct_syslibs.add(d)
389 for implied in TO_LIST(syslib_deps[d]):
390 if BUILTIN_LIBRARY(bld, implied):
391 t.direct_objects.add(implied)
392 elif targets[implied] == 'SYSLIB':
393 t.direct_syslibs.add(implied)
394 elif targets[implied] in ['LIBRARY', 'MODULE']:
395 t.direct_libs.add(implied)
397 Logs.error('Implied dependency %s in %s is of type %s' % (
398 implied, t.sname, targets[implied]))
401 t2 = bld.name_to_obj(d, bld.env)
403 Logs.error("no task %s of type %s in %s" % (d, targets[d], t.sname))
405 if t2.samba_type in [ 'LIBRARY', 'MODULE' ]:
407 elif t2.samba_type in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]:
408 t.direct_objects.add(d)
409 debug('deps: built direct dependencies')
412 def dependency_loop(loops, t, target):
413 '''add a dependency loop to the loops dictionary'''
414 if t.sname == target:
416 if not target in loops:
417 loops[target] = set()
418 if not t.sname in loops[target]:
419 loops[target].add(t.sname)
422 def indirect_libs(bld, t, chain, loops):
423 '''recursively calculate the indirect library dependencies for a target
425 An indirect library is a library that results from a dependency on
429 ret = getattr(t, 'indirect_libs', None)
434 for obj in t.direct_objects:
436 dependency_loop(loops, t, obj)
439 t2 = bld.name_to_obj(obj, bld.env)
440 r2 = indirect_libs(bld, t2, chain, loops)
442 ret = ret.union(t2.direct_libs)
445 for obj in indirect_objects(bld, t, set(), loops):
447 dependency_loop(loops, t, obj)
450 t2 = bld.name_to_obj(obj, bld.env)
451 r2 = indirect_libs(bld, t2, chain, loops)
453 ret = ret.union(t2.direct_libs)
456 t.indirect_libs = ret
461 def indirect_objects(bld, t, chain, loops):
462 '''recursively calculate the indirect object dependencies for a target
464 indirect objects are the set of objects from expanding the
465 subsystem dependencies
468 ret = getattr(t, 'indirect_objects', None)
469 if ret is not None: return ret
472 for lib in t.direct_objects:
474 dependency_loop(loops, t, lib)
477 t2 = bld.name_to_obj(lib, bld.env)
478 r2 = indirect_objects(bld, t2, chain, loops)
480 ret = ret.union(t2.direct_objects)
483 t.indirect_objects = ret
487 def extended_objects(bld, t, chain):
488 '''recursively calculate the extended object dependencies for a target
490 extended objects are the union of:
493 - direct and indirect objects of all direct and indirect libraries
496 ret = getattr(t, 'extended_objects', None)
497 if ret is not None: return ret
500 ret = ret.union(t.final_objects)
502 for lib in t.final_libs:
505 t2 = bld.name_to_obj(lib, bld.env)
507 r2 = extended_objects(bld, t2, chain)
509 ret = ret.union(t2.final_objects)
512 t.extended_objects = ret
516 def includes_objects(bld, t, chain, inc_loops):
517 '''recursively calculate the includes object dependencies for a target
519 includes dependencies come from either library or object dependencies
521 ret = getattr(t, 'includes_objects', None)
525 ret = t.direct_objects.copy()
526 ret = ret.union(t.direct_libs)
528 for obj in t.direct_objects:
530 dependency_loop(inc_loops, t, obj)
533 t2 = bld.name_to_obj(obj, bld.env)
534 r2 = includes_objects(bld, t2, chain, inc_loops)
536 ret = ret.union(t2.direct_objects)
539 for lib in t.direct_libs:
541 dependency_loop(inc_loops, t, lib)
544 t2 = bld.name_to_obj(lib, bld.env)
546 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
547 Logs.error('Target %s of type %s not found in direct_libs for %s' % (
548 lib, targets[lib], t.sname))
550 r2 = includes_objects(bld, t2, chain, inc_loops)
552 ret = ret.union(t2.direct_objects)
555 t.includes_objects = ret
559 def break_dependency_loops(bld, tgt_list):
560 '''find and break dependency loops'''
564 # build up the list of loops
566 indirect_objects(bld, t, set(), loops)
567 indirect_libs(bld, t, set(), loops)
568 includes_objects(bld, t, set(), inc_loops)
573 for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
574 objs = getattr(t, attr, set())
575 setattr(t, attr, objs.difference(loops[t.sname]))
578 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
580 for loop in inc_loops:
581 debug('deps: Found include loops for target %s : %s', loop, inc_loops[loop])
583 # expand the loops mapping by one level
584 for loop in loops.copy():
585 for tgt in loops[loop]:
587 loops[loop] = loops[loop].union(loops[tgt])
589 for loop in inc_loops.copy():
590 for tgt in inc_loops[loop]:
592 inc_loops[loop] = inc_loops[loop].union(inc_loops[tgt])
595 # expand indirect subsystem and library loops
596 for loop in loops.copy():
597 t = bld.name_to_obj(loop, bld.env)
598 if t.samba_type in ['SUBSYSTEM']:
599 loops[loop] = loops[loop].union(t.indirect_objects)
600 loops[loop] = loops[loop].union(t.direct_objects)
601 if t.samba_type in ['LIBRARY','PYTHON']:
602 loops[loop] = loops[loop].union(t.indirect_libs)
603 loops[loop] = loops[loop].union(t.direct_libs)
604 if loop in loops[loop]:
605 loops[loop].remove(loop)
607 # expand indirect includes loops
608 for loop in inc_loops.copy():
609 t = bld.name_to_obj(loop, bld.env)
610 inc_loops[loop] = inc_loops[loop].union(t.includes_objects)
611 if loop in inc_loops[loop]:
612 inc_loops[loop].remove(loop)
614 # add in the replacement dependencies
617 for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
618 objs = getattr(t, attr, set())
620 diff = loops[loop].difference(objs)
624 debug('deps: Expanded target %s of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
625 objs = objs.union(diff)
626 setattr(t, attr, objs)
628 for loop in inc_loops:
629 objs = getattr(t, 'includes_objects', set())
631 diff = inc_loops[loop].difference(objs)
635 debug('deps: Expanded target %s includes of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
636 objs = objs.union(diff)
637 setattr(t, 'includes_objects', objs)
640 def reduce_objects(bld, tgt_list):
641 '''reduce objects by looking for indirect object dependencies'''
645 t.extended_objects = None
649 for type in ['BINARY', 'PYTHON', 'LIBRARY']:
651 if t.samba_type != type: continue
652 # if we will indirectly link to a target then we don't need it
653 new = t.final_objects.copy()
654 for l in t.final_libs:
655 t2 = bld.name_to_obj(l, bld.env)
656 t2_obj = extended_objects(bld, t2, set())
657 dup = new.intersection(t2_obj)
658 if t.sname in rely_on:
659 dup = dup.difference(rely_on[t.sname])
661 debug('deps: removing dups from %s of type %s: %s also in %s %s',
662 t.sname, t.samba_type, dup, t2.samba_type, l)
663 new = new.difference(dup)
667 rely_on[l] = rely_on[l].union(dup)
668 t.final_objects = new
673 # add back in any objects that were relied upon by the reduction rules
675 t = bld.name_to_obj(r, bld.env)
676 t.final_objects = t.final_objects.union(rely_on[r])
681 def calculate_final_deps(bld, tgt_list, loops):
682 '''calculate the final library and object dependencies'''
684 # start with the maximum possible list
685 t.final_libs = t.direct_libs.union(indirect_libs(bld, t, set(), loops))
686 t.final_objects = t.direct_objects.union(indirect_objects(bld, t, set(), loops))
689 # don't depend on ourselves
690 if t.sname in t.final_libs:
691 t.final_libs.remove(t.sname)
692 if t.sname in t.final_objects:
693 t.final_objects.remove(t.sname)
695 # handle any non-shared binaries
697 if t.samba_type == 'BINARY' and bld.NONSHARED_BINARY(t.sname):
698 # replace lib deps with objlist deps
699 for l in t.final_libs:
700 objname = l + '.objlist'
701 t2 = bld.name_to_obj(objname, bld.env)
703 Logs.error('ERROR: subsystem %s not found' % objname)
705 t.final_objects.add(objname)
706 t.final_objects = t.final_objects.union(extended_objects(bld, t2, set()))
709 # find any library loops
711 if t.samba_type in ['LIBRARY', 'PYTHON']:
712 for l in t.final_libs.copy():
713 t2 = bld.name_to_obj(l, bld.env)
714 if t.sname in t2.final_libs:
715 if getattr(bld.env, "ALLOW_CIRCULAR_LIB_DEPENDENCIES", False):
716 # we could break this in either direction. If one of the libraries
717 # has a version number, and will this be distributed publicly, then
718 # we should make it the lower level library in the DAG
719 Logs.warn('deps: removing library loop %s from %s' % (t.sname, t2.sname))
720 dependency_loop(loops, t, t2.sname)
721 t2.final_libs.remove(t.sname)
723 Logs.error('ERROR: circular library dependency between %s and %s'
724 % (t.sname, t2.sname))
728 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
730 # we now need to make corrections for any library loops we broke up
731 # any target that depended on the target of the loop and doesn't
732 # depend on the source of the loop needs to get the loop source added
733 for type in ['BINARY','PYTHON','LIBRARY','BINARY']:
735 if t.samba_type != type: continue
737 if loop in t.final_libs:
738 diff = loops[loop].difference(t.final_libs)
743 # make sure we don't recreate the loop again!
744 for d in diff.copy():
745 t2 = bld.name_to_obj(d, bld.env)
746 if t2.samba_type == 'LIBRARY':
747 if t.sname in t2.final_libs:
748 debug('deps: removing expansion %s from %s', d, t.sname)
751 debug('deps: Expanded target %s by loop %s libraries (loop %s) %s', t.sname, loop,
753 t.final_libs = t.final_libs.union(diff)
755 # remove objects that are also available in linked libs
757 while reduce_objects(bld, tgt_list):
760 Logs.warn("WARNING: Unable to remove all inter-target object duplicates")
762 debug('deps: Object reduction took %u iterations', count)
764 # add in any syslib dependencies
766 if not t.samba_type in ['BINARY','PYTHON','LIBRARY']:
769 for d in t.final_objects:
770 t2 = bld.name_to_obj(d, bld.env)
771 syslibs = syslibs.union(t2.direct_syslibs)
772 # this adds the indirect syslibs as well, which may not be needed
773 # depending on the linker flags
774 for d in t.final_libs:
775 t2 = bld.name_to_obj(d, bld.env)
776 syslibs = syslibs.union(t2.direct_syslibs)
777 t.final_syslibs = syslibs
780 # find any unresolved library loops
781 lib_loop_error = False
783 if t.samba_type in ['LIBRARY', 'PYTHON']:
784 for l in t.final_libs.copy():
785 t2 = bld.name_to_obj(l, bld.env)
786 if t.sname in t2.final_libs:
787 Logs.error('ERROR: Unresolved library loop %s from %s' % (t.sname, t2.sname))
788 lib_loop_error = True
792 debug('deps: removed duplicate dependencies')
795 ######################################################################
796 # this provides a way to save our dependency calculations between runs
798 savedeps_inputs = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags', 'source']
799 savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags']
800 savedeps_outenv = ['INC_PATHS']
801 savedeps_envvars = ['NONSHARED_BINARIES', 'GLOBAL_DEPENDENCIES']
802 savedeps_caches = ['GLOBAL_DEPENDENCIES', 'TARGET_ALIAS', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
803 savedeps_files = ['buildtools/wafsamba/samba_deps.py']
805 def save_samba_deps(bld, tgt_list):
806 '''save the dependency calculations between builds, to make
807 further builds faster'''
808 denv = Environment.Environment()
810 denv.version = savedeps_version
811 denv.savedeps_inputs = savedeps_inputs
812 denv.savedeps_outputs = savedeps_outputs
820 for f in savedeps_files:
821 denv.files[f] = os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime
823 for c in savedeps_caches:
824 denv.caches[c] = LOCAL_CACHE(bld, c)
826 for e in savedeps_envvars:
827 denv.envvar[e] = bld.env[e]
830 # save all the input attributes for each target
832 for attr in savedeps_inputs:
833 v = getattr(t, attr, None)
837 denv.input[t.sname] = tdeps
839 # save all the output attributes for each target
841 for attr in savedeps_outputs:
842 v = getattr(t, attr, None)
846 denv.output[t.sname] = tdeps
849 for attr in savedeps_outenv:
851 tdeps[attr] = t.env[attr]
853 denv.outenv[t.sname] = tdeps
855 depsfile = os.path.join(bld.bdir, "sambadeps")
860 def load_samba_deps(bld, tgt_list):
861 '''load a previous set of build dependencies if possible'''
862 depsfile = os.path.join(bld.bdir, "sambadeps")
863 denv = Environment.Environment()
865 debug('deps: checking saved dependencies')
867 if (denv.version != savedeps_version or
868 denv.savedeps_inputs != savedeps_inputs or
869 denv.savedeps_outputs != savedeps_outputs):
874 # check if critical files have changed
875 for f in savedeps_files:
876 if f not in denv.files:
878 if denv.files[f] != os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime:
881 # check if caches are the same
882 for c in savedeps_caches:
883 if c not in denv.caches or denv.caches[c] != LOCAL_CACHE(bld, c):
886 # check if caches are the same
887 for e in savedeps_envvars:
888 if e not in denv.envvar or denv.envvar[e] != bld.env[e]:
891 # check inputs are the same
894 for attr in savedeps_inputs:
895 v = getattr(t, attr, None)
898 if t.sname in denv.input:
899 olddeps = denv.input[t.sname]
903 #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
906 # put outputs in place
908 if not t.sname in denv.output: continue
909 tdeps = denv.output[t.sname]
911 setattr(t, a, tdeps[a])
913 # put output env vars in place
915 if not t.sname in denv.outenv: continue
916 tdeps = denv.outenv[t.sname]
920 debug('deps: loaded saved dependencies')
925 def check_project_rules(bld):
926 '''check the project rules - ensuring the targets are sane'''
928 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
932 # build a list of task generators we are interested in
936 if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON']:
938 t = bld.name_to_obj(tgt, bld.env)
940 Logs.error("Target %s of type %s has no task generator" % (tgt, type))
944 add_samba_attributes(bld, tgt_list)
946 if load_samba_deps(bld, tgt_list):
949 Logs.info("Checking project rules ...")
951 debug('deps: project rules checking started')
953 expand_subsystem_deps(bld)
954 build_direct_deps(bld, tgt_list)
955 break_dependency_loops(bld, tgt_list)
956 calculate_final_deps(bld, tgt_list, loops)
958 # run the various attribute generators
959 for f in [ build_dependencies, build_includes, add_init_functions ]:
960 debug('deps: project rules checking %s', f)
961 for t in tgt_list: f(t)
963 debug('deps: project rules stage1 completed')
965 #check_orpaned_targets(bld, tgt_list)
967 if not check_duplicate_sources(bld, tgt_list):
968 Logs.error("Duplicate sources present - aborting")
971 if not check_group_ordering(bld, tgt_list):
972 Logs.error("Bad group ordering - aborting")
975 show_final_deps(bld, tgt_list)
977 debug('deps: project rules checking completed - %u targets checked',
980 save_samba_deps(bld, tgt_list)
982 Logs.info("Project rules pass")
985 def CHECK_PROJECT_RULES(bld):
986 '''enable checking of project targets for sanity'''
987 if bld.env.added_project_rules:
989 bld.env.added_project_rules = True
990 bld.add_pre_fun(check_project_rules)
991 Build.BuildContext.CHECK_PROJECT_RULES = CHECK_PROJECT_RULES