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 def show_dependencies(bld, target, seen):
796 '''recursively show the dependencies of target'''
801 t = bld.name_to_obj(target, bld.env)
803 Logs.error("ERROR: Unable to find target '%s'" % target)
806 Logs.info('%s(OBJECTS): %s' % (target, t.direct_objects))
807 Logs.info('%s(LIBS): %s' % (target, t.direct_libs))
808 Logs.info('%s(SYSLIBS): %s' % (target, t.direct_syslibs))
812 for t2 in t.direct_objects:
813 show_dependencies(bld, t2, seen)
816 def show_object_duplicates(bld, tgt_list):
817 '''show a list of object files that are included in more than
818 one library or binary'''
820 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
824 Logs.info("showing duplicate objects")
827 if not targets[t.sname] in [ 'LIBRARY' ]:
829 for n in getattr(t, 'final_objects', set()):
830 t2 = bld.name_to_obj(n, bld.env)
833 used_by[n].add(t.sname)
836 if len(used_by[n]) > 1:
837 Logs.info("target '%s' is used by %s" % (n, used_by[n]))
839 Logs.info("showing indirect dependency counts (sorted by count)")
841 def indirect_count(t1, t2):
842 return len(t2.indirect_objects) - len(t1.indirect_objects)
844 sorted_list = sorted(tgt_list, cmp=indirect_count)
845 for t in sorted_list:
846 if len(t.indirect_objects) > 1:
847 Logs.info("%s depends on %u indirect objects" % (t.sname, len(t.indirect_objects)))
850 ######################################################################
851 # this provides a way to save our dependency calculations between runs
853 savedeps_inputs = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags', 'source']
854 savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags']
855 savedeps_outenv = ['INC_PATHS']
856 savedeps_envvars = ['NONSHARED_BINARIES', 'GLOBAL_DEPENDENCIES']
857 savedeps_caches = ['GLOBAL_DEPENDENCIES', 'TARGET_ALIAS', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
858 savedeps_files = ['buildtools/wafsamba/samba_deps.py']
860 def save_samba_deps(bld, tgt_list):
861 '''save the dependency calculations between builds, to make
862 further builds faster'''
863 denv = Environment.Environment()
865 denv.version = savedeps_version
866 denv.savedeps_inputs = savedeps_inputs
867 denv.savedeps_outputs = savedeps_outputs
875 for f in savedeps_files:
876 denv.files[f] = os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime
878 for c in savedeps_caches:
879 denv.caches[c] = LOCAL_CACHE(bld, c)
881 for e in savedeps_envvars:
882 denv.envvar[e] = bld.env[e]
885 # save all the input attributes for each target
887 for attr in savedeps_inputs:
888 v = getattr(t, attr, None)
892 denv.input[t.sname] = tdeps
894 # save all the output attributes for each target
896 for attr in savedeps_outputs:
897 v = getattr(t, attr, None)
901 denv.output[t.sname] = tdeps
904 for attr in savedeps_outenv:
906 tdeps[attr] = t.env[attr]
908 denv.outenv[t.sname] = tdeps
910 depsfile = os.path.join(bld.bdir, "sambadeps")
915 def load_samba_deps(bld, tgt_list):
916 '''load a previous set of build dependencies if possible'''
917 depsfile = os.path.join(bld.bdir, "sambadeps")
918 denv = Environment.Environment()
920 debug('deps: checking saved dependencies')
922 if (denv.version != savedeps_version or
923 denv.savedeps_inputs != savedeps_inputs or
924 denv.savedeps_outputs != savedeps_outputs):
929 # check if critical files have changed
930 for f in savedeps_files:
931 if f not in denv.files:
933 if denv.files[f] != os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime:
936 # check if caches are the same
937 for c in savedeps_caches:
938 if c not in denv.caches or denv.caches[c] != LOCAL_CACHE(bld, c):
941 # check if caches are the same
942 for e in savedeps_envvars:
943 if e not in denv.envvar or denv.envvar[e] != bld.env[e]:
946 # check inputs are the same
949 for attr in savedeps_inputs:
950 v = getattr(t, attr, None)
953 if t.sname in denv.input:
954 olddeps = denv.input[t.sname]
958 #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
961 # put outputs in place
963 if not t.sname in denv.output: continue
964 tdeps = denv.output[t.sname]
966 setattr(t, a, tdeps[a])
968 # put output env vars in place
970 if not t.sname in denv.outenv: continue
971 tdeps = denv.outenv[t.sname]
975 debug('deps: loaded saved dependencies')
980 def check_project_rules(bld):
981 '''check the project rules - ensuring the targets are sane'''
983 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
987 # build a list of task generators we are interested in
991 if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON']:
993 t = bld.name_to_obj(tgt, bld.env)
995 Logs.error("Target %s of type %s has no task generator" % (tgt, type))
999 add_samba_attributes(bld, tgt_list)
1001 force_project_rules = (Options.options.SHOWDEPS or
1002 Options.options.SHOW_DUPLICATES)
1004 if not force_project_rules and load_samba_deps(bld, tgt_list):
1007 bld.new_rules = True
1008 Logs.info("Checking project rules ...")
1010 debug('deps: project rules checking started')
1012 expand_subsystem_deps(bld)
1013 build_direct_deps(bld, tgt_list)
1015 break_dependency_loops(bld, tgt_list)
1016 calculate_final_deps(bld, tgt_list, loops)
1018 if Options.options.SHOWDEPS:
1019 show_dependencies(bld, Options.options.SHOWDEPS, set())
1021 if Options.options.SHOW_DUPLICATES:
1022 show_object_duplicates(bld, tgt_list)
1024 # run the various attribute generators
1025 for f in [ build_dependencies, build_includes, add_init_functions ]:
1026 debug('deps: project rules checking %s', f)
1027 for t in tgt_list: f(t)
1029 debug('deps: project rules stage1 completed')
1031 #check_orpaned_targets(bld, tgt_list)
1033 if not check_duplicate_sources(bld, tgt_list):
1034 Logs.error("Duplicate sources present - aborting")
1037 if not check_group_ordering(bld, tgt_list):
1038 Logs.error("Bad group ordering - aborting")
1041 show_final_deps(bld, tgt_list)
1043 debug('deps: project rules checking completed - %u targets checked',
1046 if not bld.is_install:
1047 save_samba_deps(bld, tgt_list)
1049 Logs.info("Project rules pass")
1052 def CHECK_PROJECT_RULES(bld):
1053 '''enable checking of project targets for sanity'''
1054 if bld.env.added_project_rules:
1056 bld.env.added_project_rules = True
1057 bld.add_pre_fun(check_project_rules)
1058 Build.BuildContext.CHECK_PROJECT_RULES = CHECK_PROJECT_RULES