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. This is walking over the complete list
51 of declared subsystems, and expands the samba_deps_extended list for any
52 module<->subsystem dependencies'''
54 subsystem_list = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
55 aliases = LOCAL_CACHE(bld, 'TARGET_ALIAS')
56 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
58 for subsystem_name in subsystem_list:
59 if subsystem_name in aliases:
60 subsystem_name = aliases[subsystem_name]
61 bld.ASSERT(subsystem_name in targets, "Subsystem target %s not declared" % subsystem_name)
62 type = targets[subsystem_name]
63 if type == 'DISABLED' or type == 'EMPTY':
67 # subsystem_name = dcerpc_server (a subsystem)
68 # subsystem = dcerpc_server (a subsystem object)
69 # module_name = rpc_epmapper (a module within the dcerpc_server subsystem)
70 # module = rpc_epmapper (a module object within the dcerpc_server subsystem)
72 subsystem = bld.name_to_obj(subsystem_name, bld.env)
73 for d in subsystem_list[subsystem_name]:
74 module_name = d['TARGET']
75 module_type = targets[module_name]
76 if module_type in ['DISABLED', 'EMPTY']:
78 bld.ASSERT(subsystem is not None,
79 "Subsystem target %s for %s (%s) not found" % (subsystem_name, module_name, module_type))
80 if module_type in ['SUBSYSTEM']:
81 # if a module is a plain object type (not a library) then the
82 # subsystem it is part of needs to have it as a dependency, so targets
83 # that depend on this subsystem get the modules of that subsystem
84 subsystem.samba_deps_extended.append(module_name)
85 module = bld.name_to_obj(module_name, bld.env)
86 module.samba_includes_extended.extend(subsystem.samba_includes_extended)
87 if targets[subsystem_name] in ['SUBSYSTEM']:
88 # if a subsystem is a plain object type (not a library) then any modules
89 # in that subsystem need to depend on the subsystem
90 module.samba_deps_extended.extend(subsystem.samba_deps_extended)
91 subsystem.samba_deps_extended = unique_list(subsystem.samba_deps_extended)
95 def build_dependencies(self):
96 '''This builds the dependency list for a target. It runs after all the targets are declared
98 The reason this is not just done in the SAMBA_*() rules is that we have no way of knowing
99 the full dependency list for a target until we have all of the targets declared.
102 if self.samba_type in ['LIBRARY', 'BINARY', 'PYTHON']:
103 self.uselib = list(self.final_syslibs)
104 self.uselib_local = list(self.final_libs)
105 self.add_objects = list(self.final_objects)
107 # extra link flags from pkg_config
108 libs = self.final_syslibs.copy()
110 (ccflags, ldflags) = library_flags(self, list(libs))
111 new_ldflags = getattr(self, 'ldflags', [])
112 new_ldflags.extend(ldflags)
113 self.ldflags = new_ldflags
115 debug('deps: computed dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
116 self.sname, self.uselib, self.uselib_local, self.add_objects)
118 if self.samba_type in ['SUBSYSTEM']:
119 # this is needed for the ccflags of libs that come from pkg_config
120 self.uselib = list(self.direct_syslibs)
122 if getattr(self, 'uselib', None):
124 for l in self.uselib:
125 up_list.append(l.upper())
126 self.uselib = up_list
128 def build_includes(self):
129 '''This builds the right set of includes for a target.
131 One tricky part of this is that the includes= attribute for a
132 target needs to use paths which are relative to that targets
133 declaration directory (which we can get at via t.path).
135 The way this works is the includes list gets added as
136 samba_includes in the main build task declaration. Then this
137 function runs after all of the tasks are declared, and it
138 processes the samba_includes attribute to produce a includes=
142 if getattr(self, 'samba_includes', None) is None:
147 inc_deps = includes_objects(bld, self, set(), {})
151 # maybe add local includes
152 if getattr(self, 'local_include', True) == True and getattr(self, 'local_include_first', True):
155 includes.extend(self.samba_includes_extended)
157 if 'EXTRA_INCLUDES' in bld.env:
158 includes.extend(bld.env['EXTRA_INCLUDES'])
166 t = bld.name_to_obj(d, bld.env)
167 bld.ASSERT(t is not None, "Unable to find dependency %s for %s" % (d, self.sname))
168 inclist = getattr(t, 'samba_includes_extended', [])
169 if getattr(t, 'local_include', True) == True:
173 tpath = t.samba_abspath
175 npath = tpath + '/' + inc
176 if not npath in inc_set:
177 inc_abs.append(npath)
180 mypath = self.path.abspath(bld.env)
182 relpath = os_path_relpath(inc, mypath)
183 includes.append(relpath)
185 if getattr(self, 'local_include', True) == True and not getattr(self, 'local_include_first', True):
188 # now transform the includes list to be relative to the top directory
189 # which is represented by '#' in waf. This allows waf to cache the
190 # includes lists more efficiently
194 # some are already top based
195 includes_top.append(i)
197 absinc = os.path.join(self.path.abspath(), i)
198 relinc = os_path_relpath(absinc, self.bld.srcnode.abspath())
199 includes_top.append('#' + relinc)
201 self.includes = unique_list(includes_top)
202 debug('deps: includes for target %s: includes=%s',
203 self.sname, self.includes)
208 def add_init_functions(self):
209 '''This builds the right set of init functions'''
213 subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
215 # cope with the separated object lists from BINARY and LIBRARY targets
217 if sname.endswith('.objlist'):
221 if sname in subsystems:
222 modules.append(sname)
224 m = getattr(self, 'samba_modules', None)
226 modules.extend(TO_LIST(m))
228 m = getattr(self, 'samba_subsystem', None)
235 sentinal = getattr(self, 'init_function_sentinal', 'NULL')
237 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
239 cflags = getattr(self, 'samba_cflags', [])[:]
241 bld.ASSERT(m in subsystems,
242 "No init_function defined for module '%s' in target '%s'" % (m, self.sname))
244 for d in subsystems[m]:
245 if targets[d['TARGET']] != 'DISABLED':
246 init_fn_list.append(d['INIT_FUNCTION'])
247 if init_fn_list == []:
248 cflags.append('-DSTATIC_%s_MODULES=%s' % (m, sentinal))
250 cflags.append('-DSTATIC_%s_MODULES=%s' % (m, ','.join(init_fn_list) + ',' + sentinal))
251 self.ccflags = cflags
255 def check_duplicate_sources(bld, tgt_list):
256 '''see if we are compiling the same source file into multiple
257 subsystem targets for the same library or binary'''
259 debug('deps: checking for duplicate sources')
261 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
267 obj_sources = getattr(t, 'source', '')
268 tpath = os.path.normpath(os_path_relpath(t.path.abspath(bld.env), t.env.BUILD_DIRECTORY + '/default'))
269 obj_sources = bld.SUBDIR(tpath, obj_sources)
270 t.samba_source_set = set(TO_LIST(obj_sources))
273 if not targets[t.sname] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
277 for obj in t.add_objects:
278 t2 = t.bld.name_to_obj(obj, bld.env)
279 source_set = getattr(t2, 'samba_source_set', set())
280 sources.append( { 'dep':obj, 'src':source_set} )
283 if s['dep'] == s2['dep']: continue
284 common = s['src'].intersection(s2['src'])
285 if common.difference(seen):
286 Logs.error("Target %s has duplicate source files in %s and %s : %s" % (t.sname,
289 seen = seen.union(common)
294 def check_orpaned_targets(bld, tgt_list):
295 '''check if any build targets are orphaned'''
297 target_dict = LOCAL_CACHE(bld, 'TARGET_TYPE')
299 debug('deps: checking for orphaned targets')
302 if getattr(t, 'samba_used', False) == True:
304 type = target_dict[t.sname]
305 if not type in ['BINARY', 'LIBRARY', 'MODULE', 'ET', 'PYTHON']:
306 if re.search('^PIDL_', t.sname) is None:
307 Logs.warn("Target %s of type %s is unused by any other target" % (t.sname, type))
310 def check_group_ordering(bld, tgt_list):
311 '''see if we have any dependencies that violate the group ordering
313 It is an error for a target to depend on a target from a later
318 tm = bld.task_manager
319 return [x for x in tm.groups_names if id(tm.groups_names[x]) == id(g)][0]
321 for g in bld.task_manager.groups:
322 gname = group_name(g)
323 for t in g.tasks_gen:
324 t.samba_group = gname
328 for g in bld.task_manager.groups:
333 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
337 tdeps = getattr(t, 'add_objects', []) + getattr(t, 'uselib_local', [])
339 t2 = bld.name_to_obj(d, bld.env)
342 map1 = grp_map[t.samba_group]
343 map2 = grp_map[t2.samba_group]
346 Logs.error("Target %r in build group %r depends on target %r from later build group %r" % (
347 t.sname, t.samba_group, t2.sname, t2.samba_group))
353 def show_final_deps(bld, tgt_list):
354 '''show the final dependencies for all targets'''
356 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
359 if not targets[t.sname] in ['LIBRARY', 'BINARY', 'PYTHON']:
361 debug('deps: final dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
362 t.sname, t.uselib, t.uselib_local, t.add_objects)
365 def add_samba_attributes(bld, tgt_list):
366 '''ensure a target has a the required samba attributes'''
368 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
375 t.samba_type = targets[t.sname]
376 t.samba_abspath = t.path.abspath(bld.env)
377 t.samba_deps_extended = t.samba_deps[:]
378 t.samba_includes_extended = TO_LIST(t.samba_includes)[:]
379 t.ccflags = getattr(t, 'samba_cflags', '')
381 def replace_grouping_libraries(bld, tgt_list):
382 '''replace dependencies based on grouping libraries
384 If a library is marked as a grouping library, then any target that
385 depends on a subsystem that is part of that grouping library gets
386 that dependency replaced with a dependency on the grouping library
389 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
393 # find our list of grouping libraries, mapped from the subsystems they depend on
395 if not getattr(t, 'grouping_library', False):
397 for dep in t.samba_deps_extended:
398 if targets[dep] == 'SUBSYSTEM':
399 grouping[dep] = t.sname
401 # now replace any dependencies on elements of grouping libraries
403 for i in range(len(t.samba_deps_extended)):
404 dep = t.samba_deps_extended[i]
406 if t.sname != grouping[dep]:
407 debug("deps: target %s: replacing dependency %s with grouping library %s" % (t.sname, dep, grouping[dep]))
408 t.samba_deps_extended[i] = grouping[dep]
412 def build_direct_deps(bld, tgt_list):
413 '''build the direct_objects and direct_libs sets for each target'''
415 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
416 syslib_deps = LOCAL_CACHE(bld, 'SYSLIB_DEPS')
418 global_deps = bld.env.GLOBAL_DEPENDENCIES
419 global_deps_exclude = set()
420 for dep in global_deps:
421 t = bld.name_to_obj(dep, bld.env)
422 for d in t.samba_deps:
423 # prevent loops from the global dependencies list
424 global_deps_exclude.add(d)
425 global_deps_exclude.add(d + '.objlist')
428 t.direct_objects = set()
429 t.direct_libs = set()
430 t.direct_syslibs = set()
431 deps = t.samba_deps_extended[:]
432 if getattr(t, 'samba_use_global_deps', False) and not t.sname in global_deps_exclude:
433 deps.extend(global_deps)
435 d = EXPAND_ALIAS(bld, d)
436 if d == t.sname: continue
438 Logs.error("Unknown dependency %s in %s" % (d, t.sname))
440 if targets[d] in [ 'EMPTY', 'DISABLED' ]:
442 if targets[d] == 'PYTHON':
443 Logs.error('ERROR: Target %s has dependency on python module %s' % (t.sname, d))
445 if targets[d] == 'SYSLIB':
446 t.direct_syslibs.add(d)
448 for implied in TO_LIST(syslib_deps[d]):
449 if BUILTIN_LIBRARY(bld, implied):
450 t.direct_objects.add(implied)
451 elif targets[implied] == 'SYSLIB':
452 t.direct_syslibs.add(implied)
453 elif targets[implied] in ['LIBRARY', 'MODULE']:
454 t.direct_libs.add(implied)
456 Logs.error('Implied dependency %s in %s is of type %s' % (
457 implied, t.sname, targets[implied]))
460 t2 = bld.name_to_obj(d, bld.env)
462 Logs.error("no task %s of type %s in %s" % (d, targets[d], t.sname))
464 if t2.samba_type in [ 'LIBRARY', 'MODULE' ]:
466 elif t2.samba_type in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]:
467 t.direct_objects.add(d)
468 debug('deps: built direct dependencies')
471 def dependency_loop(loops, t, target):
472 '''add a dependency loop to the loops dictionary'''
473 if t.sname == target:
475 if not target in loops:
476 loops[target] = set()
477 if not t.sname in loops[target]:
478 loops[target].add(t.sname)
481 def indirect_libs(bld, t, chain, loops):
482 '''recursively calculate the indirect library dependencies for a target
484 An indirect library is a library that results from a dependency on
488 ret = getattr(t, 'indirect_libs', None)
493 for obj in t.direct_objects:
495 dependency_loop(loops, t, obj)
498 t2 = bld.name_to_obj(obj, bld.env)
499 r2 = indirect_libs(bld, t2, chain, loops)
501 ret = ret.union(t2.direct_libs)
504 for obj in indirect_objects(bld, t, set(), loops):
506 dependency_loop(loops, t, obj)
509 t2 = bld.name_to_obj(obj, bld.env)
510 r2 = indirect_libs(bld, t2, chain, loops)
512 ret = ret.union(t2.direct_libs)
515 t.indirect_libs = ret
520 def indirect_objects(bld, t, chain, loops):
521 '''recursively calculate the indirect object dependencies for a target
523 indirect objects are the set of objects from expanding the
524 subsystem dependencies
527 ret = getattr(t, 'indirect_objects', None)
528 if ret is not None: return ret
531 for lib in t.direct_objects:
533 dependency_loop(loops, t, lib)
536 t2 = bld.name_to_obj(lib, bld.env)
537 r2 = indirect_objects(bld, t2, chain, loops)
539 ret = ret.union(t2.direct_objects)
542 t.indirect_objects = ret
546 def extended_objects(bld, t, chain):
547 '''recursively calculate the extended object dependencies for a target
549 extended objects are the union of:
552 - direct and indirect objects of all direct and indirect libraries
555 ret = getattr(t, 'extended_objects', None)
556 if ret is not None: return ret
559 ret = ret.union(t.final_objects)
561 for lib in t.final_libs:
564 t2 = bld.name_to_obj(lib, bld.env)
566 r2 = extended_objects(bld, t2, chain)
568 ret = ret.union(t2.final_objects)
571 t.extended_objects = ret
575 def includes_objects(bld, t, chain, inc_loops):
576 '''recursively calculate the includes object dependencies for a target
578 includes dependencies come from either library or object dependencies
580 ret = getattr(t, 'includes_objects', None)
584 ret = t.direct_objects.copy()
585 ret = ret.union(t.direct_libs)
587 for obj in t.direct_objects:
589 dependency_loop(inc_loops, t, obj)
592 t2 = bld.name_to_obj(obj, bld.env)
593 r2 = includes_objects(bld, t2, chain, inc_loops)
595 ret = ret.union(t2.direct_objects)
598 for lib in t.direct_libs:
600 dependency_loop(inc_loops, t, lib)
603 t2 = bld.name_to_obj(lib, bld.env)
605 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
606 Logs.error('Target %s of type %s not found in direct_libs for %s' % (
607 lib, targets[lib], t.sname))
609 r2 = includes_objects(bld, t2, chain, inc_loops)
611 ret = ret.union(t2.direct_objects)
614 t.includes_objects = ret
618 def break_dependency_loops(bld, tgt_list):
619 '''find and break dependency loops'''
623 # build up the list of loops
625 indirect_objects(bld, t, set(), loops)
626 indirect_libs(bld, t, set(), loops)
627 includes_objects(bld, t, set(), inc_loops)
632 for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
633 objs = getattr(t, attr, set())
634 setattr(t, attr, objs.difference(loops[t.sname]))
637 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
639 for loop in inc_loops:
640 debug('deps: Found include loops for target %s : %s', loop, inc_loops[loop])
642 # expand the loops mapping by one level
643 for loop in loops.copy():
644 for tgt in loops[loop]:
646 loops[loop] = loops[loop].union(loops[tgt])
648 for loop in inc_loops.copy():
649 for tgt in inc_loops[loop]:
651 inc_loops[loop] = inc_loops[loop].union(inc_loops[tgt])
654 # expand indirect subsystem and library loops
655 for loop in loops.copy():
656 t = bld.name_to_obj(loop, bld.env)
657 if t.samba_type in ['SUBSYSTEM']:
658 loops[loop] = loops[loop].union(t.indirect_objects)
659 loops[loop] = loops[loop].union(t.direct_objects)
660 if t.samba_type in ['LIBRARY','PYTHON']:
661 loops[loop] = loops[loop].union(t.indirect_libs)
662 loops[loop] = loops[loop].union(t.direct_libs)
663 if loop in loops[loop]:
664 loops[loop].remove(loop)
666 # expand indirect includes loops
667 for loop in inc_loops.copy():
668 t = bld.name_to_obj(loop, bld.env)
669 inc_loops[loop] = inc_loops[loop].union(t.includes_objects)
670 if loop in inc_loops[loop]:
671 inc_loops[loop].remove(loop)
673 # add in the replacement dependencies
676 for attr in ['indirect_objects', 'indirect_libs']:
677 objs = getattr(t, attr, set())
679 diff = loops[loop].difference(objs)
683 debug('deps: Expanded target %s of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
684 objs = objs.union(diff)
685 setattr(t, attr, objs)
687 for loop in inc_loops:
688 objs = getattr(t, 'includes_objects', set())
690 diff = inc_loops[loop].difference(objs)
694 debug('deps: Expanded target %s includes of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
695 objs = objs.union(diff)
696 setattr(t, 'includes_objects', objs)
699 def reduce_objects(bld, tgt_list):
700 '''reduce objects by looking for indirect object dependencies'''
704 t.extended_objects = None
708 for type in ['BINARY', 'PYTHON', 'LIBRARY']:
710 if t.samba_type != type: continue
711 # if we will indirectly link to a target then we don't need it
712 new = t.final_objects.copy()
713 for l in t.final_libs:
714 t2 = bld.name_to_obj(l, bld.env)
715 t2_obj = extended_objects(bld, t2, set())
716 dup = new.intersection(t2_obj)
717 if t.sname in rely_on:
718 dup = dup.difference(rely_on[t.sname])
720 debug('deps: removing dups from %s of type %s: %s also in %s %s',
721 t.sname, t.samba_type, dup, t2.samba_type, l)
722 new = new.difference(dup)
726 rely_on[l] = rely_on[l].union(dup)
727 t.final_objects = new
732 # add back in any objects that were relied upon by the reduction rules
734 t = bld.name_to_obj(r, bld.env)
735 t.final_objects = t.final_objects.union(rely_on[r])
740 def calculate_final_deps(bld, tgt_list, loops):
741 '''calculate the final library and object dependencies'''
743 # start with the maximum possible list
744 t.final_libs = t.direct_libs.union(indirect_libs(bld, t, set(), loops))
745 t.final_objects = t.direct_objects.union(indirect_objects(bld, t, set(), loops))
748 # don't depend on ourselves
749 if t.sname in t.final_libs:
750 t.final_libs.remove(t.sname)
751 if t.sname in t.final_objects:
752 t.final_objects.remove(t.sname)
754 # handle any non-shared binaries
756 if t.samba_type == 'BINARY' and bld.NONSHARED_BINARY(t.sname):
757 # replace lib deps with objlist deps
758 for l in t.final_libs:
759 objname = l + '.objlist'
760 t2 = bld.name_to_obj(objname, bld.env)
762 Logs.error('ERROR: subsystem %s not found' % objname)
764 t.final_objects.add(objname)
765 t.final_objects = t.final_objects.union(extended_objects(bld, t2, set()))
768 # find any library loops
770 if t.samba_type in ['LIBRARY', 'PYTHON']:
771 for l in t.final_libs.copy():
772 t2 = bld.name_to_obj(l, bld.env)
773 if t.sname in t2.final_libs:
774 if getattr(bld.env, "ALLOW_CIRCULAR_LIB_DEPENDENCIES", False):
775 # we could break this in either direction. If one of the libraries
776 # has a version number, and will this be distributed publicly, then
777 # we should make it the lower level library in the DAG
778 Logs.warn('deps: removing library loop %s from %s' % (t.sname, t2.sname))
779 dependency_loop(loops, t, t2.sname)
780 t2.final_libs.remove(t.sname)
782 Logs.error('ERROR: circular library dependency between %s and %s'
783 % (t.sname, t2.sname))
787 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
789 # we now need to make corrections for any library loops we broke up
790 # any target that depended on the target of the loop and doesn't
791 # depend on the source of the loop needs to get the loop source added
792 for type in ['BINARY','PYTHON','LIBRARY','BINARY']:
794 if t.samba_type != type: continue
796 if loop in t.final_libs:
797 diff = loops[loop].difference(t.final_libs)
802 # make sure we don't recreate the loop again!
803 for d in diff.copy():
804 t2 = bld.name_to_obj(d, bld.env)
805 if t2.samba_type == 'LIBRARY':
806 if t.sname in t2.final_libs:
807 debug('deps: removing expansion %s from %s', d, t.sname)
810 debug('deps: Expanded target %s by loop %s libraries (loop %s) %s', t.sname, loop,
812 t.final_libs = t.final_libs.union(diff)
814 # remove objects that are also available in linked libs
816 while reduce_objects(bld, tgt_list):
819 Logs.warn("WARNING: Unable to remove all inter-target object duplicates")
821 debug('deps: Object reduction took %u iterations', count)
823 # add in any syslib dependencies
825 if not t.samba_type in ['BINARY','PYTHON','LIBRARY']:
828 for d in t.final_objects:
829 t2 = bld.name_to_obj(d, bld.env)
830 syslibs = syslibs.union(t2.direct_syslibs)
831 # this adds the indirect syslibs as well, which may not be needed
832 # depending on the linker flags
833 for d in t.final_libs:
834 t2 = bld.name_to_obj(d, bld.env)
835 syslibs = syslibs.union(t2.direct_syslibs)
836 t.final_syslibs = syslibs
839 # find any unresolved library loops
840 lib_loop_error = False
842 if t.samba_type in ['LIBRARY', 'PYTHON']:
843 for l in t.final_libs.copy():
844 t2 = bld.name_to_obj(l, bld.env)
845 if t.sname in t2.final_libs:
846 Logs.error('ERROR: Unresolved library loop %s from %s' % (t.sname, t2.sname))
847 lib_loop_error = True
851 debug('deps: removed duplicate dependencies')
854 def show_dependencies(bld, target, seen):
855 '''recursively show the dependencies of target'''
860 t = bld.name_to_obj(target, bld.env)
862 Logs.error("ERROR: Unable to find target '%s'" % target)
865 Logs.info('%s(OBJECTS): %s' % (target, t.direct_objects))
866 Logs.info('%s(LIBS): %s' % (target, t.direct_libs))
867 Logs.info('%s(SYSLIBS): %s' % (target, t.direct_syslibs))
871 for t2 in t.direct_objects:
872 show_dependencies(bld, t2, seen)
875 def show_object_duplicates(bld, tgt_list):
876 '''show a list of object files that are included in more than
877 one library or binary'''
879 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
883 Logs.info("showing duplicate objects")
886 if not targets[t.sname] in [ 'LIBRARY', 'PYTHON' ]:
888 for n in getattr(t, 'final_objects', set()):
889 t2 = bld.name_to_obj(n, bld.env)
892 used_by[n].add(t.sname)
895 if len(used_by[n]) > 1:
896 Logs.info("target '%s' is used by %s" % (n, used_by[n]))
898 Logs.info("showing indirect dependency counts (sorted by count)")
900 def indirect_count(t1, t2):
901 return len(t2.indirect_objects) - len(t1.indirect_objects)
903 sorted_list = sorted(tgt_list, cmp=indirect_count)
904 for t in sorted_list:
905 if len(t.indirect_objects) > 1:
906 Logs.info("%s depends on %u indirect objects" % (t.sname, len(t.indirect_objects)))
909 ######################################################################
910 # this provides a way to save our dependency calculations between runs
912 savedeps_inputs = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags', 'source', 'grouping_library']
913 savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags', 'ldflags']
914 savedeps_outenv = ['INC_PATHS']
915 savedeps_envvars = ['NONSHARED_BINARIES', 'GLOBAL_DEPENDENCIES']
916 savedeps_caches = ['GLOBAL_DEPENDENCIES', 'TARGET_ALIAS', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
917 savedeps_files = ['buildtools/wafsamba/samba_deps.py']
919 def save_samba_deps(bld, tgt_list):
920 '''save the dependency calculations between builds, to make
921 further builds faster'''
922 denv = Environment.Environment()
924 denv.version = savedeps_version
925 denv.savedeps_inputs = savedeps_inputs
926 denv.savedeps_outputs = savedeps_outputs
934 for f in savedeps_files:
935 denv.files[f] = os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime
937 for c in savedeps_caches:
938 denv.caches[c] = LOCAL_CACHE(bld, c)
940 for e in savedeps_envvars:
941 denv.envvar[e] = bld.env[e]
944 # save all the input attributes for each target
946 for attr in savedeps_inputs:
947 v = getattr(t, attr, None)
951 denv.input[t.sname] = tdeps
953 # save all the output attributes for each target
955 for attr in savedeps_outputs:
956 v = getattr(t, attr, None)
960 denv.output[t.sname] = tdeps
963 for attr in savedeps_outenv:
965 tdeps[attr] = t.env[attr]
967 denv.outenv[t.sname] = tdeps
969 depsfile = os.path.join(bld.bdir, "sambadeps")
974 def load_samba_deps(bld, tgt_list):
975 '''load a previous set of build dependencies if possible'''
976 depsfile = os.path.join(bld.bdir, "sambadeps")
977 denv = Environment.Environment()
979 debug('deps: checking saved dependencies')
981 if (denv.version != savedeps_version or
982 denv.savedeps_inputs != savedeps_inputs or
983 denv.savedeps_outputs != savedeps_outputs):
988 # check if critical files have changed
989 for f in savedeps_files:
990 if f not in denv.files:
992 if denv.files[f] != os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime:
995 # check if caches are the same
996 for c in savedeps_caches:
997 if c not in denv.caches or denv.caches[c] != LOCAL_CACHE(bld, c):
1000 # check if caches are the same
1001 for e in savedeps_envvars:
1002 if e not in denv.envvar or denv.envvar[e] != bld.env[e]:
1005 # check inputs are the same
1008 for attr in savedeps_inputs:
1009 v = getattr(t, attr, None)
1012 if t.sname in denv.input:
1013 olddeps = denv.input[t.sname]
1016 if tdeps != olddeps:
1017 #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
1020 # put outputs in place
1022 if not t.sname in denv.output: continue
1023 tdeps = denv.output[t.sname]
1025 setattr(t, a, tdeps[a])
1027 # put output env vars in place
1029 if not t.sname in denv.outenv: continue
1030 tdeps = denv.outenv[t.sname]
1034 debug('deps: loaded saved dependencies')
1039 def check_project_rules(bld):
1040 '''check the project rules - ensuring the targets are sane'''
1042 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
1046 # build a list of task generators we are interested in
1050 if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON']:
1052 t = bld.name_to_obj(tgt, bld.env)
1054 Logs.error("Target %s of type %s has no task generator" % (tgt, type))
1058 add_samba_attributes(bld, tgt_list)
1060 force_project_rules = (Options.options.SHOWDEPS or
1061 Options.options.SHOW_DUPLICATES)
1063 if not force_project_rules and load_samba_deps(bld, tgt_list):
1066 bld.new_rules = True
1067 Logs.info("Checking project rules ...")
1069 debug('deps: project rules checking started')
1071 expand_subsystem_deps(bld)
1072 replace_grouping_libraries(bld, tgt_list)
1073 build_direct_deps(bld, tgt_list)
1075 break_dependency_loops(bld, tgt_list)
1077 if Options.options.SHOWDEPS:
1078 show_dependencies(bld, Options.options.SHOWDEPS, set())
1080 calculate_final_deps(bld, tgt_list, loops)
1082 if Options.options.SHOW_DUPLICATES:
1083 show_object_duplicates(bld, tgt_list)
1085 # run the various attribute generators
1086 for f in [ build_dependencies, build_includes, add_init_functions ]:
1087 debug('deps: project rules checking %s', f)
1088 for t in tgt_list: f(t)
1090 debug('deps: project rules stage1 completed')
1092 #check_orpaned_targets(bld, tgt_list)
1094 if not check_duplicate_sources(bld, tgt_list):
1095 Logs.error("Duplicate sources present - aborting")
1098 if not check_group_ordering(bld, tgt_list):
1099 Logs.error("Bad group ordering - aborting")
1102 show_final_deps(bld, tgt_list)
1104 debug('deps: project rules checking completed - %u targets checked',
1107 if not bld.is_install:
1108 save_samba_deps(bld, tgt_list)
1110 Logs.info("Project rules pass")
1113 def CHECK_PROJECT_RULES(bld):
1114 '''enable checking of project targets for sanity'''
1115 if bld.env.added_project_rules:
1117 bld.env.added_project_rules = True
1118 bld.add_pre_fun(check_project_rules)
1119 Build.BuildContext.CHECK_PROJECT_RULES = CHECK_PROJECT_RULES