s4-waf: added test for dlopen prototype
[Samba/gebeck_regimport.git] / buildtools / wafsamba / samba_deps.py
blob56b971a44733208e2cdacde620564104c94c585d
1 # Samba automatic dependency handling and project rules
3 import Build, os, re, Environment
4 from samba_utils import *
5 from samba_autoconf import *
7 @conf
8 def ADD_GLOBAL_DEPENDENCY(ctx, dep):
9 '''add a dependency for all binaries and libraries'''
10 if not 'GLOBAL_DEPENDENCIES' in ctx.env:
11 ctx.env.GLOBAL_DEPENDENCIES = []
12 ctx.env.GLOBAL_DEPENDENCIES.append(dep)
15 def TARGET_ALIAS(bld, target, alias):
16 '''define an alias for a target name'''
17 cache = LOCAL_CACHE(bld, 'TARGET_ALIAS')
18 if alias in cache:
19 print("Target alias %s already set to %s : newalias %s" % (alias, cache[alias], target))
20 raise
21 cache[alias] = target
22 Build.BuildContext.TARGET_ALIAS = TARGET_ALIAS
25 @conf
26 def SET_SYSLIB_DEPS(conf, target, deps):
27 '''setup some implied dependencies for a SYSLIB'''
28 cache = LOCAL_CACHE(conf, 'SYSLIB_DEPS')
29 cache[target] = deps
32 def EXPAND_ALIAS(bld, target):
33 '''expand a target name via an alias'''
34 aliases = LOCAL_CACHE(bld, 'TARGET_ALIAS')
35 if target in aliases:
36 return aliases[target]
37 return target
38 Build.BuildContext.EXPAND_ALIAS = EXPAND_ALIAS
41 def expand_subsystem_deps(bld):
42 '''expand the reverse dependencies resulting from subsystem
43 attributes of modules'''
44 subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
45 aliases = LOCAL_CACHE(bld, 'TARGET_ALIAS')
46 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
48 for s in subsystems:
49 if s in aliases:
50 s = aliases[s]
51 bld.ASSERT(s in targets, "Subsystem target %s not declared" % s)
52 type = targets[s]
53 if type == 'DISABLED' or type == 'EMPTY':
54 continue
56 t = bld.name_to_obj(s, bld.env)
57 bld.ASSERT(t is not None, "Subsystem target %s not found" % s)
58 for d in subsystems[s]:
59 type = targets[d['TARGET']]
60 if type != 'DISABLED' and type != 'EMPTY':
61 t.samba_deps_extended.append(d['TARGET'])
62 t2 = bld.name_to_obj(d['TARGET'], bld.env)
63 t2.samba_includes_extended.extend(t.samba_includes_extended)
64 t2.samba_deps_extended.extend(t.samba_deps_extended)
65 t.samba_deps_extended = unique_list(t.samba_deps_extended)
69 def build_dependencies(self):
70 '''This builds the dependency list for a target. It runs after all the targets are declared
72 The reason this is not just done in the SAMBA_*() rules is that we have no way of knowing
73 the full dependency list for a target until we have all of the targets declared.
74 '''
76 if self.samba_type in ['LIBRARY', 'BINARY', 'PYTHON']:
77 self.uselib = list(self.final_syslibs)
78 self.uselib_local = list(self.final_libs)
79 self.add_objects = list(self.final_objects)
81 # extra link flags from pkg_config
82 libs = self.final_syslibs.copy()
84 (ccflags, ldflags) = library_flags(self, list(libs))
85 new_ldflags = getattr(self, 'ldflags', [])
86 new_ldflags.extend(ldflags)
87 self.ldflags = new_ldflags
89 debug('deps: computed dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
90 self.sname, self.uselib, self.uselib_local, self.add_objects)
92 if self.samba_type in ['SUBSYSTEM']:
93 # this is needed for the ccflags of libs that come from pkg_config
94 self.uselib = list(self.direct_syslibs)
96 if getattr(self, 'uselib', None):
97 up_list = []
98 for l in self.uselib:
99 up_list.append(l.upper())
100 self.uselib = up_list
103 def build_includes(self):
104 '''This builds the right set of includes for a target.
106 One tricky part of this is that the includes= attribute for a
107 target needs to use paths which are relative to that targets
108 declaration directory (which we can get at via t.path).
110 The way this works is the includes list gets added as
111 samba_includes in the main build task declaration. Then this
112 function runs after all of the tasks are declared, and it
113 processes the samba_includes attribute to produce a includes=
114 attribute
117 if getattr(self, 'samba_includes', None) is None:
118 return
120 bld = self.bld
122 inc_deps = includes_objects(bld, self, set(), {})
124 includes = []
126 # maybe add local includes
127 if getattr(self, 'local_include', True) == True and getattr(self, 'local_include_first', True):
128 includes.append('.')
130 includes.extend(self.samba_includes_extended)
132 if 'EXTRA_INCLUDES' in bld.env:
133 includes.extend(bld.env['EXTRA_INCLUDES'])
135 includes.append('#')
137 inc_set = set()
138 inc_abs = []
140 for d in inc_deps:
141 t = bld.name_to_obj(d, bld.env)
142 bld.ASSERT(t is not None, "Unable to find dependency %s for %s" % (d, self.sname))
143 inclist = getattr(t, 'samba_includes_extended', [])
144 if getattr(t, 'local_include', True) == True:
145 inclist.append('.')
146 if inclist == []:
147 continue
148 tpath = t.samba_abspath
149 for inc in inclist:
150 npath = tpath + '/' + inc
151 if not npath in inc_set:
152 inc_abs.append(npath)
153 inc_set.add(npath)
155 mypath = self.path.abspath(bld.env)
156 for inc in inc_abs:
157 relpath = os_path_relpath(inc, mypath)
158 includes.append(relpath)
160 if getattr(self, 'local_include', True) == True and not getattr(self, 'local_include_first', True):
161 includes.append('.')
163 # now transform the includes list to be relative to the top directory
164 # which is represented by '#' in waf. This allows waf to cache the
165 # includes lists more efficiently
166 includes_top = []
167 for i in includes:
168 if i[0] == '#':
169 # some are already top based
170 includes_top.append(i)
171 continue
172 absinc = os.path.join(self.path.abspath(), i)
173 relinc = os_path_relpath(absinc, self.bld.srcnode.abspath())
174 includes_top.append('#' + relinc)
176 self.includes = unique_list(includes_top)
177 debug('deps: includes for target %s: includes=%s',
178 self.sname, self.includes)
183 def add_init_functions(self):
184 '''This builds the right set of init functions'''
186 bld = self.bld
188 subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
190 # cope with the separated object lists from BINARY and LIBRARY targets
191 sname = self.sname
192 if sname.endswith('.objlist'):
193 sname = sname[0:-8]
195 modules = []
196 if sname in subsystems:
197 modules.append(sname)
199 m = getattr(self, 'samba_modules', None)
200 if m is not None:
201 modules.extend(TO_LIST(m))
203 m = getattr(self, 'samba_subsystem', None)
204 if m is not None:
205 modules.append(m)
207 if modules == []:
208 return
210 sentinal = getattr(self, 'init_function_sentinal', 'NULL')
212 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
214 cflags = getattr(self, 'samba_cflags', [])[:]
215 for m in modules:
216 bld.ASSERT(m in subsystems,
217 "No init_function defined for module '%s' in target '%s'" % (m, self.sname))
218 init_fn_list = []
219 for d in subsystems[m]:
220 if targets[d['TARGET']] != 'DISABLED':
221 init_fn_list.append(d['INIT_FUNCTION'])
222 if init_fn_list == []:
223 cflags.append('-DSTATIC_%s_MODULES=%s' % (m, sentinal))
224 else:
225 cflags.append('-DSTATIC_%s_MODULES=%s' % (m, ','.join(init_fn_list) + ',' + sentinal))
226 self.ccflags = cflags
230 def check_duplicate_sources(bld, tgt_list):
231 '''see if we are compiling the same source file into multiple
232 subsystem targets for the same library or binary'''
234 debug('deps: checking for duplicate sources')
236 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
237 ret = True
239 seen = set()
241 for t in tgt_list:
242 obj_sources = getattr(t, 'source', '')
243 tpath = os_path_relpath(t.path.abspath(bld.env), t.env['BUILD_DIRECTORY'] + '/default')
244 obj_sources = bld.SUBDIR(tpath, obj_sources)
245 t.samba_source_set = set(TO_LIST(obj_sources))
247 for t in tgt_list:
248 if not targets[t.sname] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
249 continue
251 sources = []
252 for obj in t.add_objects:
253 t2 = t.bld.name_to_obj(obj, bld.env)
254 source_set = getattr(t2, 'samba_source_set', set())
255 sources.append( { 'dep':obj, 'src':source_set} )
256 for s in sources:
257 for s2 in sources:
258 if s['dep'] == s2['dep']: continue
259 common = s['src'].intersection(s2['src'])
260 if common.difference(seen):
261 print("Target %s has duplicate source files in %s and %s : %s" % (t.sname,
262 s['dep'], s2['dep'],
263 common))
264 seen = seen.union(common)
265 ret = False
266 return ret
269 def check_orpaned_targets(bld, tgt_list):
270 '''check if any build targets are orphaned'''
272 target_dict = LOCAL_CACHE(bld, 'TARGET_TYPE')
274 debug('deps: checking for orphaned targets')
276 for t in tgt_list:
277 if getattr(t, 'samba_used', False) == True:
278 continue
279 type = target_dict[t.sname]
280 if not type in ['BINARY', 'LIBRARY', 'MODULE', 'ET', 'PYTHON']:
281 if re.search('^PIDL_', t.sname) is None:
282 print "Target %s of type %s is unused by any other target" % (t.sname, type)
285 def show_final_deps(bld, tgt_list):
286 '''show the final dependencies for all targets'''
288 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
290 for t in tgt_list:
291 if not targets[t.sname] in ['LIBRARY', 'BINARY', 'PYTHON']:
292 continue
293 debug('deps: final dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
294 t.sname, t.uselib, t.uselib_local, t.add_objects)
297 def add_samba_attributes(bld, tgt_list):
298 '''ensure a target has a the required samba attributes'''
300 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
302 for t in tgt_list:
303 if t.name != '':
304 t.sname = t.name
305 else:
306 t.sname = t.target
307 t.samba_type = targets[t.sname]
308 t.samba_abspath = t.path.abspath(bld.env)
309 t.samba_deps_extended = t.samba_deps[:]
310 t.samba_includes_extended = TO_LIST(t.samba_includes)[:]
311 t.ccflags = getattr(t, 'samba_cflags', '')
314 def build_direct_deps(bld, tgt_list):
315 '''build the direct_objects and direct_libs sets for each target'''
317 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
318 syslib_deps = LOCAL_CACHE(bld, 'SYSLIB_DEPS')
319 global_deps = bld.env.GLOBAL_DEPENDENCIES
321 for t in tgt_list:
322 t.direct_objects = set()
323 t.direct_libs = set()
324 t.direct_syslibs = set()
325 deps = t.samba_deps_extended
326 deps.extend(global_deps)
327 for d in deps:
328 d = EXPAND_ALIAS(bld, d)
329 if d == t.sname: continue
330 if not d in targets:
331 print "Unknown dependency %s in %s" % (d, t.sname)
332 raise
333 if targets[d] in [ 'EMPTY', 'DISABLED' ]:
334 continue
335 if targets[d] == 'SYSLIB':
336 t.direct_syslibs.add(d)
337 if d in syslib_deps:
338 for implied in TO_LIST(syslib_deps[d]):
339 t.direct_libs.add(implied)
340 continue
341 t2 = bld.name_to_obj(d, bld.env)
342 if t2 is None:
343 print "no task %s type %s" % (d, targets[d])
344 if t2.samba_type in [ 'LIBRARY', 'MODULE' ]:
345 t.direct_libs.add(d)
346 elif t2.samba_type in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]:
347 t.direct_objects.add(d)
348 debug('deps: built direct dependencies')
351 def dependency_loop(loops, t, target):
352 '''add a dependency loop to the loops dictionary'''
353 if t.sname == target:
354 return
355 if not target in loops:
356 loops[target] = set()
357 if not t.sname in loops[target]:
358 loops[target].add(t.sname)
361 def indirect_libs(bld, t, chain, loops):
362 '''recursively calculate the indirect library dependencies for a target
364 An indirect library is a library that results from a dependency on
365 a subsystem
368 ret = getattr(t, 'indirect_libs', None)
369 if ret is not None:
370 return ret
372 ret = set()
373 for obj in t.direct_objects:
374 if obj in chain:
375 dependency_loop(loops, t, obj)
376 continue
377 chain.add(obj)
378 t2 = bld.name_to_obj(obj, bld.env)
379 r2 = indirect_libs(bld, t2, chain, loops)
380 chain.remove(obj)
381 ret = ret.union(t2.direct_libs)
382 ret = ret.union(r2)
384 for obj in indirect_objects(bld, t, set(), loops):
385 if obj in chain:
386 dependency_loop(loops, t, obj)
387 continue
388 chain.add(obj)
389 t2 = bld.name_to_obj(obj, bld.env)
390 r2 = indirect_libs(bld, t2, chain, loops)
391 chain.remove(obj)
392 ret = ret.union(t2.direct_libs)
393 ret = ret.union(r2)
395 t.indirect_libs = ret
397 return ret
400 def indirect_objects(bld, t, chain, loops):
401 '''recursively calculate the indirect object dependencies for a target
403 indirect objects are the set of objects from expanding the
404 subsystem dependencies
407 ret = getattr(t, 'indirect_objects', None)
408 if ret is not None: return ret
410 ret = set()
411 for lib in t.direct_objects:
412 if lib in chain:
413 dependency_loop(loops, t, lib)
414 continue
415 chain.add(lib)
416 t2 = bld.name_to_obj(lib, bld.env)
417 r2 = indirect_objects(bld, t2, chain, loops)
418 chain.remove(lib)
419 ret = ret.union(t2.direct_objects)
420 ret = ret.union(r2)
422 t.indirect_objects = ret
423 return ret
426 def extended_objects(bld, t, chain):
427 '''recursively calculate the extended object dependencies for a target
429 extended objects are the union of:
430 - direct objects
431 - indirect objects
432 - direct and indirect objects of all direct and indirect libraries
435 ret = getattr(t, 'extended_objects', None)
436 if ret is not None: return ret
438 ret = set()
439 ret = ret.union(t.direct_objects)
440 ret = ret.union(t.indirect_objects)
442 for lib in t.direct_libs:
443 if lib in chain:
444 continue
445 t2 = bld.name_to_obj(lib, bld.env)
446 chain.add(lib)
447 r2 = extended_objects(bld, t2, chain)
448 chain.remove(lib)
449 ret = ret.union(t2.direct_objects)
450 ret = ret.union(t2.indirect_objects)
451 ret = ret.union(r2)
453 t.extended_objects = ret
454 return ret
457 def includes_objects(bld, t, chain, inc_loops):
458 '''recursively calculate the includes object dependencies for a target
460 includes dependencies come from either library or object dependencies
462 ret = getattr(t, 'includes_objects', None)
463 if ret is not None:
464 return ret
466 ret = t.direct_objects.copy()
467 ret = ret.union(t.direct_libs)
469 for obj in t.direct_objects:
470 if obj in chain:
471 dependency_loop(inc_loops, t, obj)
472 continue
473 chain.add(obj)
474 t2 = bld.name_to_obj(obj, bld.env)
475 r2 = includes_objects(bld, t2, chain, inc_loops)
476 chain.remove(obj)
477 ret = ret.union(t2.direct_objects)
478 ret = ret.union(r2)
480 for lib in t.direct_libs:
481 if lib in chain:
482 dependency_loop(inc_loops, t, lib)
483 continue
484 chain.add(lib)
485 t2 = bld.name_to_obj(lib, bld.env)
486 r2 = includes_objects(bld, t2, chain, inc_loops)
487 chain.remove(lib)
488 ret = ret.union(t2.direct_objects)
489 ret = ret.union(r2)
491 t.includes_objects = ret
492 return ret
495 def break_dependency_loops(bld, tgt_list):
496 '''find and break dependency loops'''
497 loops = {}
498 inc_loops = {}
500 # build up the list of loops
501 for t in tgt_list:
502 indirect_objects(bld, t, set(), loops)
503 indirect_libs(bld, t, set(), loops)
504 includes_objects(bld, t, set(), inc_loops)
506 # break the loops
507 for t in tgt_list:
508 if t.sname in loops:
509 for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
510 objs = getattr(t, attr, set())
511 setattr(t, attr, objs.difference(loops[t.sname]))
513 for loop in loops:
514 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
516 # expand the loops mapping by one level
517 for loop in loops.copy():
518 for tgt in loops[loop]:
519 if tgt in loops:
520 loops[loop] = loops[loop].union(loops[tgt])
522 # expand indirect subsystem and library loops
523 for loop in loops.copy():
524 t = bld.name_to_obj(loop, bld.env)
525 if t.samba_type in ['SUBSYSTEM']:
526 loops[loop] = loops[loop].union(t.indirect_objects)
527 loops[loop] = loops[loop].union(t.direct_objects)
528 if t.samba_type in ['LIBRARY','PYTHON']:
529 loops[loop] = loops[loop].union(t.indirect_libs)
530 loops[loop] = loops[loop].union(t.direct_libs)
531 if loop in loops[loop]:
532 loops[loop].remove(loop)
534 # add in the replacement dependencies
535 for t in tgt_list:
536 for loop in loops:
537 for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
538 objs = getattr(t, attr, set())
539 if loop in objs:
540 diff = loops[loop].difference(objs)
541 if t.sname in diff:
542 diff.remove(t.sname)
543 if diff:
544 debug('deps: Expanded target %s of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
545 objs = objs.union(diff)
546 if t.sname == 'ldb_password_hash':
547 debug('deps: setting %s %s to %s', t.sname, attr, objs)
548 setattr(t, attr, objs)
550 def calculate_final_deps(bld, tgt_list, loops):
551 '''calculate the final library and object dependencies'''
552 for t in tgt_list:
553 # start with the maximum possible list
554 t.final_libs = t.direct_libs.union(indirect_libs(bld, t, set(), loops))
555 t.final_objects = t.direct_objects.union(indirect_objects(bld, t, set(), loops))
557 for t in tgt_list:
558 # don't depend on ourselves
559 if t.sname in t.final_libs:
560 t.final_libs.remove(t.sname)
561 if t.sname in t.final_objects:
562 t.final_objects.remove(t.sname)
564 # find any library loops
565 for t in tgt_list:
566 if t.samba_type in ['LIBRARY', 'PYTHON']:
567 for l in t.final_libs.copy():
568 t2 = bld.name_to_obj(l, bld.env)
569 if t.sname in t2.final_libs:
570 # we could break this in either direction. If one of the libraries
571 # has a version number, and will this be distributed publicly, then
572 # we should make it the lower level library in the DAG
573 debug('deps: removing library loop %s from %s', t.sname, t2.sname)
574 dependency_loop(loops, t, t2.sname)
575 t2.final_libs.remove(t.sname)
577 for type in ['BINARY']:
578 for t in tgt_list:
579 if t.samba_type != type: continue
580 # if we will indirectly link to a target then we don't need it
581 new = t.final_objects.copy()
582 for l in t.final_libs:
583 t2 = bld.name_to_obj(l, bld.env)
584 t2_obj = extended_objects(bld, t2, set())
585 dup = new.intersection(t2_obj)
586 if dup:
587 debug('deps: removing dups from %s of type %s: %s also in %s %s',
588 t.sname, t.samba_type, dup, t2.samba_type, l)
589 new = new.difference(dup)
590 changed = True
591 t.final_objects = new
593 for loop in loops:
594 debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
596 # we now need to make corrections for any library loops we broke up
597 # any target that depended on the target of the loop and doesn't
598 # depend on the source of the loop needs to get the loop source added
599 for type in ['BINARY','PYTHON','LIBRARY']:
600 for t in tgt_list:
601 if t.samba_type != type: continue
602 for loop in loops:
603 if loop in t.final_libs:
604 diff = loops[loop].difference(t.final_libs)
605 if t.sname in diff:
606 diff.remove(t.sname)
607 if diff:
608 debug('deps: Expanded target %s by loop %s libraries %s', t.sname, loop, diff)
609 t.final_libs = t.final_libs.union(diff)
611 # add in any syslib dependencies
612 for t in tgt_list:
613 if not t.samba_type in ['BINARY','PYTHON','LIBRARY']:
614 continue
615 syslibs = set()
616 for d in t.final_objects:
617 t2 = bld.name_to_obj(d, bld.env)
618 syslibs = syslibs.union(t2.direct_syslibs)
619 # this adds the indirect syslibs as well, which may not be needed
620 # depending on the linker flags
621 for d in t.final_libs:
622 t2 = bld.name_to_obj(d, bld.env)
623 syslibs = syslibs.union(t2.direct_syslibs)
624 t.final_syslibs = syslibs
626 debug('deps: removed duplicate dependencies')
630 ######################################################################
631 # this provides a way to save our dependency calculations between runs
632 savedeps_version = 3
633 savedeps_inputs = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags', 'source']
634 savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags']
635 savedeps_outenv = ['INC_PATHS']
636 savedeps_caches = ['GLOBAL_DEPENDENCIES', 'TARGET_ALIAS', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
637 savedeps_files = ['buildtools/wafsamba/samba_deps.py']
639 def save_samba_deps(bld, tgt_list):
640 '''save the dependency calculations between builds, to make
641 further builds faster'''
642 denv = Environment.Environment()
644 denv.version = savedeps_version
645 denv.savedeps_inputs = savedeps_inputs
646 denv.savedeps_outputs = savedeps_outputs
647 denv.input = {}
648 denv.output = {}
649 denv.outenv = {}
650 denv.caches = {}
651 denv.files = {}
653 for f in savedeps_files:
654 denv.files[f] = os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime
656 for c in savedeps_caches:
657 denv.caches[c] = LOCAL_CACHE(bld, c)
659 for t in tgt_list:
660 # save all the input attributes for each target
661 tdeps = {}
662 for attr in savedeps_inputs:
663 v = getattr(t, attr, None)
664 if v is not None:
665 tdeps[attr] = v
666 if tdeps != {}:
667 denv.input[t.sname] = tdeps
669 # save all the output attributes for each target
670 tdeps = {}
671 for attr in savedeps_outputs:
672 v = getattr(t, attr, None)
673 if v is not None:
674 tdeps[attr] = v
675 if tdeps != {}:
676 denv.output[t.sname] = tdeps
678 tdeps = {}
679 for attr in savedeps_outenv:
680 if attr in t.env:
681 tdeps[attr] = t.env[attr]
682 if tdeps != {}:
683 denv.outenv[t.sname] = tdeps
685 depsfile = os.path.join(bld.bdir, "sambadeps")
686 denv.store(depsfile)
689 def load_samba_deps(bld, tgt_list):
690 '''load a previous set of build dependencies if possible'''
691 depsfile = os.path.join(bld.bdir, "sambadeps")
692 denv = Environment.Environment()
693 try:
694 debug('deps: checking saved dependencies')
695 denv.load(depsfile)
696 if (denv.version != savedeps_version or
697 denv.savedeps_inputs != savedeps_inputs or
698 denv.savedeps_outputs != savedeps_outputs):
699 return False
700 except:
701 return False
703 # check if critical files have changed
704 for f in savedeps_files:
705 if f not in denv.files:
706 return False
707 if denv.files[f] != os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime:
708 return False
710 # check if caches are the same
711 for c in savedeps_caches:
712 if c not in denv.caches or denv.caches[c] != LOCAL_CACHE(bld, c):
713 return False
715 # check inputs are the same
716 for t in tgt_list:
717 tdeps = {}
718 for attr in savedeps_inputs:
719 v = getattr(t, attr, None)
720 if v is not None:
721 tdeps[attr] = v
722 if t.sname in denv.input:
723 olddeps = denv.input[t.sname]
724 else:
725 olddeps = {}
726 if tdeps != olddeps:
727 #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
728 return False
730 # put outputs in place
731 for t in tgt_list:
732 if not t.sname in denv.output: continue
733 tdeps = denv.output[t.sname]
734 for a in tdeps:
735 setattr(t, a, tdeps[a])
737 # put output env vars in place
738 for t in tgt_list:
739 if not t.sname in denv.outenv: continue
740 tdeps = denv.outenv[t.sname]
741 for a in tdeps:
742 t.env[a] = tdeps[a]
744 debug('deps: loaded saved dependencies')
745 return True
748 def check_project_rules(bld):
749 '''check the project rules - ensuring the targets are sane'''
751 targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
752 loops = {}
753 inc_loops = {}
755 # build a list of task generators we are interested in
756 tgt_list = []
757 for tgt in targets:
758 type = targets[tgt]
759 if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON']:
760 continue
761 t = bld.name_to_obj(tgt, bld.env)
762 if t is None:
763 print "Target %s of type %s has no task generator" % (tgt, type)
764 raise
765 tgt_list.append(t)
767 add_samba_attributes(bld, tgt_list)
769 if load_samba_deps(bld, tgt_list):
770 return
772 print "Checking project rules ..."
774 debug('deps: project rules checking started')
776 expand_subsystem_deps(bld)
777 build_direct_deps(bld, tgt_list)
778 break_dependency_loops(bld, tgt_list)
779 calculate_final_deps(bld, tgt_list, loops)
781 # run the various attribute generators
782 for f in [ build_dependencies, build_includes, add_init_functions ]:
783 debug('deps: project rules checking %s', f)
784 for t in tgt_list: f(t)
786 debug('deps: project rules stage1 completed')
788 #check_orpaned_targets(bld, tgt_list)
790 if not check_duplicate_sources(bld, tgt_list):
791 print "Duplicate sources present - aborting"
792 sys.exit(1)
794 show_final_deps(bld, tgt_list)
796 debug('deps: project rules checking completed - %u targets checked',
797 len(tgt_list))
799 save_samba_deps(bld, tgt_list)
801 print "Project rules pass"
804 def CHECK_PROJECT_RULES(bld):
805 '''enable checking of project targets for sanity'''
806 if bld.env.added_project_rules:
807 return
808 bld.env.added_project_rules = True
809 bld.add_pre_fun(check_project_rules)
810 Build.BuildContext.CHECK_PROJECT_RULES = CHECK_PROJECT_RULES