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
)
16 def TARGET_ALIAS(bld
, target
, alias
):
17 '''define an alias for a target name'''
18 cache
= LOCAL_CACHE(bld
, 'TARGET_ALIAS')
20 Logs
.error("Target alias %s already set to %s : newalias %s" % (alias
, cache
[alias
], target
))
23 Build
.BuildContext
.TARGET_ALIAS
= TARGET_ALIAS
27 def SET_SYSLIB_DEPS(conf
, target
, deps
):
28 '''setup some implied dependencies for a SYSLIB'''
29 cache
= LOCAL_CACHE(conf
, 'SYSLIB_DEPS')
33 def EXPAND_ALIAS(bld
, target
):
34 '''expand a target name via an alias'''
35 aliases
= LOCAL_CACHE(bld
, 'TARGET_ALIAS')
37 return aliases
[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')
52 bld
.ASSERT(s
in targets
, "Subsystem target %s not declared" % s
)
54 if type == 'DISABLED' or type == 'EMPTY':
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.
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):
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=
118 if getattr(self
, 'samba_includes', None) is None:
123 inc_deps
= includes_objects(bld
, self
, set(), {})
127 # maybe add local includes
128 if getattr(self
, 'local_include', True) == True and getattr(self
, 'local_include_first', True):
131 includes
.extend(self
.samba_includes_extended
)
133 if 'EXTRA_INCLUDES' in bld
.env
:
134 includes
.extend(bld
.env
['EXTRA_INCLUDES'])
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:
149 tpath
= t
.samba_abspath
151 npath
= tpath
+ '/' + inc
152 if not npath
in inc_set
:
153 inc_abs
.append(npath
)
156 mypath
= self
.path
.abspath(bld
.env
)
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):
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
170 # some are already top based
171 includes_top
.append(i
)
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'''
189 subsystems
= LOCAL_CACHE(bld
, 'INIT_FUNCTIONS')
191 # cope with the separated object lists from BINARY and LIBRARY targets
193 if sname
.endswith('.objlist'):
197 if sname
in subsystems
:
198 modules
.append(sname
)
200 m
= getattr(self
, 'samba_modules', None)
202 modules
.extend(TO_LIST(m
))
204 m
= getattr(self
, 'samba_subsystem', None)
211 sentinal
= getattr(self
, 'init_function_sentinal', 'NULL')
213 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
215 cflags
= getattr(self
, 'samba_cflags', [])[:]
217 bld
.ASSERT(m
in subsystems
,
218 "No init_function defined for module '%s' in target '%s'" % (m
, self
.sname
))
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
))
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')
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
))
249 if not targets
[t
.sname
] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
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
} )
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
,
265 seen
= seen
.union(common
)
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')
278 if getattr(t
, 'samba_used', False) == True:
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
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
304 for g
in bld
.task_manager
.groups
:
309 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
313 tdeps
= getattr(t
, 'add_objects', []) + getattr(t
, 'uselib_local', [])
315 t2
= bld
.name_to_obj(d
, bld
.env
)
318 map1
= grp_map
[t
.samba_group
]
319 map2
= grp_map
[t2
.samba_group
]
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
))
329 def show_final_deps(bld
, tgt_list
):
330 '''show the final dependencies for all targets'''
332 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
335 if not targets
[t
.sname
] in ['LIBRARY', 'BINARY', 'PYTHON']:
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')
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
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
)
373 d
= EXPAND_ALIAS(bld
, d
)
374 if d
== t
.sname
: continue
376 Logs
.error("Unknown dependency %s in %s" % (d
, t
.sname
))
378 if targets
[d
] in [ 'EMPTY', 'DISABLED' ]:
380 if targets
[d
] == 'SYSLIB':
381 t
.direct_syslibs
.add(d
)
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
)
391 Logs
.error('Implied dependency %s in %s is of type %s' % (
392 implied
, t
.sname
, targets
[implied
]))
395 t2
= bld
.name_to_obj(d
, bld
.env
)
397 Logs
.error("no task %s of type %s in %s" % (d
, targets
[d
], t
.sname
))
399 if t2
.samba_type
in [ 'LIBRARY', 'MODULE' ]:
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
:
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
423 ret
= getattr(t
, 'indirect_libs', None)
428 for obj
in t
.direct_objects
:
430 dependency_loop(loops
, t
, obj
)
433 t2
= bld
.name_to_obj(obj
, bld
.env
)
434 r2
= indirect_libs(bld
, t2
, chain
, loops
)
436 ret
= ret
.union(t2
.direct_libs
)
439 for obj
in indirect_objects(bld
, t
, set(), loops
):
441 dependency_loop(loops
, t
, obj
)
444 t2
= bld
.name_to_obj(obj
, bld
.env
)
445 r2
= indirect_libs(bld
, t2
, chain
, loops
)
447 ret
= ret
.union(t2
.direct_libs
)
450 t
.indirect_libs
= 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
466 for lib
in t
.direct_objects
:
468 dependency_loop(loops
, t
, lib
)
471 t2
= bld
.name_to_obj(lib
, bld
.env
)
472 r2
= indirect_objects(bld
, t2
, chain
, loops
)
474 ret
= ret
.union(t2
.direct_objects
)
477 t
.indirect_objects
= 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:
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
494 ret
= ret
.union(t
.final_objects
)
496 for lib
in t
.final_libs
:
499 t2
= bld
.name_to_obj(lib
, bld
.env
)
501 r2
= extended_objects(bld
, t2
, chain
)
503 ret
= ret
.union(t2
.final_objects
)
506 t
.extended_objects
= 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)
519 ret
= t
.direct_objects
.copy()
520 ret
= ret
.union(t
.direct_libs
)
522 for obj
in t
.direct_objects
:
524 dependency_loop(inc_loops
, t
, obj
)
527 t2
= bld
.name_to_obj(obj
, bld
.env
)
528 r2
= includes_objects(bld
, t2
, chain
, inc_loops
)
530 ret
= ret
.union(t2
.direct_objects
)
533 for lib
in t
.direct_libs
:
535 dependency_loop(inc_loops
, t
, lib
)
538 t2
= bld
.name_to_obj(lib
, bld
.env
)
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
))
544 r2
= includes_objects(bld
, t2
, chain
, inc_loops
)
546 ret
= ret
.union(t2
.direct_objects
)
549 t
.includes_objects
= ret
553 def break_dependency_loops(bld
, tgt_list
):
554 '''find and break dependency loops'''
558 # build up the list of loops
560 indirect_objects(bld
, t
, set(), loops
)
561 indirect_libs(bld
, t
, set(), loops
)
562 includes_objects(bld
, t
, set(), inc_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
]))
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
]:
581 loops
[loop
] = loops
[loop
].union(loops
[tgt
])
583 for loop
in inc_loops
.copy():
584 for tgt
in inc_loops
[loop
]:
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
611 for attr
in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
612 objs
= getattr(t
, attr
, set())
614 diff
= loops
[loop
].difference(objs
)
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())
625 diff
= inc_loops
[loop
].difference(objs
)
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'''
639 t
.extended_objects
= None
643 for type in ['BINARY', 'PYTHON', 'LIBRARY']:
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
])
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
)
661 rely_on
[l
] = rely_on
[l
].union(dup
)
662 t
.final_objects
= new
667 # add back in any objects that were relied upon by the reduction rules
669 t
= bld
.name_to_obj(r
, bld
.env
)
670 t
.final_objects
= t
.final_objects
.union(rely_on
[r
])
675 def calculate_final_deps(bld
, tgt_list
, loops
):
676 '''calculate the final library and object dependencies'''
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
))
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
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
)
697 Logs
.error('ERROR: subsystem %s not found' % objname
)
699 t
.final_objects
.add(objname
)
700 t
.final_objects
= t
.final_objects
.union(extended_objects(bld
, t2
, set()))
703 # find any library loops
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
)
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']:
725 if t
.samba_type
!= type: continue
727 if loop
in t
.final_libs
:
728 diff
= loops
[loop
].difference(t
.final_libs
)
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
)
741 debug('deps: Expanded target %s by loop %s libraries (loop %s) %s', t
.sname
, loop
,
743 t
.final_libs
= t
.final_libs
.union(diff
)
745 # remove objects that are also available in linked libs
747 while reduce_objects(bld
, tgt_list
):
750 Logs
.warn("WARNING: Unable to remove all inter-target object duplicates")
752 debug('deps: Object reduction took %u iterations', count
)
754 # add in any syslib dependencies
756 if not t
.samba_type
in ['BINARY','PYTHON','LIBRARY']:
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
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
782 debug('deps: removed duplicate dependencies')
785 ######################################################################
786 # this provides a way to save our dependency calculations between runs
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
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
]
820 # save all the input attributes for each target
822 for attr
in savedeps_inputs
:
823 v
= getattr(t
, attr
, None)
827 denv
.input[t
.sname
] = tdeps
829 # save all the output attributes for each target
831 for attr
in savedeps_outputs
:
832 v
= getattr(t
, attr
, None)
836 denv
.output
[t
.sname
] = tdeps
839 for attr
in savedeps_outenv
:
841 tdeps
[attr
] = t
.env
[attr
]
843 denv
.outenv
[t
.sname
] = tdeps
845 depsfile
= os
.path
.join(bld
.bdir
, "sambadeps")
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()
855 debug('deps: checking saved dependencies')
857 if (denv
.version
!= savedeps_version
or
858 denv
.savedeps_inputs
!= savedeps_inputs
or
859 denv
.savedeps_outputs
!= savedeps_outputs
):
864 # check if critical files have changed
865 for f
in savedeps_files
:
866 if f
not in denv
.files
:
868 if denv
.files
[f
] != os
.stat(os
.path
.join(bld
.srcnode
.abspath(), f
)).st_mtime
:
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
):
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
]:
881 # check inputs are the same
884 for attr
in savedeps_inputs
:
885 v
= getattr(t
, attr
, None)
888 if t
.sname
in denv
.input:
889 olddeps
= denv
.input[t
.sname
]
893 #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
896 # put outputs in place
898 if not t
.sname
in denv
.output
: continue
899 tdeps
= denv
.output
[t
.sname
]
901 setattr(t
, a
, tdeps
[a
])
903 # put output env vars in place
905 if not t
.sname
in denv
.outenv
: continue
906 tdeps
= denv
.outenv
[t
.sname
]
910 debug('deps: loaded saved dependencies')
915 def check_project_rules(bld
):
916 '''check the project rules - ensuring the targets are sane'''
918 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
922 # build a list of task generators we are interested in
926 if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON']:
928 t
= bld
.name_to_obj(tgt
, bld
.env
)
930 Logs
.error("Target %s of type %s has no task generator" % (tgt
, type))
934 add_samba_attributes(bld
, tgt_list
)
936 if load_samba_deps(bld
, tgt_list
):
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")
961 if not check_group_ordering(bld
, tgt_list
):
962 Logs
.error("Bad group ordering - aborting")
965 show_final_deps(bld
, tgt_list
)
967 debug('deps: project rules checking completed - %u targets checked',
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
:
979 bld
.env
.added_project_rules
= True
980 bld
.add_pre_fun(check_project_rules
)
981 Build
.BuildContext
.CHECK_PROJECT_RULES
= CHECK_PROJECT_RULES