s3: Remove a use of smbd_server_fd
[Samba/gbeck.git] / buildtools / wafsamba / samba_deps.py
blob94b7484def7a27ecf7e7ba38f5b8b6dfc1113700
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
8 @conf
9 def ADD_GLOBAL_DEPENDENCY(ctx, dep):
10 '''add a dependency for all binaries and libraries'''
11 if not 'GLOBAL_DEPENDENCIES' in ctx.env:
12 ctx.env.GLOBAL_DEPENDENCIES = []
13 ctx.env.GLOBAL_DEPENDENCIES.append(dep)
16 def TARGET_ALIAS(bld, target, alias):
17 '''define an alias for a target name'''
18 cache = LOCAL_CACHE(bld, 'TARGET_ALIAS')
19 if alias in cache:
20 Logs.error("Target alias %s already set to %s : newalias %s" % (alias, cache[alias], target))
21 sys.exit(1)
22 cache[alias] = target
23 Build.BuildContext.TARGET_ALIAS = TARGET_ALIAS
26 @conf
27 def SET_SYSLIB_DEPS(conf, target, deps):
28 '''setup some implied dependencies for a SYSLIB'''
29 cache = LOCAL_CACHE(conf, 'SYSLIB_DEPS')
30 cache[target] = deps
33 def EXPAND_ALIAS(bld, target):
34 '''expand a target name via an alias'''
35 aliases = LOCAL_CACHE(bld, 'TARGET_ALIAS')
36 if target in aliases:
37 return aliases[target]
38 return target
39 Build.BuildContext.EXPAND_ALIAS = EXPAND_ALIAS
42 def expand_subsystem_deps(bld):
43 '''expand the reverse dependencies resulting from subsystem
44 attributes of modules'''
45 subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
46 aliases = LOCAL_CACHE(bld, 'TARGET_ALIAS')
47 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
49 for s in subsystems:
50 if s in aliases:
51 s = aliases[s]
52 bld.ASSERT(s in targets, "Subsystem target %s not declared" % s)
53 type = targets[s]
54 if type == 'DISABLED' or type == 'EMPTY':
55 continue
57 t = bld.name_to_obj(s, bld.env)
58 for d in subsystems[s]:
59 type = targets[d['TARGET']]
60 if type != 'DISABLED' and type != 'EMPTY':
61 bld.ASSERT(t is not None,
62 "Subsystem target %s for %s (%s) not found" % (s, d['TARGET'], type))
63 t.samba_deps_extended.append(d['TARGET'])
64 t2 = bld.name_to_obj(d['TARGET'], bld.env)
65 t2.samba_includes_extended.extend(t.samba_includes_extended)
66 t2.samba_deps_extended.extend(t.samba_deps_extended)
67 t.samba_deps_extended = unique_list(t.samba_deps_extended)
71 def build_dependencies(self):
72 '''This builds the dependency list for a target. It runs after all the targets are declared
74 The reason this is not just done in the SAMBA_*() rules is that we have no way of knowing
75 the full dependency list for a target until we have all of the targets declared.
76 '''
78 if self.samba_type in ['LIBRARY', 'BINARY', 'PYTHON']:
79 self.uselib = list(self.final_syslibs)
80 self.uselib_local = list(self.final_libs)
81 self.add_objects = list(self.final_objects)
83 # extra link flags from pkg_config
84 libs = self.final_syslibs.copy()
86 (ccflags, ldflags) = library_flags(self, list(libs))
87 new_ldflags = getattr(self, 'ldflags', [])
88 new_ldflags.extend(ldflags)
89 self.ldflags = new_ldflags
91 debug('deps: computed dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
92 self.sname, self.uselib, self.uselib_local, self.add_objects)
94 if self.samba_type in ['SUBSYSTEM']:
95 # this is needed for the ccflags of libs that come from pkg_config
96 self.uselib = list(self.direct_syslibs)
98 if getattr(self, 'uselib', None):
99 up_list = []
100 for l in self.uselib:
101 up_list.append(l.upper())
102 self.uselib = up_list
104 def build_includes(self):
105 '''This builds the right set of includes for a target.
107 One tricky part of this is that the includes= attribute for a
108 target needs to use paths which are relative to that targets
109 declaration directory (which we can get at via t.path).
111 The way this works is the includes list gets added as
112 samba_includes in the main build task declaration. Then this
113 function runs after all of the tasks are declared, and it
114 processes the samba_includes attribute to produce a includes=
115 attribute
118 if getattr(self, 'samba_includes', None) is None:
119 return
121 bld = self.bld
123 inc_deps = includes_objects(bld, self, set(), {})
125 includes = []
127 # maybe add local includes
128 if getattr(self, 'local_include', True) == True and getattr(self, 'local_include_first', True):
129 includes.append('.')
131 includes.extend(self.samba_includes_extended)
133 if 'EXTRA_INCLUDES' in bld.env:
134 includes.extend(bld.env['EXTRA_INCLUDES'])
136 includes.append('#')
138 inc_set = set()
139 inc_abs = []
141 for d in inc_deps:
142 t = bld.name_to_obj(d, bld.env)
143 bld.ASSERT(t is not None, "Unable to find dependency %s for %s" % (d, self.sname))
144 inclist = getattr(t, 'samba_includes_extended', [])
145 if getattr(t, 'local_include', True) == True:
146 inclist.append('.')
147 if inclist == []:
148 continue
149 tpath = t.samba_abspath
150 for inc in inclist:
151 npath = tpath + '/' + inc
152 if not npath in inc_set:
153 inc_abs.append(npath)
154 inc_set.add(npath)
156 mypath = self.path.abspath(bld.env)
157 for inc in inc_abs:
158 relpath = os_path_relpath(inc, mypath)
159 includes.append(relpath)
161 if getattr(self, 'local_include', True) == True and not getattr(self, 'local_include_first', True):
162 includes.append('.')
164 # now transform the includes list to be relative to the top directory
165 # which is represented by '#' in waf. This allows waf to cache the
166 # includes lists more efficiently
167 includes_top = []
168 for i in includes:
169 if i[0] == '#':
170 # some are already top based
171 includes_top.append(i)
172 continue
173 absinc = os.path.join(self.path.abspath(), i)
174 relinc = os_path_relpath(absinc, self.bld.srcnode.abspath())
175 includes_top.append('#' + relinc)
177 self.includes = unique_list(includes_top)
178 debug('deps: includes for target %s: includes=%s',
179 self.sname, self.includes)
184 def add_init_functions(self):
185 '''This builds the right set of init functions'''
187 bld = self.bld
189 subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
191 # cope with the separated object lists from BINARY and LIBRARY targets
192 sname = self.sname
193 if sname.endswith('.objlist'):
194 sname = sname[0:-8]
196 modules = []
197 if sname in subsystems:
198 modules.append(sname)
200 m = getattr(self, 'samba_modules', None)
201 if m is not None:
202 modules.extend(TO_LIST(m))
204 m = getattr(self, 'samba_subsystem', None)
205 if m is not None:
206 modules.append(m)
208 if modules == []:
209 return
211 sentinal = getattr(self, 'init_function_sentinal', 'NULL')
213 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
215 cflags = getattr(self, 'samba_cflags', [])[:]
216 for m in modules:
217 bld.ASSERT(m in subsystems,
218 "No init_function defined for module '%s' in target '%s'" % (m, self.sname))
219 init_fn_list = []
220 for d in subsystems[m]:
221 if targets[d['TARGET']] != 'DISABLED':
222 init_fn_list.append(d['INIT_FUNCTION'])
223 if init_fn_list == []:
224 cflags.append('-DSTATIC_%s_MODULES=%s' % (m, sentinal))
225 else:
226 cflags.append('-DSTATIC_%s_MODULES=%s' % (m, ','.join(init_fn_list) + ',' + sentinal))
227 self.ccflags = cflags
231 def check_duplicate_sources(bld, tgt_list):
232 '''see if we are compiling the same source file into multiple
233 subsystem targets for the same library or binary'''
235 debug('deps: checking for duplicate sources')
237 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
238 ret = True
240 seen = set()
242 for t in tgt_list:
243 obj_sources = getattr(t, 'source', '')
244 tpath = os.path.normpath(os_path_relpath(t.path.abspath(bld.env), t.env.BUILD_DIRECTORY + '/default'))
245 obj_sources = bld.SUBDIR(tpath, obj_sources)
246 t.samba_source_set = set(TO_LIST(obj_sources))
248 for t in tgt_list:
249 if not targets[t.sname] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
250 continue
252 sources = []
253 for obj in t.add_objects:
254 t2 = t.bld.name_to_obj(obj, bld.env)
255 source_set = getattr(t2, 'samba_source_set', set())
256 sources.append( { 'dep':obj, 'src':source_set} )
257 for s in sources:
258 for s2 in sources:
259 if s['dep'] == s2['dep']: continue
260 common = s['src'].intersection(s2['src'])
261 if common.difference(seen):
262 Logs.error("Target %s has duplicate source files in %s and %s : %s" % (t.sname,
263 s['dep'], s2['dep'],
264 common))
265 seen = seen.union(common)
266 ret = False
267 return ret
270 def check_orpaned_targets(bld, tgt_list):
271 '''check if any build targets are orphaned'''
273 target_dict = LOCAL_CACHE(bld, 'TARGET_TYPE')
275 debug('deps: checking for orphaned targets')
277 for t in tgt_list:
278 if getattr(t, 'samba_used', False) == True:
279 continue
280 type = target_dict[t.sname]
281 if not type in ['BINARY', 'LIBRARY', 'MODULE', 'ET', 'PYTHON']:
282 if re.search('^PIDL_', t.sname) is None:
283 Logs.warn("Target %s of type %s is unused by any other target" % (t.sname, type))
286 def check_group_ordering(bld, tgt_list):
287 '''see if we have any dependencies that violate the group ordering
289 It is an error for a target to depend on a target from a later
290 build group
293 def group_name(g):
294 tm = bld.task_manager
295 return [x for x in tm.groups_names if id(tm.groups_names[x]) == id(g)][0]
297 for g in bld.task_manager.groups:
298 gname = group_name(g)
299 for t in g.tasks_gen:
300 t.samba_group = gname
302 grp_map = {}
303 idx = 0
304 for g in bld.task_manager.groups:
305 name = group_name(g)
306 grp_map[name] = idx
307 idx += 1
309 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
311 ret = True
312 for t in tgt_list:
313 tdeps = getattr(t, 'add_objects', []) + getattr(t, 'uselib_local', [])
314 for d in tdeps:
315 t2 = bld.name_to_obj(d, bld.env)
316 if t2 is None:
317 continue
318 map1 = grp_map[t.samba_group]
319 map2 = grp_map[t2.samba_group]
321 if map2 > map1:
322 Logs.error("Target %r in build group %r depends on target %r from later build group %r" % (
323 t.sname, t.samba_group, t2.sname, t2.samba_group))
324 ret = False
326 return ret
329 def show_final_deps(bld, tgt_list):
330 '''show the final dependencies for all targets'''
332 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
334 for t in tgt_list:
335 if not targets[t.sname] in ['LIBRARY', 'BINARY', 'PYTHON']:
336 continue
337 debug('deps: final dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
338 t.sname, t.uselib, t.uselib_local, t.add_objects)
341 def add_samba_attributes(bld, tgt_list):
342 '''ensure a target has a the required samba attributes'''
344 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
346 for t in tgt_list:
347 if t.name != '':
348 t.sname = t.name
349 else:
350 t.sname = t.target
351 t.samba_type = targets[t.sname]
352 t.samba_abspath = t.path.abspath(bld.env)
353 t.samba_deps_extended = t.samba_deps[:]
354 t.samba_includes_extended = TO_LIST(t.samba_includes)[:]
355 t.ccflags = getattr(t, 'samba_cflags', '')
358 def build_direct_deps(bld, tgt_list):
359 '''build the direct_objects and direct_libs sets for each target'''
361 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
362 syslib_deps = LOCAL_CACHE(bld, 'SYSLIB_DEPS')
363 global_deps = bld.env.GLOBAL_DEPENDENCIES
365 for t in tgt_list:
366 t.direct_objects = set()
367 t.direct_libs = set()
368 t.direct_syslibs = set()
369 deps = t.samba_deps_extended
370 if getattr(t, 'samba_use_global_deps', False):
371 deps.extend(global_deps)
372 for d in deps:
373 d = EXPAND_ALIAS(bld, d)
374 if d == t.sname: continue
375 if not d in targets:
376 Logs.error("Unknown dependency %s in %s" % (d, t.sname))
377 sys.exit(1)
378 if targets[d] in [ 'EMPTY', 'DISABLED' ]:
379 continue
380 if targets[d] == 'SYSLIB':
381 t.direct_syslibs.add(d)
382 if d in syslib_deps:
383 for implied in TO_LIST(syslib_deps[d]):
384 if BUILTIN_LIBRARY(bld, implied):
385 t.direct_objects.add(implied)
386 elif targets[implied] == 'SYSLIB':
387 t.direct_syslibs.add(implied)
388 elif targets[implied] in ['LIBRARY', 'MODULE']:
389 t.direct_libs.add(implied)
390 else:
391 Logs.error('Implied dependency %s in %s is of type %s' % (
392 implied, t.sname, targets[implied]))
393 sys.exit(1)
394 continue
395 t2 = bld.name_to_obj(d, bld.env)
396 if t2 is None:
397 Logs.error("no task %s of type %s in %s" % (d, targets[d], t.sname))
398 sys.exit(1)
399 if t2.samba_type in [ 'LIBRARY', 'MODULE' ]:
400 t.direct_libs.add(d)
401 elif t2.samba_type in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]:
402 t.direct_objects.add(d)
403 debug('deps: built direct dependencies')
406 def dependency_loop(loops, t, target):
407 '''add a dependency loop to the loops dictionary'''
408 if t.sname == target:
409 return
410 if not target in loops:
411 loops[target] = set()
412 if not t.sname in loops[target]:
413 loops[target].add(t.sname)
416 def indirect_libs(bld, t, chain, loops):
417 '''recursively calculate the indirect library dependencies for a target
419 An indirect library is a library that results from a dependency on
420 a subsystem
423 ret = getattr(t, 'indirect_libs', None)
424 if ret is not None:
425 return ret
427 ret = set()
428 for obj in t.direct_objects:
429 if obj in chain:
430 dependency_loop(loops, t, obj)
431 continue
432 chain.add(obj)
433 t2 = bld.name_to_obj(obj, bld.env)
434 r2 = indirect_libs(bld, t2, chain, loops)
435 chain.remove(obj)
436 ret = ret.union(t2.direct_libs)
437 ret = ret.union(r2)
439 for obj in indirect_objects(bld, t, set(), loops):
440 if obj in chain:
441 dependency_loop(loops, t, obj)
442 continue
443 chain.add(obj)
444 t2 = bld.name_to_obj(obj, bld.env)
445 r2 = indirect_libs(bld, t2, chain, loops)
446 chain.remove(obj)
447 ret = ret.union(t2.direct_libs)
448 ret = ret.union(r2)
450 t.indirect_libs = ret
452 return ret
455 def indirect_objects(bld, t, chain, loops):
456 '''recursively calculate the indirect object dependencies for a target
458 indirect objects are the set of objects from expanding the
459 subsystem dependencies
462 ret = getattr(t, 'indirect_objects', None)
463 if ret is not None: return ret
465 ret = set()
466 for lib in t.direct_objects:
467 if lib in chain:
468 dependency_loop(loops, t, lib)
469 continue
470 chain.add(lib)
471 t2 = bld.name_to_obj(lib, bld.env)
472 r2 = indirect_objects(bld, t2, chain, loops)
473 chain.remove(lib)
474 ret = ret.union(t2.direct_objects)
475 ret = ret.union(r2)
477 t.indirect_objects = ret
478 return ret
481 def extended_objects(bld, t, chain):
482 '''recursively calculate the extended object dependencies for a target
484 extended objects are the union of:
485 - direct objects
486 - indirect objects
487 - direct and indirect objects of all direct and indirect libraries
490 ret = getattr(t, 'extended_objects', None)
491 if ret is not None: return ret
493 ret = set()
494 ret = ret.union(t.final_objects)
496 for lib in t.final_libs:
497 if lib in chain:
498 continue
499 t2 = bld.name_to_obj(lib, bld.env)
500 chain.add(lib)
501 r2 = extended_objects(bld, t2, chain)
502 chain.remove(lib)
503 ret = ret.union(t2.final_objects)
504 ret = ret.union(r2)
506 t.extended_objects = ret
507 return ret
510 def includes_objects(bld, t, chain, inc_loops):
511 '''recursively calculate the includes object dependencies for a target
513 includes dependencies come from either library or object dependencies
515 ret = getattr(t, 'includes_objects', None)
516 if ret is not None:
517 return ret
519 ret = t.direct_objects.copy()
520 ret = ret.union(t.direct_libs)
522 for obj in t.direct_objects:
523 if obj in chain:
524 dependency_loop(inc_loops, t, obj)
525 continue
526 chain.add(obj)
527 t2 = bld.name_to_obj(obj, bld.env)
528 r2 = includes_objects(bld, t2, chain, inc_loops)
529 chain.remove(obj)
530 ret = ret.union(t2.direct_objects)
531 ret = ret.union(r2)
533 for lib in t.direct_libs:
534 if lib in chain:
535 dependency_loop(inc_loops, t, lib)
536 continue
537 chain.add(lib)
538 t2 = bld.name_to_obj(lib, bld.env)
539 if t2 is None:
540 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
541 Logs.error('Target %s of type %s not found in direct_libs for %s' % (
542 lib, targets[lib], t.sname))
543 sys.exit(1)
544 r2 = includes_objects(bld, t2, chain, inc_loops)
545 chain.remove(lib)
546 ret = ret.union(t2.direct_objects)
547 ret = ret.union(r2)
549 t.includes_objects = ret
550 return ret
553 def break_dependency_loops(bld, tgt_list):
554 '''find and break dependency loops'''
555 loops = {}
556 inc_loops = {}
558 # build up the list of loops
559 for t in tgt_list:
560 indirect_objects(bld, t, set(), loops)
561 indirect_libs(bld, t, set(), loops)
562 includes_objects(bld, t, set(), inc_loops)
564 # break the loops
565 for t in tgt_list:
566 if t.sname in loops:
567 for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
568 objs = getattr(t, attr, set())
569 setattr(t, attr, objs.difference(loops[t.sname]))
571 for loop in loops:
572 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
574 for loop in inc_loops:
575 debug('deps: Found include loops for target %s : %s', loop, inc_loops[loop])
577 # expand the loops mapping by one level
578 for loop in loops.copy():
579 for tgt in loops[loop]:
580 if tgt in loops:
581 loops[loop] = loops[loop].union(loops[tgt])
583 for loop in inc_loops.copy():
584 for tgt in inc_loops[loop]:
585 if tgt in inc_loops:
586 inc_loops[loop] = inc_loops[loop].union(inc_loops[tgt])
589 # expand indirect subsystem and library loops
590 for loop in loops.copy():
591 t = bld.name_to_obj(loop, bld.env)
592 if t.samba_type in ['SUBSYSTEM']:
593 loops[loop] = loops[loop].union(t.indirect_objects)
594 loops[loop] = loops[loop].union(t.direct_objects)
595 if t.samba_type in ['LIBRARY','PYTHON']:
596 loops[loop] = loops[loop].union(t.indirect_libs)
597 loops[loop] = loops[loop].union(t.direct_libs)
598 if loop in loops[loop]:
599 loops[loop].remove(loop)
601 # expand indirect includes loops
602 for loop in inc_loops.copy():
603 t = bld.name_to_obj(loop, bld.env)
604 inc_loops[loop] = inc_loops[loop].union(t.includes_objects)
605 if loop in inc_loops[loop]:
606 inc_loops[loop].remove(loop)
608 # add in the replacement dependencies
609 for t in tgt_list:
610 for loop in loops:
611 for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
612 objs = getattr(t, attr, set())
613 if loop in objs:
614 diff = loops[loop].difference(objs)
615 if t.sname in diff:
616 diff.remove(t.sname)
617 if diff:
618 debug('deps: Expanded target %s of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
619 objs = objs.union(diff)
620 setattr(t, attr, objs)
622 for loop in inc_loops:
623 objs = getattr(t, 'includes_objects', set())
624 if loop in objs:
625 diff = inc_loops[loop].difference(objs)
626 if t.sname in diff:
627 diff.remove(t.sname)
628 if diff:
629 debug('deps: Expanded target %s includes of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
630 objs = objs.union(diff)
631 setattr(t, 'includes_objects', objs)
634 def reduce_objects(bld, tgt_list):
635 '''reduce objects by looking for indirect object dependencies'''
636 rely_on = {}
638 for t in tgt_list:
639 t.extended_objects = None
641 changed = False
643 for type in ['BINARY', 'PYTHON', 'LIBRARY']:
644 for t in tgt_list:
645 if t.samba_type != type: continue
646 # if we will indirectly link to a target then we don't need it
647 new = t.final_objects.copy()
648 for l in t.final_libs:
649 t2 = bld.name_to_obj(l, bld.env)
650 t2_obj = extended_objects(bld, t2, set())
651 dup = new.intersection(t2_obj)
652 if t.sname in rely_on:
653 dup = dup.difference(rely_on[t.sname])
654 if dup:
655 debug('deps: removing dups from %s of type %s: %s also in %s %s',
656 t.sname, t.samba_type, dup, t2.samba_type, l)
657 new = new.difference(dup)
658 changed = True
659 if not l in rely_on:
660 rely_on[l] = set()
661 rely_on[l] = rely_on[l].union(dup)
662 t.final_objects = new
664 if not changed:
665 return False
667 # add back in any objects that were relied upon by the reduction rules
668 for r in rely_on:
669 t = bld.name_to_obj(r, bld.env)
670 t.final_objects = t.final_objects.union(rely_on[r])
672 return True
675 def calculate_final_deps(bld, tgt_list, loops):
676 '''calculate the final library and object dependencies'''
677 for t in tgt_list:
678 # start with the maximum possible list
679 t.final_libs = t.direct_libs.union(indirect_libs(bld, t, set(), loops))
680 t.final_objects = t.direct_objects.union(indirect_objects(bld, t, set(), loops))
682 for t in tgt_list:
683 # don't depend on ourselves
684 if t.sname in t.final_libs:
685 t.final_libs.remove(t.sname)
686 if t.sname in t.final_objects:
687 t.final_objects.remove(t.sname)
689 # handle any non-shared binaries
690 for t in tgt_list:
691 if t.samba_type == 'BINARY' and bld.NONSHARED_BINARY(t.sname):
692 # replace lib deps with objlist deps
693 for l in t.final_libs:
694 objname = l + '.objlist'
695 t2 = bld.name_to_obj(objname, bld.env)
696 if t2 is None:
697 Logs.error('ERROR: subsystem %s not found' % objname)
698 sys.exit(1)
699 t.final_objects.add(objname)
700 t.final_objects = t.final_objects.union(extended_objects(bld, t2, set()))
701 t.final_libs = set()
703 # find any library loops
704 for t in tgt_list:
705 if t.samba_type in ['LIBRARY', 'PYTHON']:
706 for l in t.final_libs.copy():
707 t2 = bld.name_to_obj(l, bld.env)
708 if t.sname in t2.final_libs:
709 # we could break this in either direction. If one of the libraries
710 # has a version number, and will this be distributed publicly, then
711 # we should make it the lower level library in the DAG
712 debug('deps: removing library loop %s from %s', t.sname, t2.sname)
713 dependency_loop(loops, t, t2.sname)
714 t2.final_libs.remove(t.sname)
717 for loop in loops:
718 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
720 # we now need to make corrections for any library loops we broke up
721 # any target that depended on the target of the loop and doesn't
722 # depend on the source of the loop needs to get the loop source added
723 for type in ['BINARY','PYTHON','LIBRARY','BINARY']:
724 for t in tgt_list:
725 if t.samba_type != type: continue
726 for loop in loops:
727 if loop in t.final_libs:
728 diff = loops[loop].difference(t.final_libs)
729 if t.sname in diff:
730 diff.remove(t.sname)
731 if t.sname in diff:
732 diff.remove(t.sname)
733 # make sure we don't recreate the loop again!
734 for d in diff.copy():
735 t2 = bld.name_to_obj(d, bld.env)
736 if t2.samba_type == 'LIBRARY':
737 if t.sname in t2.final_libs:
738 debug('deps: removing expansion %s from %s', d, t.sname)
739 diff.remove(d)
740 if diff:
741 debug('deps: Expanded target %s by loop %s libraries (loop %s) %s', t.sname, loop,
742 loops[loop], diff)
743 t.final_libs = t.final_libs.union(diff)
745 # remove objects that are also available in linked libs
746 count = 0
747 while reduce_objects(bld, tgt_list):
748 count += 1
749 if count > 100:
750 Logs.warn("WARNING: Unable to remove all inter-target object duplicates")
751 break
752 debug('deps: Object reduction took %u iterations', count)
754 # add in any syslib dependencies
755 for t in tgt_list:
756 if not t.samba_type in ['BINARY','PYTHON','LIBRARY']:
757 continue
758 syslibs = set()
759 for d in t.final_objects:
760 t2 = bld.name_to_obj(d, bld.env)
761 syslibs = syslibs.union(t2.direct_syslibs)
762 # this adds the indirect syslibs as well, which may not be needed
763 # depending on the linker flags
764 for d in t.final_libs:
765 t2 = bld.name_to_obj(d, bld.env)
766 syslibs = syslibs.union(t2.direct_syslibs)
767 t.final_syslibs = syslibs
770 # find any unresolved library loops
771 lib_loop_error = False
772 for t in tgt_list:
773 if t.samba_type in ['LIBRARY', 'PYTHON']:
774 for l in t.final_libs.copy():
775 t2 = bld.name_to_obj(l, bld.env)
776 if t.sname in t2.final_libs:
777 Logs.error('ERROR: Unresolved library loop %s from %s' % (t.sname, t2.sname))
778 lib_loop_error = True
779 if lib_loop_error:
780 sys.exit(1)
782 debug('deps: removed duplicate dependencies')
785 ######################################################################
786 # this provides a way to save our dependency calculations between runs
787 savedeps_version = 3
788 savedeps_inputs = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags', 'source']
789 savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags']
790 savedeps_outenv = ['INC_PATHS']
791 savedeps_envvars = ['NONSHARED_BINARIES', 'GLOBAL_DEPENDENCIES']
792 savedeps_caches = ['GLOBAL_DEPENDENCIES', 'TARGET_ALIAS', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
793 savedeps_files = ['buildtools/wafsamba/samba_deps.py']
795 def save_samba_deps(bld, tgt_list):
796 '''save the dependency calculations between builds, to make
797 further builds faster'''
798 denv = Environment.Environment()
800 denv.version = savedeps_version
801 denv.savedeps_inputs = savedeps_inputs
802 denv.savedeps_outputs = savedeps_outputs
803 denv.input = {}
804 denv.output = {}
805 denv.outenv = {}
806 denv.caches = {}
807 denv.envvar = {}
808 denv.files = {}
810 for f in savedeps_files:
811 denv.files[f] = os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime
813 for c in savedeps_caches:
814 denv.caches[c] = LOCAL_CACHE(bld, c)
816 for e in savedeps_envvars:
817 denv.envvar[e] = bld.env[e]
819 for t in tgt_list:
820 # save all the input attributes for each target
821 tdeps = {}
822 for attr in savedeps_inputs:
823 v = getattr(t, attr, None)
824 if v is not None:
825 tdeps[attr] = v
826 if tdeps != {}:
827 denv.input[t.sname] = tdeps
829 # save all the output attributes for each target
830 tdeps = {}
831 for attr in savedeps_outputs:
832 v = getattr(t, attr, None)
833 if v is not None:
834 tdeps[attr] = v
835 if tdeps != {}:
836 denv.output[t.sname] = tdeps
838 tdeps = {}
839 for attr in savedeps_outenv:
840 if attr in t.env:
841 tdeps[attr] = t.env[attr]
842 if tdeps != {}:
843 denv.outenv[t.sname] = tdeps
845 depsfile = os.path.join(bld.bdir, "sambadeps")
846 denv.store(depsfile)
850 def load_samba_deps(bld, tgt_list):
851 '''load a previous set of build dependencies if possible'''
852 depsfile = os.path.join(bld.bdir, "sambadeps")
853 denv = Environment.Environment()
854 try:
855 debug('deps: checking saved dependencies')
856 denv.load(depsfile)
857 if (denv.version != savedeps_version or
858 denv.savedeps_inputs != savedeps_inputs or
859 denv.savedeps_outputs != savedeps_outputs):
860 return False
861 except:
862 return False
864 # check if critical files have changed
865 for f in savedeps_files:
866 if f not in denv.files:
867 return False
868 if denv.files[f] != os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime:
869 return False
871 # check if caches are the same
872 for c in savedeps_caches:
873 if c not in denv.caches or denv.caches[c] != LOCAL_CACHE(bld, c):
874 return False
876 # check if caches are the same
877 for e in savedeps_envvars:
878 if e not in denv.envvar or denv.envvar[e] != bld.env[e]:
879 return False
881 # check inputs are the same
882 for t in tgt_list:
883 tdeps = {}
884 for attr in savedeps_inputs:
885 v = getattr(t, attr, None)
886 if v is not None:
887 tdeps[attr] = v
888 if t.sname in denv.input:
889 olddeps = denv.input[t.sname]
890 else:
891 olddeps = {}
892 if tdeps != olddeps:
893 #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
894 return False
896 # put outputs in place
897 for t in tgt_list:
898 if not t.sname in denv.output: continue
899 tdeps = denv.output[t.sname]
900 for a in tdeps:
901 setattr(t, a, tdeps[a])
903 # put output env vars in place
904 for t in tgt_list:
905 if not t.sname in denv.outenv: continue
906 tdeps = denv.outenv[t.sname]
907 for a in tdeps:
908 t.env[a] = tdeps[a]
910 debug('deps: loaded saved dependencies')
911 return True
915 def check_project_rules(bld):
916 '''check the project rules - ensuring the targets are sane'''
918 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
919 loops = {}
920 inc_loops = {}
922 # build a list of task generators we are interested in
923 tgt_list = []
924 for tgt in targets:
925 type = targets[tgt]
926 if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON']:
927 continue
928 t = bld.name_to_obj(tgt, bld.env)
929 if t is None:
930 Logs.error("Target %s of type %s has no task generator" % (tgt, type))
931 sys.exit(1)
932 tgt_list.append(t)
934 add_samba_attributes(bld, tgt_list)
936 if load_samba_deps(bld, tgt_list):
937 return
939 Logs.info("Checking project rules ...")
941 debug('deps: project rules checking started')
943 expand_subsystem_deps(bld)
944 build_direct_deps(bld, tgt_list)
945 break_dependency_loops(bld, tgt_list)
946 calculate_final_deps(bld, tgt_list, loops)
948 # run the various attribute generators
949 for f in [ build_dependencies, build_includes, add_init_functions ]:
950 debug('deps: project rules checking %s', f)
951 for t in tgt_list: f(t)
953 debug('deps: project rules stage1 completed')
955 #check_orpaned_targets(bld, tgt_list)
957 if not check_duplicate_sources(bld, tgt_list):
958 Logs.error("Duplicate sources present - aborting")
959 sys.exit(1)
961 if not check_group_ordering(bld, tgt_list):
962 Logs.error("Bad group ordering - aborting")
963 sys.exit(1)
965 show_final_deps(bld, tgt_list)
967 debug('deps: project rules checking completed - %u targets checked',
968 len(tgt_list))
970 save_samba_deps(bld, tgt_list)
972 Logs.info("Project rules pass")
975 def CHECK_PROJECT_RULES(bld):
976 '''enable checking of project targets for sanity'''
977 if bld.env.added_project_rules:
978 return
979 bld.env.added_project_rules = True
980 bld.add_pre_fun(check_project_rules)
981 Build.BuildContext.CHECK_PROJECT_RULES = CHECK_PROJECT_RULES