1 # Samba automatic dependency handling and project rules
3 import os, sys, re, time
5 import Build, Environment, Options, Logs, Utils
7 from Configure import conf
9 from samba_bundled import BUILTIN_LIBRARY
10 from samba_utils import LOCAL_CACHE, TO_LIST, get_tgt_list, unique_list, os_path_relpath
11 from samba_autoconf import library_flags
14 def ADD_GLOBAL_DEPENDENCY(ctx, dep):
15 '''add a dependency for all binaries and libraries'''
16 if not 'GLOBAL_DEPENDENCIES' in ctx.env:
17 ctx.env.GLOBAL_DEPENDENCIES = []
18 ctx.env.GLOBAL_DEPENDENCIES.append(dep)
22 def BREAK_CIRCULAR_LIBRARY_DEPENDENCIES(ctx):
23 '''indicate that circular dependencies between libraries should be broken.'''
24 ctx.env.ALLOW_CIRCULAR_LIB_DEPENDENCIES = True
28 def SET_SYSLIB_DEPS(conf, target, deps):
29 '''setup some implied dependencies for a SYSLIB'''
30 cache = LOCAL_CACHE(conf, 'SYSLIB_DEPS')
34 def expand_subsystem_deps(bld):
35 '''expand the reverse dependencies resulting from subsystem
36 attributes of modules. This is walking over the complete list
37 of declared subsystems, and expands the samba_deps_extended list for any
38 module<->subsystem dependencies'''
40 subsystem_list = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
41 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
43 for subsystem_name in subsystem_list:
44 bld.ASSERT(subsystem_name in targets, "Subsystem target %s not declared" % subsystem_name)
45 type = targets[subsystem_name]
46 if type == 'DISABLED' or type == 'EMPTY':
50 # subsystem_name = dcerpc_server (a subsystem)
51 # subsystem = dcerpc_server (a subsystem object)
52 # module_name = rpc_epmapper (a module within the dcerpc_server subsystem)
53 # module = rpc_epmapper (a module object within the dcerpc_server subsystem)
55 subsystem = bld.get_tgen_by_name(subsystem_name)
56 bld.ASSERT(subsystem is not None, "Unable to find subsystem %s" % subsystem_name)
57 for d in subsystem_list[subsystem_name]:
58 module_name = d['TARGET']
59 module_type = targets[module_name]
60 if module_type in ['DISABLED', 'EMPTY']:
62 bld.ASSERT(subsystem is not None,
63 "Subsystem target %s for %s (%s) not found" % (subsystem_name, module_name, module_type))
64 if module_type in ['SUBSYSTEM']:
65 # if a module is a plain object type (not a library) then the
66 # subsystem it is part of needs to have it as a dependency, so targets
67 # that depend on this subsystem get the modules of that subsystem
68 subsystem.samba_deps_extended.append(module_name)
69 subsystem.samba_deps_extended = unique_list(subsystem.samba_deps_extended)
73 def build_dependencies(self):
74 '''This builds the dependency list for a target. It runs after all the targets are declared
76 The reason this is not just done in the SAMBA_*() rules is that we have no way of knowing
77 the full dependency list for a target until we have all of the targets declared.
80 if self.samba_type in ['LIBRARY', 'BINARY', 'PYTHON']:
81 self.uselib = list(self.final_syslibs)
82 self.uselib_local = list(self.final_libs)
83 self.add_objects = list(self.final_objects)
85 # extra link flags from pkg_config
86 libs = self.final_syslibs.copy()
88 (ccflags, ldflags, cpppath) = library_flags(self, list(libs))
89 new_ldflags = getattr(self, 'samba_ldflags', [])[:]
90 new_ldflags.extend(ldflags)
91 self.ldflags = new_ldflags
93 if getattr(self, 'allow_undefined_symbols', False) and self.env.undefined_ldflags:
94 for f in self.env.undefined_ldflags:
95 self.ldflags.remove(f)
97 if getattr(self, 'allow_undefined_symbols', False) and self.env.undefined_ignore_ldflags:
98 for f in self.env.undefined_ignore_ldflags:
99 self.ldflags.append(f)
101 debug('deps: computed dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
102 self.sname, self.uselib, self.uselib_local, self.add_objects)
104 if self.samba_type in ['SUBSYSTEM']:
105 # this is needed for the ccflags of libs that come from pkg_config
106 self.uselib = list(self.final_syslibs)
107 self.uselib.extend(list(self.direct_syslibs))
108 for lib in self.final_libs:
109 t = self.bld.get_tgen_by_name(lib)
110 self.uselib.extend(list(t.final_syslibs))
111 self.uselib = unique_list(self.uselib)
113 if getattr(self, 'uselib', None):
115 for l in self.uselib:
116 up_list.append(l.upper())
117 self.uselib = up_list
120 def build_includes(self):
121 '''This builds the right set of includes for a target.
123 One tricky part of this is that the includes= attribute for a
124 target needs to use paths which are relative to that targets
125 declaration directory (which we can get at via t.path).
127 The way this works is the includes list gets added as
128 samba_includes in the main build task declaration. Then this
129 function runs after all of the tasks are declared, and it
130 processes the samba_includes attribute to produce a includes=
134 if getattr(self, 'samba_includes', None) is None:
139 inc_deps = includes_objects(bld, self, set(), {})
143 # maybe add local includes
144 if getattr(self, 'local_include', True) and getattr(self, 'local_include_first', True):
147 includes.extend(self.samba_includes_extended)
149 if 'EXTRA_INCLUDES' in bld.env and getattr(self, 'global_include', True):
150 includes.extend(bld.env['EXTRA_INCLUDES'])
158 t = bld.get_tgen_by_name(d)
159 bld.ASSERT(t is not None, "Unable to find dependency %s for %s" % (d, self.sname))
160 inclist = getattr(t, 'samba_includes_extended', [])[:]
161 if getattr(t, 'local_include', True):
165 tpath = t.samba_abspath
167 npath = tpath + '/' + inc
168 if not npath in inc_set:
169 inc_abs.append(npath)
172 mypath = self.path.abspath(bld.env)
174 relpath = os_path_relpath(inc, mypath)
175 includes.append(relpath)
177 if getattr(self, 'local_include', True) and not getattr(self, 'local_include_first', True):
180 # now transform the includes list to be relative to the top directory
181 # which is represented by '#' in waf. This allows waf to cache the
182 # includes lists more efficiently
186 # some are already top based
187 includes_top.append(i)
189 absinc = os.path.join(self.path.abspath(), i)
190 relinc = os_path_relpath(absinc, self.bld.srcnode.abspath())
191 includes_top.append('#' + relinc)
193 self.includes = unique_list(includes_top)
194 debug('deps: includes for target %s: includes=%s',
195 self.sname, self.includes)
198 def add_init_functions(self):
199 '''This builds the right set of init functions'''
203 subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
205 # cope with the separated object lists from BINARY and LIBRARY targets
207 if sname.endswith('.objlist'):
211 if sname in subsystems:
212 modules.append(sname)
214 m = getattr(self, 'samba_modules', None)
216 modules.extend(TO_LIST(m))
218 m = getattr(self, 'samba_subsystem', None)
222 if 'pyembed' in self.features:
225 sentinel = getattr(self, 'init_function_sentinel', 'NULL')
227 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
228 cflags = getattr(self, 'samba_cflags', [])[:]
231 sname = sname.replace('-','_')
232 sname = sname.replace('/','_')
233 cflags.append('-DSTATIC_%s_MODULES=%s' % (sname, sentinel))
234 if sentinel == 'NULL':
235 proto = "extern void __%s_dummy_module_proto(void)" % (sname)
236 cflags.append('-DSTATIC_%s_MODULES_PROTO=%s' % (sname, proto))
237 self.ccflags = 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, sentinel))
249 if sentinel == 'NULL':
250 proto = "extern void __%s_dummy_module_proto(void)" % (m)
251 cflags.append('-DSTATIC_%s_MODULES_PROTO=%s' % (m, proto))
253 cflags.append('-DSTATIC_%s_MODULES=%s' % (m, ','.join(init_fn_list) + ',' + sentinel))
255 for f in init_fn_list:
256 proto += '_MODULE_PROTO(%s)' % f
257 proto += "extern void __%s_dummy_module_proto(void)" % (m)
258 cflags.append('-DSTATIC_%s_MODULES_PROTO=%s' % (m, proto))
259 self.ccflags = cflags
262 def check_duplicate_sources(bld, tgt_list):
263 '''see if we are compiling the same source file more than once'''
265 debug('deps: checking for duplicate sources')
266 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
269 source_list = TO_LIST(getattr(t, 'source', ''))
270 tpath = os.path.normpath(os_path_relpath(t.path.abspath(bld.env), t.env.BUILD_DIRECTORY + '/default'))
272 for s in source_list:
273 p = os.path.normpath(os.path.join(tpath, s))
275 Logs.error("ERROR: source %s appears twice in target '%s'" % (p, t.sname))
278 t.samba_source_set = obj_sources
282 # build a list of targets that each source file is part of
284 if not targets[t.sname] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
286 for obj in t.add_objects:
287 t2 = t.bld.get_tgen_by_name(obj)
288 source_set = getattr(t2, 'samba_source_set', set())
290 if not s in subsystems:
292 if not t.sname in subsystems[s]:
293 subsystems[s][t.sname] = []
294 subsystems[s][t.sname].append(t2.sname)
297 if len(subsystems[s]) > 1 and Options.options.SHOW_DUPLICATES:
298 Logs.warn("WARNING: source %s is in more than one target: %s" % (s, subsystems[s].keys()))
299 for tname in subsystems[s]:
300 if len(subsystems[s][tname]) > 1:
301 raise Utils.WafError("ERROR: source %s is in more than one subsystem of target '%s': %s" % (s, tname, subsystems[s][tname]))
306 def check_orphaned_targets(bld, tgt_list):
307 '''check if any build targets are orphaned'''
309 target_dict = LOCAL_CACHE(bld, 'TARGET_TYPE')
311 debug('deps: checking for orphaned targets')
314 if getattr(t, 'samba_used', False):
316 type = target_dict[t.sname]
317 if not type in ['BINARY', 'LIBRARY', 'MODULE', 'ET', 'PYTHON']:
318 if re.search('^PIDL_', t.sname) is None:
319 Logs.warn("Target %s of type %s is unused by any other target" % (t.sname, type))
322 def check_group_ordering(bld, tgt_list):
323 '''see if we have any dependencies that violate the group ordering
325 It is an error for a target to depend on a target from a later
330 tm = bld.task_manager
331 return [x for x in tm.groups_names if id(tm.groups_names[x]) == id(g)][0]
333 for g in bld.task_manager.groups:
334 gname = group_name(g)
335 for t in g.tasks_gen:
336 t.samba_group = gname
340 for g in bld.task_manager.groups:
345 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
349 tdeps = getattr(t, 'add_objects', []) + getattr(t, 'uselib_local', [])
351 t2 = bld.get_tgen_by_name(d)
354 map1 = grp_map[t.samba_group]
355 map2 = grp_map[t2.samba_group]
358 Logs.error("Target %r in build group %r depends on target %r from later build group %r" % (
359 t.sname, t.samba_group, t2.sname, t2.samba_group))
365 def show_final_deps(bld, tgt_list):
366 '''show the final dependencies for all targets'''
368 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
371 if not targets[t.sname] in ['LIBRARY', 'BINARY', 'PYTHON', 'SUBSYSTEM']:
373 debug('deps: final dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
374 t.sname, t.uselib, getattr(t, 'uselib_local', []), getattr(t, 'add_objects', []))
377 def add_samba_attributes(bld, tgt_list):
378 '''ensure a target has a the required samba attributes'''
380 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
387 t.samba_type = targets[t.sname]
388 t.samba_abspath = t.path.abspath(bld.env)
389 t.samba_deps_extended = t.samba_deps[:]
390 t.samba_includes_extended = TO_LIST(t.samba_includes)[:]
391 t.ccflags = getattr(t, 'samba_cflags', '')
393 def replace_grouping_libraries(bld, tgt_list):
394 '''replace dependencies based on grouping libraries
396 If a library is marked as a grouping library, then any target that
397 depends on a subsystem that is part of that grouping library gets
398 that dependency replaced with a dependency on the grouping library
401 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
405 # find our list of grouping libraries, mapped from the subsystems they depend on
407 if not getattr(t, 'grouping_library', False):
409 for dep in t.samba_deps_extended:
410 bld.ASSERT(dep in targets, "grouping library target %s not declared in %s" % (dep, t.sname))
411 if targets[dep] == 'SUBSYSTEM':
412 grouping[dep] = t.sname
414 # now replace any dependencies on elements of grouping libraries
416 for i in range(len(t.samba_deps_extended)):
417 dep = t.samba_deps_extended[i]
419 if t.sname != grouping[dep]:
420 debug("deps: target %s: replacing dependency %s with grouping library %s" % (t.sname, dep, grouping[dep]))
421 t.samba_deps_extended[i] = grouping[dep]
425 def build_direct_deps(bld, tgt_list):
426 '''build the direct_objects and direct_libs sets for each target'''
428 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
429 syslib_deps = LOCAL_CACHE(bld, 'SYSLIB_DEPS')
431 global_deps = bld.env.GLOBAL_DEPENDENCIES
432 global_deps_exclude = set()
433 for dep in global_deps:
434 t = bld.get_tgen_by_name(dep)
435 for d in t.samba_deps:
436 # prevent loops from the global dependencies list
437 global_deps_exclude.add(d)
438 global_deps_exclude.add(d + '.objlist')
441 t.direct_objects = set()
442 t.direct_libs = set()
443 t.direct_syslibs = set()
444 deps = t.samba_deps_extended[:]
445 if getattr(t, 'samba_use_global_deps', False) and not t.sname in global_deps_exclude:
446 deps.extend(global_deps)
448 if d == t.sname: continue
450 Logs.error("Unknown dependency '%s' in '%s'" % (d, t.sname))
452 if targets[d] in [ 'EMPTY', 'DISABLED' ]:
454 if targets[d] == 'PYTHON' and targets[t.sname] != 'PYTHON' and t.sname.find('.objlist') == -1:
455 # this check should be more restrictive, but for now we have pidl-generated python
456 # code that directly depends on other python modules
457 Logs.error('ERROR: Target %s has dependency on python module %s' % (t.sname, d))
459 if targets[d] == 'SYSLIB':
460 t.direct_syslibs.add(d)
462 for implied in TO_LIST(syslib_deps[d]):
463 if BUILTIN_LIBRARY(bld, implied):
464 t.direct_objects.add(implied)
465 elif targets[implied] == 'SYSLIB':
466 t.direct_syslibs.add(implied)
467 elif targets[implied] in ['LIBRARY', 'MODULE']:
468 t.direct_libs.add(implied)
470 Logs.error('Implied dependency %s in %s is of type %s' % (
471 implied, t.sname, targets[implied]))
474 t2 = bld.get_tgen_by_name(d)
476 Logs.error("no task %s of type %s in %s" % (d, targets[d], t.sname))
478 if t2.samba_type in [ 'LIBRARY', 'MODULE' ]:
480 elif t2.samba_type in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]:
481 t.direct_objects.add(d)
482 debug('deps: built direct dependencies')
485 def dependency_loop(loops, t, target):
486 '''add a dependency loop to the loops dictionary'''
487 if t.sname == target:
489 if not target in loops:
490 loops[target] = set()
491 if not t.sname in loops[target]:
492 loops[target].add(t.sname)
495 def indirect_libs(bld, t, chain, loops):
496 '''recursively calculate the indirect library dependencies for a target
498 An indirect library is a library that results from a dependency on
502 ret = getattr(t, 'indirect_libs', None)
507 for obj in t.direct_objects:
509 dependency_loop(loops, t, obj)
512 t2 = bld.get_tgen_by_name(obj)
513 r2 = indirect_libs(bld, t2, chain, loops)
515 ret = ret.union(t2.direct_libs)
518 for obj in indirect_objects(bld, t, set(), loops):
520 dependency_loop(loops, t, obj)
523 t2 = bld.get_tgen_by_name(obj)
524 r2 = indirect_libs(bld, t2, chain, loops)
526 ret = ret.union(t2.direct_libs)
529 t.indirect_libs = ret
534 def indirect_objects(bld, t, chain, loops):
535 '''recursively calculate the indirect object dependencies for a target
537 indirect objects are the set of objects from expanding the
538 subsystem dependencies
541 ret = getattr(t, 'indirect_objects', None)
542 if ret is not None: return ret
545 for lib in t.direct_objects:
547 dependency_loop(loops, t, lib)
550 t2 = bld.get_tgen_by_name(lib)
551 r2 = indirect_objects(bld, t2, chain, loops)
553 ret = ret.union(t2.direct_objects)
556 t.indirect_objects = ret
560 def extended_objects(bld, t, chain):
561 '''recursively calculate the extended object dependencies for a target
563 extended objects are the union of:
566 - direct and indirect objects of all direct and indirect libraries
569 ret = getattr(t, 'extended_objects', None)
570 if ret is not None: return ret
573 ret = ret.union(t.final_objects)
575 for lib in t.final_libs:
578 t2 = bld.get_tgen_by_name(lib)
580 r2 = extended_objects(bld, t2, chain)
582 ret = ret.union(t2.final_objects)
585 t.extended_objects = ret
589 def includes_objects(bld, t, chain, inc_loops):
590 '''recursively calculate the includes object dependencies for a target
592 includes dependencies come from either library or object dependencies
594 ret = getattr(t, 'includes_objects', None)
598 ret = t.direct_objects.copy()
599 ret = ret.union(t.direct_libs)
601 for obj in t.direct_objects:
603 dependency_loop(inc_loops, t, obj)
606 t2 = bld.get_tgen_by_name(obj)
607 r2 = includes_objects(bld, t2, chain, inc_loops)
609 ret = ret.union(t2.direct_objects)
612 for lib in t.direct_libs:
614 dependency_loop(inc_loops, t, lib)
617 t2 = bld.get_tgen_by_name(lib)
619 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
620 Logs.error('Target %s of type %s not found in direct_libs for %s' % (
621 lib, targets[lib], t.sname))
623 r2 = includes_objects(bld, t2, chain, inc_loops)
625 ret = ret.union(t2.direct_objects)
628 t.includes_objects = ret
632 def break_dependency_loops(bld, tgt_list):
633 '''find and break dependency loops'''
637 # build up the list of loops
639 indirect_objects(bld, t, set(), loops)
640 indirect_libs(bld, t, set(), loops)
641 includes_objects(bld, t, set(), inc_loops)
646 for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
647 objs = getattr(t, attr, set())
648 setattr(t, attr, objs.difference(loops[t.sname]))
651 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
653 for loop in inc_loops:
654 debug('deps: Found include loops for target %s : %s', loop, inc_loops[loop])
656 # expand the loops mapping by one level
657 for loop in loops.copy():
658 for tgt in loops[loop]:
660 loops[loop] = loops[loop].union(loops[tgt])
662 for loop in inc_loops.copy():
663 for tgt in inc_loops[loop]:
665 inc_loops[loop] = inc_loops[loop].union(inc_loops[tgt])
668 # expand indirect subsystem and library loops
669 for loop in loops.copy():
670 t = bld.get_tgen_by_name(loop)
671 if t.samba_type in ['SUBSYSTEM']:
672 loops[loop] = loops[loop].union(t.indirect_objects)
673 loops[loop] = loops[loop].union(t.direct_objects)
674 if t.samba_type in ['LIBRARY','PYTHON']:
675 loops[loop] = loops[loop].union(t.indirect_libs)
676 loops[loop] = loops[loop].union(t.direct_libs)
677 if loop in loops[loop]:
678 loops[loop].remove(loop)
680 # expand indirect includes loops
681 for loop in inc_loops.copy():
682 t = bld.get_tgen_by_name(loop)
683 inc_loops[loop] = inc_loops[loop].union(t.includes_objects)
684 if loop in inc_loops[loop]:
685 inc_loops[loop].remove(loop)
687 # add in the replacement dependencies
690 for attr in ['indirect_objects', 'indirect_libs']:
691 objs = getattr(t, attr, set())
693 diff = loops[loop].difference(objs)
697 debug('deps: Expanded target %s of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
698 objs = objs.union(diff)
699 setattr(t, attr, objs)
701 for loop in inc_loops:
702 objs = getattr(t, 'includes_objects', set())
704 diff = inc_loops[loop].difference(objs)
708 debug('deps: Expanded target %s includes of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
709 objs = objs.union(diff)
710 setattr(t, 'includes_objects', objs)
713 def reduce_objects(bld, tgt_list):
714 '''reduce objects by looking for indirect object dependencies'''
718 t.extended_objects = None
722 for type in ['BINARY', 'PYTHON', 'LIBRARY']:
724 if t.samba_type != type: continue
725 # if we will indirectly link to a target then we don't need it
726 new = t.final_objects.copy()
727 for l in t.final_libs:
728 t2 = bld.get_tgen_by_name(l)
729 t2_obj = extended_objects(bld, t2, set())
730 dup = new.intersection(t2_obj)
731 if t.sname in rely_on:
732 dup = dup.difference(rely_on[t.sname])
734 debug('deps: removing dups from %s of type %s: %s also in %s %s',
735 t.sname, t.samba_type, dup, t2.samba_type, l)
736 new = new.difference(dup)
740 rely_on[l] = rely_on[l].union(dup)
741 t.final_objects = new
746 # add back in any objects that were relied upon by the reduction rules
748 t = bld.get_tgen_by_name(r)
749 t.final_objects = t.final_objects.union(rely_on[r])
754 def show_library_loop(bld, lib1, lib2, path, seen):
755 '''show the detailed path of a library loop between lib1 and lib2'''
757 t = bld.get_tgen_by_name(lib1)
758 if not lib2 in getattr(t, 'final_libs', set()):
761 for d in t.samba_deps_extended:
765 path2 = path + '=>' + d
767 Logs.warn('library loop path: ' + path2)
769 show_library_loop(bld, d, lib2, path2, seen)
773 def calculate_final_deps(bld, tgt_list, loops):
774 '''calculate the final library and object dependencies'''
776 # start with the maximum possible list
777 t.final_libs = t.direct_libs.union(indirect_libs(bld, t, set(), loops))
778 t.final_objects = t.direct_objects.union(indirect_objects(bld, t, set(), loops))
781 # don't depend on ourselves
782 if t.sname in t.final_libs:
783 t.final_libs.remove(t.sname)
784 if t.sname in t.final_objects:
785 t.final_objects.remove(t.sname)
787 # handle any non-shared binaries
789 if t.samba_type == 'BINARY' and bld.NONSHARED_BINARY(t.sname):
790 subsystem_list = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
791 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
793 # replace lib deps with objlist deps
794 for l in t.final_libs:
795 objname = l + '.objlist'
796 t2 = bld.get_tgen_by_name(objname)
798 Logs.error('ERROR: subsystem %s not found' % objname)
800 t.final_objects.add(objname)
801 t.final_objects = t.final_objects.union(extended_objects(bld, t2, set()))
802 if l in subsystem_list:
803 # its a subsystem - we also need the contents of any modules
804 for d in subsystem_list[l]:
805 module_name = d['TARGET']
806 if targets[module_name] == 'LIBRARY':
807 objname = module_name + '.objlist'
808 elif targets[module_name] == 'SUBSYSTEM':
809 objname = module_name
812 t2 = bld.get_tgen_by_name(objname)
814 Logs.error('ERROR: subsystem %s not found' % objname)
816 t.final_objects.add(objname)
817 t.final_objects = t.final_objects.union(extended_objects(bld, t2, set()))
820 # find any library loops
822 if t.samba_type in ['LIBRARY', 'PYTHON']:
823 for l in t.final_libs.copy():
824 t2 = bld.get_tgen_by_name(l)
825 if t.sname in t2.final_libs:
826 if getattr(bld.env, "ALLOW_CIRCULAR_LIB_DEPENDENCIES", False):
827 # we could break this in either direction. If one of the libraries
828 # has a version number, and will this be distributed publicly, then
829 # we should make it the lower level library in the DAG
830 Logs.warn('deps: removing library loop %s from %s' % (t.sname, t2.sname))
831 dependency_loop(loops, t, t2.sname)
832 t2.final_libs.remove(t.sname)
834 Logs.error('ERROR: circular library dependency between %s and %s'
835 % (t.sname, t2.sname))
836 show_library_loop(bld, t.sname, t2.sname, t.sname, set())
837 show_library_loop(bld, t2.sname, t.sname, t2.sname, set())
841 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
843 # we now need to make corrections for any library loops we broke up
844 # any target that depended on the target of the loop and doesn't
845 # depend on the source of the loop needs to get the loop source added
846 for type in ['BINARY','PYTHON','LIBRARY','BINARY']:
848 if t.samba_type != type: continue
850 if loop in t.final_libs:
851 diff = loops[loop].difference(t.final_libs)
856 # make sure we don't recreate the loop again!
857 for d in diff.copy():
858 t2 = bld.get_tgen_by_name(d)
859 if t2.samba_type == 'LIBRARY':
860 if t.sname in t2.final_libs:
861 debug('deps: removing expansion %s from %s', d, t.sname)
864 debug('deps: Expanded target %s by loop %s libraries (loop %s) %s', t.sname, loop,
866 t.final_libs = t.final_libs.union(diff)
868 # remove objects that are also available in linked libs
870 while reduce_objects(bld, tgt_list):
873 Logs.warn("WARNING: Unable to remove all inter-target object duplicates")
875 debug('deps: Object reduction took %u iterations', count)
877 # add in any syslib dependencies
879 if not t.samba_type in ['BINARY','PYTHON','LIBRARY','SUBSYSTEM']:
882 for d in t.final_objects:
883 t2 = bld.get_tgen_by_name(d)
884 syslibs = syslibs.union(t2.direct_syslibs)
885 # this adds the indirect syslibs as well, which may not be needed
886 # depending on the linker flags
887 for d in t.final_libs:
888 t2 = bld.get_tgen_by_name(d)
889 syslibs = syslibs.union(t2.direct_syslibs)
890 t.final_syslibs = syslibs
893 # find any unresolved library loops
894 lib_loop_error = False
896 if t.samba_type in ['LIBRARY', 'PYTHON']:
897 for l in t.final_libs.copy():
898 t2 = bld.get_tgen_by_name(l)
899 if t.sname in t2.final_libs:
900 Logs.error('ERROR: Unresolved library loop %s from %s' % (t.sname, t2.sname))
901 lib_loop_error = True
905 debug('deps: removed duplicate dependencies')
908 def show_dependencies(bld, target, seen):
909 '''recursively show the dependencies of target'''
914 t = bld.get_tgen_by_name(target)
916 Logs.error("ERROR: Unable to find target '%s'" % target)
919 Logs.info('%s(OBJECTS): %s' % (target, t.direct_objects))
920 Logs.info('%s(LIBS): %s' % (target, t.direct_libs))
921 Logs.info('%s(SYSLIBS): %s' % (target, t.direct_syslibs))
925 for t2 in t.direct_objects:
926 show_dependencies(bld, t2, seen)
929 def show_object_duplicates(bld, tgt_list):
930 '''show a list of object files that are included in more than
931 one library or binary'''
933 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
937 Logs.info("showing duplicate objects")
940 if not targets[t.sname] in [ 'LIBRARY', 'PYTHON' ]:
942 for n in getattr(t, 'final_objects', set()):
943 t2 = bld.get_tgen_by_name(n)
946 used_by[n].add(t.sname)
949 if len(used_by[n]) > 1:
950 Logs.info("target '%s' is used by %s" % (n, used_by[n]))
952 Logs.info("showing indirect dependency counts (sorted by count)")
954 def indirect_count(t1, t2):
955 return len(t2.indirect_objects) - len(t1.indirect_objects)
957 sorted_list = sorted(tgt_list, cmp=indirect_count)
958 for t in sorted_list:
959 if len(t.indirect_objects) > 1:
960 Logs.info("%s depends on %u indirect objects" % (t.sname, len(t.indirect_objects)))
963 ######################################################################
964 # this provides a way to save our dependency calculations between runs
966 savedeps_inputs = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags',
967 'source', 'grouping_library', 'samba_ldflags', 'allow_undefined_symbols',
968 'use_global_deps', 'global_include' ]
969 savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes',
970 'ccflags', 'ldflags', 'samba_deps_extended', 'final_libs']
971 savedeps_outenv = ['INC_PATHS']
972 savedeps_envvars = ['NONSHARED_BINARIES', 'GLOBAL_DEPENDENCIES', 'EXTRA_CFLAGS', 'EXTRA_LDFLAGS', 'EXTRA_INCLUDES' ]
973 savedeps_caches = ['GLOBAL_DEPENDENCIES', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
974 savedeps_files = ['buildtools/wafsamba/samba_deps.py']
976 def save_samba_deps(bld, tgt_list):
977 '''save the dependency calculations between builds, to make
978 further builds faster'''
979 denv = Environment.Environment()
981 denv.version = savedeps_version
982 denv.savedeps_inputs = savedeps_inputs
983 denv.savedeps_outputs = savedeps_outputs
991 for f in savedeps_files:
992 denv.files[f] = os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime
994 for c in savedeps_caches:
995 denv.caches[c] = LOCAL_CACHE(bld, c)
997 for e in savedeps_envvars:
998 denv.envvar[e] = bld.env[e]
1001 # save all the input attributes for each target
1003 for attr in savedeps_inputs:
1004 v = getattr(t, attr, None)
1008 denv.input[t.sname] = tdeps
1010 # save all the output attributes for each target
1012 for attr in savedeps_outputs:
1013 v = getattr(t, attr, None)
1017 denv.output[t.sname] = tdeps
1020 for attr in savedeps_outenv:
1022 tdeps[attr] = t.env[attr]
1024 denv.outenv[t.sname] = tdeps
1026 depsfile = os.path.join(bld.bdir, "sambadeps")
1027 denv.store_fast(depsfile)
1031 def load_samba_deps(bld, tgt_list):
1032 '''load a previous set of build dependencies if possible'''
1033 depsfile = os.path.join(bld.bdir, "sambadeps")
1034 denv = Environment.Environment()
1036 debug('deps: checking saved dependencies')
1037 denv.load_fast(depsfile)
1038 if (denv.version != savedeps_version or
1039 denv.savedeps_inputs != savedeps_inputs or
1040 denv.savedeps_outputs != savedeps_outputs):
1045 # check if critical files have changed
1046 for f in savedeps_files:
1047 if f not in denv.files:
1049 if denv.files[f] != os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime:
1052 # check if caches are the same
1053 for c in savedeps_caches:
1054 if c not in denv.caches or denv.caches[c] != LOCAL_CACHE(bld, c):
1057 # check if caches are the same
1058 for e in savedeps_envvars:
1059 if e not in denv.envvar or denv.envvar[e] != bld.env[e]:
1062 # check inputs are the same
1065 for attr in savedeps_inputs:
1066 v = getattr(t, attr, None)
1069 if t.sname in denv.input:
1070 olddeps = denv.input[t.sname]
1073 if tdeps != olddeps:
1074 #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
1077 # put outputs in place
1079 if not t.sname in denv.output: continue
1080 tdeps = denv.output[t.sname]
1082 setattr(t, a, tdeps[a])
1084 # put output env vars in place
1086 if not t.sname in denv.outenv: continue
1087 tdeps = denv.outenv[t.sname]
1091 debug('deps: loaded saved dependencies')
1096 def check_project_rules(bld):
1097 '''check the project rules - ensuring the targets are sane'''
1102 tgt_list = get_tgt_list(bld)
1104 add_samba_attributes(bld, tgt_list)
1106 force_project_rules = (Options.options.SHOWDEPS or
1107 Options.options.SHOW_DUPLICATES)
1109 if not force_project_rules and load_samba_deps(bld, tgt_list):
1113 tstart = time.clock()
1115 bld.new_rules = True
1116 Logs.info("Checking project rules ...")
1118 debug('deps: project rules checking started')
1120 expand_subsystem_deps(bld)
1122 debug("deps: expand_subsystem_deps: %f" % (time.clock() - tstart))
1124 replace_grouping_libraries(bld, tgt_list)
1126 debug("deps: replace_grouping_libraries: %f" % (time.clock() - tstart))
1128 build_direct_deps(bld, tgt_list)
1130 debug("deps: build_direct_deps: %f" % (time.clock() - tstart))
1132 break_dependency_loops(bld, tgt_list)
1134 debug("deps: break_dependency_loops: %f" % (time.clock() - tstart))
1136 if Options.options.SHOWDEPS:
1137 show_dependencies(bld, Options.options.SHOWDEPS, set())
1139 calculate_final_deps(bld, tgt_list, loops)
1141 debug("deps: calculate_final_deps: %f" % (time.clock() - tstart))
1143 if Options.options.SHOW_DUPLICATES:
1144 show_object_duplicates(bld, tgt_list)
1146 # run the various attribute generators
1147 for f in [ build_dependencies, build_includes, add_init_functions ]:
1148 debug('deps: project rules checking %s', f)
1149 for t in tgt_list: f(t)
1150 debug("deps: %s: %f" % (f, time.clock() - tstart))
1152 debug('deps: project rules stage1 completed')
1154 #check_orphaned_targets(bld, tgt_list)
1156 if not check_duplicate_sources(bld, tgt_list):
1157 Logs.error("Duplicate sources present - aborting")
1160 debug("deps: check_duplicate_sources: %f" % (time.clock() - tstart))
1162 if not check_group_ordering(bld, tgt_list):
1163 Logs.error("Bad group ordering - aborting")
1166 debug("deps: check_group_ordering: %f" % (time.clock() - tstart))
1168 show_final_deps(bld, tgt_list)
1170 debug("deps: show_final_deps: %f" % (time.clock() - tstart))
1172 debug('deps: project rules checking completed - %u targets checked',
1175 if not bld.is_install:
1176 save_samba_deps(bld, tgt_list)
1178 debug("deps: save_samba_deps: %f" % (time.clock() - tstart))
1180 Logs.info("Project rules pass")
1183 def CHECK_PROJECT_RULES(bld):
1184 '''enable checking of project targets for sanity'''
1185 if bld.env.added_project_rules:
1187 bld.env.added_project_rules = True
1188 bld.add_pre_fun(check_project_rules)
1189 Build.BuildContext.CHECK_PROJECT_RULES = CHECK_PROJECT_RULES