1 # Samba automatic dependency handling and project rules
3 import Build
, os
, re
, Environment
, Logs
4 from samba_utils
import *
5 from samba_autoconf
import *
6 from samba_bundled
import BUILTIN_LIBRARY
9 def ADD_GLOBAL_DEPENDENCY(ctx
, dep
):
10 '''add a dependency for all binaries and libraries'''
11 if not 'GLOBAL_DEPENDENCIES' in ctx
.env
:
12 ctx
.env
.GLOBAL_DEPENDENCIES
= []
13 ctx
.env
.GLOBAL_DEPENDENCIES
.append(dep
)
17 def BREAK_CIRCULAR_LIBRARY_DEPENDENCIES(ctx
):
18 '''indicate that circular dependencies between libraries should be broken.'''
19 ctx
.env
.ALLOW_CIRCULAR_LIB_DEPENDENCIES
= True
22 def TARGET_ALIAS(bld
, target
, alias
):
23 '''define an alias for a target name'''
24 cache
= LOCAL_CACHE(bld
, 'TARGET_ALIAS')
26 Logs
.error("Target alias %s already set to %s : newalias %s" % (alias
, cache
[alias
], target
))
29 Build
.BuildContext
.TARGET_ALIAS
= TARGET_ALIAS
33 def SET_SYSLIB_DEPS(conf
, target
, deps
):
34 '''setup some implied dependencies for a SYSLIB'''
35 cache
= LOCAL_CACHE(conf
, 'SYSLIB_DEPS')
39 def EXPAND_ALIAS(bld
, target
):
40 '''expand a target name via an alias'''
41 aliases
= LOCAL_CACHE(bld
, 'TARGET_ALIAS')
43 return aliases
[target
]
45 Build
.BuildContext
.EXPAND_ALIAS
= EXPAND_ALIAS
48 def expand_subsystem_deps(bld
):
49 '''expand the reverse dependencies resulting from subsystem
50 attributes of modules. This is walking over the complete list
51 of declared subsystems, and expands the samba_deps_extended list for any
52 module<->subsystem dependencies'''
54 subsystem_list
= LOCAL_CACHE(bld
, 'INIT_FUNCTIONS')
55 aliases
= LOCAL_CACHE(bld
, 'TARGET_ALIAS')
56 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
58 for subsystem_name
in subsystem_list
:
59 if subsystem_name
in aliases
:
60 subsystem_name
= aliases
[subsystem_name
]
61 bld
.ASSERT(subsystem_name
in targets
, "Subsystem target %s not declared" % subsystem_name
)
62 type = targets
[subsystem_name
]
63 if type == 'DISABLED' or type == 'EMPTY':
67 # subsystem_name = dcerpc_server (a subsystem)
68 # subsystem = dcerpc_server (a subsystem object)
69 # module_name = rpc_epmapper (a module within the dcerpc_server subsystem)
70 # module = rpc_epmapper (a module object within the dcerpc_server subsystem)
72 subsystem
= bld
.name_to_obj(subsystem_name
, bld
.env
)
73 for d
in subsystem_list
[subsystem_name
]:
74 module_name
= d
['TARGET']
75 module_type
= targets
[module_name
]
76 if module_type
in ['DISABLED', 'EMPTY']:
78 bld
.ASSERT(subsystem
is not None,
79 "Subsystem target %s for %s (%s) not found" % (subsystem_name
, module_name
, module_type
))
80 if module_type
in ['SUBSYSTEM']:
81 # if a module is a plain object type (not a library) then the
82 # subsystem it is part of needs to have it as a dependency, so targets
83 # that depend on this subsystem get the modules of that subsystem
84 subsystem
.samba_deps_extended
.append(module_name
)
85 module
= bld
.name_to_obj(module_name
, bld
.env
)
86 module
.samba_includes_extended
.extend(subsystem
.samba_includes_extended
)
87 if targets
[subsystem_name
] in ['SUBSYSTEM']:
88 # if a subsystem is a plain object type (not a library) then any modules
89 # in that subsystem need to depend on the subsystem
90 module
.samba_deps_extended
.extend(subsystem
.samba_deps_extended
)
91 subsystem
.samba_deps_extended
= unique_list(subsystem
.samba_deps_extended
)
95 def build_dependencies(self
):
96 '''This builds the dependency list for a target. It runs after all the targets are declared
98 The reason this is not just done in the SAMBA_*() rules is that we have no way of knowing
99 the full dependency list for a target until we have all of the targets declared.
102 if self
.samba_type
in ['LIBRARY', 'BINARY', 'PYTHON']:
103 self
.uselib
= list(self
.final_syslibs
)
104 self
.uselib_local
= list(self
.final_libs
)
105 self
.add_objects
= list(self
.final_objects
)
107 # extra link flags from pkg_config
108 libs
= self
.final_syslibs
.copy()
110 (ccflags
, ldflags
) = library_flags(self
, list(libs
))
111 new_ldflags
= getattr(self
, 'ldflags', [])
112 new_ldflags
.extend(ldflags
)
113 self
.ldflags
= new_ldflags
115 debug('deps: computed dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
116 self
.sname
, self
.uselib
, self
.uselib_local
, self
.add_objects
)
118 if self
.samba_type
in ['SUBSYSTEM']:
119 # this is needed for the ccflags of libs that come from pkg_config
120 self
.uselib
= list(self
.direct_syslibs
)
122 if getattr(self
, 'uselib', None):
124 for l
in self
.uselib
:
125 up_list
.append(l
.upper())
126 self
.uselib
= up_list
128 def build_includes(self
):
129 '''This builds the right set of includes for a target.
131 One tricky part of this is that the includes= attribute for a
132 target needs to use paths which are relative to that targets
133 declaration directory (which we can get at via t.path).
135 The way this works is the includes list gets added as
136 samba_includes in the main build task declaration. Then this
137 function runs after all of the tasks are declared, and it
138 processes the samba_includes attribute to produce a includes=
142 if getattr(self
, 'samba_includes', None) is None:
147 inc_deps
= includes_objects(bld
, self
, set(), {})
151 # maybe add local includes
152 if getattr(self
, 'local_include', True) == True and getattr(self
, 'local_include_first', True):
155 includes
.extend(self
.samba_includes_extended
)
157 if 'EXTRA_INCLUDES' in bld
.env
:
158 includes
.extend(bld
.env
['EXTRA_INCLUDES'])
166 t
= bld
.name_to_obj(d
, bld
.env
)
167 bld
.ASSERT(t
is not None, "Unable to find dependency %s for %s" % (d
, self
.sname
))
168 inclist
= getattr(t
, 'samba_includes_extended', [])
169 if getattr(t
, 'local_include', True) == True:
173 tpath
= t
.samba_abspath
175 npath
= tpath
+ '/' + inc
176 if not npath
in inc_set
:
177 inc_abs
.append(npath
)
180 mypath
= self
.path
.abspath(bld
.env
)
182 relpath
= os_path_relpath(inc
, mypath
)
183 includes
.append(relpath
)
185 if getattr(self
, 'local_include', True) == True and not getattr(self
, 'local_include_first', True):
188 # now transform the includes list to be relative to the top directory
189 # which is represented by '#' in waf. This allows waf to cache the
190 # includes lists more efficiently
194 # some are already top based
195 includes_top
.append(i
)
197 absinc
= os
.path
.join(self
.path
.abspath(), i
)
198 relinc
= os_path_relpath(absinc
, self
.bld
.srcnode
.abspath())
199 includes_top
.append('#' + relinc
)
201 self
.includes
= unique_list(includes_top
)
202 debug('deps: includes for target %s: includes=%s',
203 self
.sname
, self
.includes
)
208 def add_init_functions(self
):
209 '''This builds the right set of init functions'''
213 subsystems
= LOCAL_CACHE(bld
, 'INIT_FUNCTIONS')
215 # cope with the separated object lists from BINARY and LIBRARY targets
217 if sname
.endswith('.objlist'):
221 if sname
in subsystems
:
222 modules
.append(sname
)
224 m
= getattr(self
, 'samba_modules', None)
226 modules
.extend(TO_LIST(m
))
228 m
= getattr(self
, 'samba_subsystem', None)
235 sentinal
= getattr(self
, 'init_function_sentinal', 'NULL')
237 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
239 cflags
= getattr(self
, 'samba_cflags', [])[:]
241 bld
.ASSERT(m
in subsystems
,
242 "No init_function defined for module '%s' in target '%s'" % (m
, self
.sname
))
244 for d
in subsystems
[m
]:
245 if targets
[d
['TARGET']] != 'DISABLED':
246 init_fn_list
.append(d
['INIT_FUNCTION'])
247 if init_fn_list
== []:
248 cflags
.append('-DSTATIC_%s_MODULES=%s' % (m
, sentinal
))
250 cflags
.append('-DSTATIC_%s_MODULES=%s' % (m
, ','.join(init_fn_list
) + ',' + sentinal
))
251 self
.ccflags
= cflags
255 def check_duplicate_sources(bld
, tgt_list
):
256 '''see if we are compiling the same source file into multiple
257 subsystem targets for the same library or binary'''
259 debug('deps: checking for duplicate sources')
261 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
267 obj_sources
= getattr(t
, 'source', '')
268 tpath
= os
.path
.normpath(os_path_relpath(t
.path
.abspath(bld
.env
), t
.env
.BUILD_DIRECTORY
+ '/default'))
269 obj_sources
= bld
.SUBDIR(tpath
, obj_sources
)
270 t
.samba_source_set
= set(TO_LIST(obj_sources
))
273 if not targets
[t
.sname
] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
277 for obj
in t
.add_objects
:
278 t2
= t
.bld
.name_to_obj(obj
, bld
.env
)
279 source_set
= getattr(t2
, 'samba_source_set', set())
280 sources
.append( { 'dep':obj
, 'src':source_set
} )
283 if s
['dep'] == s2
['dep']: continue
284 common
= s
['src'].intersection(s2
['src'])
285 if common
.difference(seen
):
286 Logs
.error("Target %s has duplicate source files in %s and %s : %s" % (t
.sname
,
289 seen
= seen
.union(common
)
294 def check_orpaned_targets(bld
, tgt_list
):
295 '''check if any build targets are orphaned'''
297 target_dict
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
299 debug('deps: checking for orphaned targets')
302 if getattr(t
, 'samba_used', False) == True:
304 type = target_dict
[t
.sname
]
305 if not type in ['BINARY', 'LIBRARY', 'MODULE', 'ET', 'PYTHON']:
306 if re
.search('^PIDL_', t
.sname
) is None:
307 Logs
.warn("Target %s of type %s is unused by any other target" % (t
.sname
, type))
310 def check_group_ordering(bld
, tgt_list
):
311 '''see if we have any dependencies that violate the group ordering
313 It is an error for a target to depend on a target from a later
318 tm
= bld
.task_manager
319 return [x
for x
in tm
.groups_names
if id(tm
.groups_names
[x
]) == id(g
)][0]
321 for g
in bld
.task_manager
.groups
:
322 gname
= group_name(g
)
323 for t
in g
.tasks_gen
:
324 t
.samba_group
= gname
328 for g
in bld
.task_manager
.groups
:
333 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
337 tdeps
= getattr(t
, 'add_objects', []) + getattr(t
, 'uselib_local', [])
339 t2
= bld
.name_to_obj(d
, bld
.env
)
342 map1
= grp_map
[t
.samba_group
]
343 map2
= grp_map
[t2
.samba_group
]
346 Logs
.error("Target %r in build group %r depends on target %r from later build group %r" % (
347 t
.sname
, t
.samba_group
, t2
.sname
, t2
.samba_group
))
353 def show_final_deps(bld
, tgt_list
):
354 '''show the final dependencies for all targets'''
356 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
359 if not targets
[t
.sname
] in ['LIBRARY', 'BINARY', 'PYTHON']:
361 debug('deps: final dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
362 t
.sname
, t
.uselib
, t
.uselib_local
, t
.add_objects
)
365 def add_samba_attributes(bld
, tgt_list
):
366 '''ensure a target has a the required samba attributes'''
368 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
375 t
.samba_type
= targets
[t
.sname
]
376 t
.samba_abspath
= t
.path
.abspath(bld
.env
)
377 t
.samba_deps_extended
= t
.samba_deps
[:]
378 t
.samba_includes_extended
= TO_LIST(t
.samba_includes
)[:]
379 t
.ccflags
= getattr(t
, 'samba_cflags', '')
381 def replace_grouping_libraries(bld
, tgt_list
):
382 '''replace dependencies based on grouping libraries
384 If a library is marked as a grouping library, then any target that
385 depends on a subsystem that is part of that grouping library gets
386 that dependency replaced with a dependency on the grouping library
389 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
393 # find our list of grouping libraries, mapped from the subsystems they depend on
395 if not getattr(t
, 'grouping_library', False):
397 for dep
in t
.samba_deps_extended
:
398 if targets
[dep
] == 'SUBSYSTEM':
399 grouping
[dep
] = t
.sname
401 # now replace any dependencies on elements of grouping libraries
403 for i
in range(len(t
.samba_deps_extended
)):
404 dep
= t
.samba_deps_extended
[i
]
406 if t
.sname
!= grouping
[dep
]:
407 debug("deps: target %s: replacing dependency %s with grouping library %s" % (t
.sname
, dep
, grouping
[dep
]))
408 t
.samba_deps_extended
[i
] = grouping
[dep
]
412 def build_direct_deps(bld
, tgt_list
):
413 '''build the direct_objects and direct_libs sets for each target'''
415 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
416 syslib_deps
= LOCAL_CACHE(bld
, 'SYSLIB_DEPS')
418 global_deps
= bld
.env
.GLOBAL_DEPENDENCIES
419 global_deps_exclude
= set()
420 for dep
in global_deps
:
421 t
= bld
.name_to_obj(dep
, bld
.env
)
422 for d
in t
.samba_deps
:
423 # prevent loops from the global dependencies list
424 global_deps_exclude
.add(d
)
425 global_deps_exclude
.add(d
+ '.objlist')
428 t
.direct_objects
= set()
429 t
.direct_libs
= set()
430 t
.direct_syslibs
= set()
431 deps
= t
.samba_deps_extended
[:]
432 if getattr(t
, 'samba_use_global_deps', False) and not t
.sname
in global_deps_exclude
:
433 deps
.extend(global_deps
)
435 d
= EXPAND_ALIAS(bld
, d
)
436 if d
== t
.sname
: continue
438 Logs
.error("Unknown dependency %s in %s" % (d
, t
.sname
))
440 if targets
[d
] in [ 'EMPTY', 'DISABLED' ]:
442 if targets
[d
] == 'PYTHON' and targets
[t
.sname
] != 'PYTHON' and t
.sname
.find('.objlist') == -1:
443 # this check should be more restrictive, but for now we have pidl-generated python
444 # code that directly depends on other python modules
445 Logs
.error('ERROR: Target %s has dependency on python module %s' % (t
.sname
, d
))
447 if targets
[d
] == 'SYSLIB':
448 t
.direct_syslibs
.add(d
)
450 for implied
in TO_LIST(syslib_deps
[d
]):
451 if BUILTIN_LIBRARY(bld
, implied
):
452 t
.direct_objects
.add(implied
)
453 elif targets
[implied
] == 'SYSLIB':
454 t
.direct_syslibs
.add(implied
)
455 elif targets
[implied
] in ['LIBRARY', 'MODULE']:
456 t
.direct_libs
.add(implied
)
458 Logs
.error('Implied dependency %s in %s is of type %s' % (
459 implied
, t
.sname
, targets
[implied
]))
462 t2
= bld
.name_to_obj(d
, bld
.env
)
464 Logs
.error("no task %s of type %s in %s" % (d
, targets
[d
], t
.sname
))
466 if t2
.samba_type
in [ 'LIBRARY', 'MODULE' ]:
468 elif t2
.samba_type
in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]:
469 t
.direct_objects
.add(d
)
470 debug('deps: built direct dependencies')
473 def dependency_loop(loops
, t
, target
):
474 '''add a dependency loop to the loops dictionary'''
475 if t
.sname
== target
:
477 if not target
in loops
:
478 loops
[target
] = set()
479 if not t
.sname
in loops
[target
]:
480 loops
[target
].add(t
.sname
)
483 def indirect_libs(bld
, t
, chain
, loops
):
484 '''recursively calculate the indirect library dependencies for a target
486 An indirect library is a library that results from a dependency on
490 ret
= getattr(t
, 'indirect_libs', None)
495 for obj
in t
.direct_objects
:
497 dependency_loop(loops
, t
, obj
)
500 t2
= bld
.name_to_obj(obj
, bld
.env
)
501 r2
= indirect_libs(bld
, t2
, chain
, loops
)
503 ret
= ret
.union(t2
.direct_libs
)
506 for obj
in indirect_objects(bld
, t
, set(), loops
):
508 dependency_loop(loops
, t
, obj
)
511 t2
= bld
.name_to_obj(obj
, bld
.env
)
512 r2
= indirect_libs(bld
, t2
, chain
, loops
)
514 ret
= ret
.union(t2
.direct_libs
)
517 t
.indirect_libs
= ret
522 def indirect_objects(bld
, t
, chain
, loops
):
523 '''recursively calculate the indirect object dependencies for a target
525 indirect objects are the set of objects from expanding the
526 subsystem dependencies
529 ret
= getattr(t
, 'indirect_objects', None)
530 if ret
is not None: return ret
533 for lib
in t
.direct_objects
:
535 dependency_loop(loops
, t
, lib
)
538 t2
= bld
.name_to_obj(lib
, bld
.env
)
539 r2
= indirect_objects(bld
, t2
, chain
, loops
)
541 ret
= ret
.union(t2
.direct_objects
)
544 t
.indirect_objects
= ret
548 def extended_objects(bld
, t
, chain
):
549 '''recursively calculate the extended object dependencies for a target
551 extended objects are the union of:
554 - direct and indirect objects of all direct and indirect libraries
557 ret
= getattr(t
, 'extended_objects', None)
558 if ret
is not None: return ret
561 ret
= ret
.union(t
.final_objects
)
563 for lib
in t
.final_libs
:
566 t2
= bld
.name_to_obj(lib
, bld
.env
)
568 r2
= extended_objects(bld
, t2
, chain
)
570 ret
= ret
.union(t2
.final_objects
)
573 t
.extended_objects
= ret
577 def includes_objects(bld
, t
, chain
, inc_loops
):
578 '''recursively calculate the includes object dependencies for a target
580 includes dependencies come from either library or object dependencies
582 ret
= getattr(t
, 'includes_objects', None)
586 ret
= t
.direct_objects
.copy()
587 ret
= ret
.union(t
.direct_libs
)
589 for obj
in t
.direct_objects
:
591 dependency_loop(inc_loops
, t
, obj
)
594 t2
= bld
.name_to_obj(obj
, bld
.env
)
595 r2
= includes_objects(bld
, t2
, chain
, inc_loops
)
597 ret
= ret
.union(t2
.direct_objects
)
600 for lib
in t
.direct_libs
:
602 dependency_loop(inc_loops
, t
, lib
)
605 t2
= bld
.name_to_obj(lib
, bld
.env
)
607 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
608 Logs
.error('Target %s of type %s not found in direct_libs for %s' % (
609 lib
, targets
[lib
], t
.sname
))
611 r2
= includes_objects(bld
, t2
, chain
, inc_loops
)
613 ret
= ret
.union(t2
.direct_objects
)
616 t
.includes_objects
= ret
620 def break_dependency_loops(bld
, tgt_list
):
621 '''find and break dependency loops'''
625 # build up the list of loops
627 indirect_objects(bld
, t
, set(), loops
)
628 indirect_libs(bld
, t
, set(), loops
)
629 includes_objects(bld
, t
, set(), inc_loops
)
634 for attr
in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
635 objs
= getattr(t
, attr
, set())
636 setattr(t
, attr
, objs
.difference(loops
[t
.sname
]))
639 debug('deps: Found dependency loops for target %s : %s', loop
, loops
[loop
])
641 for loop
in inc_loops
:
642 debug('deps: Found include loops for target %s : %s', loop
, inc_loops
[loop
])
644 # expand the loops mapping by one level
645 for loop
in loops
.copy():
646 for tgt
in loops
[loop
]:
648 loops
[loop
] = loops
[loop
].union(loops
[tgt
])
650 for loop
in inc_loops
.copy():
651 for tgt
in inc_loops
[loop
]:
653 inc_loops
[loop
] = inc_loops
[loop
].union(inc_loops
[tgt
])
656 # expand indirect subsystem and library loops
657 for loop
in loops
.copy():
658 t
= bld
.name_to_obj(loop
, bld
.env
)
659 if t
.samba_type
in ['SUBSYSTEM']:
660 loops
[loop
] = loops
[loop
].union(t
.indirect_objects
)
661 loops
[loop
] = loops
[loop
].union(t
.direct_objects
)
662 if t
.samba_type
in ['LIBRARY','PYTHON']:
663 loops
[loop
] = loops
[loop
].union(t
.indirect_libs
)
664 loops
[loop
] = loops
[loop
].union(t
.direct_libs
)
665 if loop
in loops
[loop
]:
666 loops
[loop
].remove(loop
)
668 # expand indirect includes loops
669 for loop
in inc_loops
.copy():
670 t
= bld
.name_to_obj(loop
, bld
.env
)
671 inc_loops
[loop
] = inc_loops
[loop
].union(t
.includes_objects
)
672 if loop
in inc_loops
[loop
]:
673 inc_loops
[loop
].remove(loop
)
675 # add in the replacement dependencies
678 for attr
in ['indirect_objects', 'indirect_libs']:
679 objs
= getattr(t
, attr
, set())
681 diff
= loops
[loop
].difference(objs
)
685 debug('deps: Expanded target %s of type %s from loop %s by %s', t
.sname
, t
.samba_type
, loop
, diff
)
686 objs
= objs
.union(diff
)
687 setattr(t
, attr
, objs
)
689 for loop
in inc_loops
:
690 objs
= getattr(t
, 'includes_objects', set())
692 diff
= inc_loops
[loop
].difference(objs
)
696 debug('deps: Expanded target %s includes of type %s from loop %s by %s', t
.sname
, t
.samba_type
, loop
, diff
)
697 objs
= objs
.union(diff
)
698 setattr(t
, 'includes_objects', objs
)
701 def reduce_objects(bld
, tgt_list
):
702 '''reduce objects by looking for indirect object dependencies'''
706 t
.extended_objects
= None
710 for type in ['BINARY', 'PYTHON', 'LIBRARY']:
712 if t
.samba_type
!= type: continue
713 # if we will indirectly link to a target then we don't need it
714 new
= t
.final_objects
.copy()
715 for l
in t
.final_libs
:
716 t2
= bld
.name_to_obj(l
, bld
.env
)
717 t2_obj
= extended_objects(bld
, t2
, set())
718 dup
= new
.intersection(t2_obj
)
719 if t
.sname
in rely_on
:
720 dup
= dup
.difference(rely_on
[t
.sname
])
722 debug('deps: removing dups from %s of type %s: %s also in %s %s',
723 t
.sname
, t
.samba_type
, dup
, t2
.samba_type
, l
)
724 new
= new
.difference(dup
)
728 rely_on
[l
] = rely_on
[l
].union(dup
)
729 t
.final_objects
= new
734 # add back in any objects that were relied upon by the reduction rules
736 t
= bld
.name_to_obj(r
, bld
.env
)
737 t
.final_objects
= t
.final_objects
.union(rely_on
[r
])
742 def calculate_final_deps(bld
, tgt_list
, loops
):
743 '''calculate the final library and object dependencies'''
745 # start with the maximum possible list
746 t
.final_libs
= t
.direct_libs
.union(indirect_libs(bld
, t
, set(), loops
))
747 t
.final_objects
= t
.direct_objects
.union(indirect_objects(bld
, t
, set(), loops
))
750 # don't depend on ourselves
751 if t
.sname
in t
.final_libs
:
752 t
.final_libs
.remove(t
.sname
)
753 if t
.sname
in t
.final_objects
:
754 t
.final_objects
.remove(t
.sname
)
756 # handle any non-shared binaries
758 if t
.samba_type
== 'BINARY' and bld
.NONSHARED_BINARY(t
.sname
):
759 # replace lib deps with objlist deps
760 for l
in t
.final_libs
:
761 objname
= l
+ '.objlist'
762 t2
= bld
.name_to_obj(objname
, bld
.env
)
764 Logs
.error('ERROR: subsystem %s not found' % objname
)
766 t
.final_objects
.add(objname
)
767 t
.final_objects
= t
.final_objects
.union(extended_objects(bld
, t2
, set()))
770 # find any library loops
772 if t
.samba_type
in ['LIBRARY', 'PYTHON']:
773 for l
in t
.final_libs
.copy():
774 t2
= bld
.name_to_obj(l
, bld
.env
)
775 if t
.sname
in t2
.final_libs
:
776 if getattr(bld
.env
, "ALLOW_CIRCULAR_LIB_DEPENDENCIES", False):
777 # we could break this in either direction. If one of the libraries
778 # has a version number, and will this be distributed publicly, then
779 # we should make it the lower level library in the DAG
780 Logs
.warn('deps: removing library loop %s from %s' % (t
.sname
, t2
.sname
))
781 dependency_loop(loops
, t
, t2
.sname
)
782 t2
.final_libs
.remove(t
.sname
)
784 Logs
.error('ERROR: circular library dependency between %s and %s'
785 % (t
.sname
, t2
.sname
))
789 debug('deps: Found dependency loops for target %s : %s', loop
, loops
[loop
])
791 # we now need to make corrections for any library loops we broke up
792 # any target that depended on the target of the loop and doesn't
793 # depend on the source of the loop needs to get the loop source added
794 for type in ['BINARY','PYTHON','LIBRARY','BINARY']:
796 if t
.samba_type
!= type: continue
798 if loop
in t
.final_libs
:
799 diff
= loops
[loop
].difference(t
.final_libs
)
804 # make sure we don't recreate the loop again!
805 for d
in diff
.copy():
806 t2
= bld
.name_to_obj(d
, bld
.env
)
807 if t2
.samba_type
== 'LIBRARY':
808 if t
.sname
in t2
.final_libs
:
809 debug('deps: removing expansion %s from %s', d
, t
.sname
)
812 debug('deps: Expanded target %s by loop %s libraries (loop %s) %s', t
.sname
, loop
,
814 t
.final_libs
= t
.final_libs
.union(diff
)
816 # remove objects that are also available in linked libs
818 while reduce_objects(bld
, tgt_list
):
821 Logs
.warn("WARNING: Unable to remove all inter-target object duplicates")
823 debug('deps: Object reduction took %u iterations', count
)
825 # add in any syslib dependencies
827 if not t
.samba_type
in ['BINARY','PYTHON','LIBRARY']:
830 for d
in t
.final_objects
:
831 t2
= bld
.name_to_obj(d
, bld
.env
)
832 syslibs
= syslibs
.union(t2
.direct_syslibs
)
833 # this adds the indirect syslibs as well, which may not be needed
834 # depending on the linker flags
835 for d
in t
.final_libs
:
836 t2
= bld
.name_to_obj(d
, bld
.env
)
837 syslibs
= syslibs
.union(t2
.direct_syslibs
)
838 t
.final_syslibs
= syslibs
841 # find any unresolved library loops
842 lib_loop_error
= False
844 if t
.samba_type
in ['LIBRARY', 'PYTHON']:
845 for l
in t
.final_libs
.copy():
846 t2
= bld
.name_to_obj(l
, bld
.env
)
847 if t
.sname
in t2
.final_libs
:
848 Logs
.error('ERROR: Unresolved library loop %s from %s' % (t
.sname
, t2
.sname
))
849 lib_loop_error
= True
853 debug('deps: removed duplicate dependencies')
856 def show_dependencies(bld
, target
, seen
):
857 '''recursively show the dependencies of target'''
862 t
= bld
.name_to_obj(target
, bld
.env
)
864 Logs
.error("ERROR: Unable to find target '%s'" % target
)
867 Logs
.info('%s(OBJECTS): %s' % (target
, t
.direct_objects
))
868 Logs
.info('%s(LIBS): %s' % (target
, t
.direct_libs
))
869 Logs
.info('%s(SYSLIBS): %s' % (target
, t
.direct_syslibs
))
873 for t2
in t
.direct_objects
:
874 show_dependencies(bld
, t2
, seen
)
877 def show_object_duplicates(bld
, tgt_list
):
878 '''show a list of object files that are included in more than
879 one library or binary'''
881 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
885 Logs
.info("showing duplicate objects")
888 if not targets
[t
.sname
] in [ 'LIBRARY', 'PYTHON' ]:
890 for n
in getattr(t
, 'final_objects', set()):
891 t2
= bld
.name_to_obj(n
, bld
.env
)
894 used_by
[n
].add(t
.sname
)
897 if len(used_by
[n
]) > 1:
898 Logs
.info("target '%s' is used by %s" % (n
, used_by
[n
]))
900 Logs
.info("showing indirect dependency counts (sorted by count)")
902 def indirect_count(t1
, t2
):
903 return len(t2
.indirect_objects
) - len(t1
.indirect_objects
)
905 sorted_list
= sorted(tgt_list
, cmp=indirect_count
)
906 for t
in sorted_list
:
907 if len(t
.indirect_objects
) > 1:
908 Logs
.info("%s depends on %u indirect objects" % (t
.sname
, len(t
.indirect_objects
)))
911 ######################################################################
912 # this provides a way to save our dependency calculations between runs
914 savedeps_inputs
= ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags', 'source', 'grouping_library']
915 savedeps_outputs
= ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags', 'ldflags']
916 savedeps_outenv
= ['INC_PATHS']
917 savedeps_envvars
= ['NONSHARED_BINARIES', 'GLOBAL_DEPENDENCIES']
918 savedeps_caches
= ['GLOBAL_DEPENDENCIES', 'TARGET_ALIAS', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
919 savedeps_files
= ['buildtools/wafsamba/samba_deps.py']
921 def save_samba_deps(bld
, tgt_list
):
922 '''save the dependency calculations between builds, to make
923 further builds faster'''
924 denv
= Environment
.Environment()
926 denv
.version
= savedeps_version
927 denv
.savedeps_inputs
= savedeps_inputs
928 denv
.savedeps_outputs
= savedeps_outputs
936 for f
in savedeps_files
:
937 denv
.files
[f
] = os
.stat(os
.path
.join(bld
.srcnode
.abspath(), f
)).st_mtime
939 for c
in savedeps_caches
:
940 denv
.caches
[c
] = LOCAL_CACHE(bld
, c
)
942 for e
in savedeps_envvars
:
943 denv
.envvar
[e
] = bld
.env
[e
]
946 # save all the input attributes for each target
948 for attr
in savedeps_inputs
:
949 v
= getattr(t
, attr
, None)
953 denv
.input[t
.sname
] = tdeps
955 # save all the output attributes for each target
957 for attr
in savedeps_outputs
:
958 v
= getattr(t
, attr
, None)
962 denv
.output
[t
.sname
] = tdeps
965 for attr
in savedeps_outenv
:
967 tdeps
[attr
] = t
.env
[attr
]
969 denv
.outenv
[t
.sname
] = tdeps
971 depsfile
= os
.path
.join(bld
.bdir
, "sambadeps")
976 def load_samba_deps(bld
, tgt_list
):
977 '''load a previous set of build dependencies if possible'''
978 depsfile
= os
.path
.join(bld
.bdir
, "sambadeps")
979 denv
= Environment
.Environment()
981 debug('deps: checking saved dependencies')
983 if (denv
.version
!= savedeps_version
or
984 denv
.savedeps_inputs
!= savedeps_inputs
or
985 denv
.savedeps_outputs
!= savedeps_outputs
):
990 # check if critical files have changed
991 for f
in savedeps_files
:
992 if f
not in denv
.files
:
994 if denv
.files
[f
] != os
.stat(os
.path
.join(bld
.srcnode
.abspath(), f
)).st_mtime
:
997 # check if caches are the same
998 for c
in savedeps_caches
:
999 if c
not in denv
.caches
or denv
.caches
[c
] != LOCAL_CACHE(bld
, c
):
1002 # check if caches are the same
1003 for e
in savedeps_envvars
:
1004 if e
not in denv
.envvar
or denv
.envvar
[e
] != bld
.env
[e
]:
1007 # check inputs are the same
1010 for attr
in savedeps_inputs
:
1011 v
= getattr(t
, attr
, None)
1014 if t
.sname
in denv
.input:
1015 olddeps
= denv
.input[t
.sname
]
1018 if tdeps
!= olddeps
:
1019 #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
1022 # put outputs in place
1024 if not t
.sname
in denv
.output
: continue
1025 tdeps
= denv
.output
[t
.sname
]
1027 setattr(t
, a
, tdeps
[a
])
1029 # put output env vars in place
1031 if not t
.sname
in denv
.outenv
: continue
1032 tdeps
= denv
.outenv
[t
.sname
]
1036 debug('deps: loaded saved dependencies')
1041 def check_project_rules(bld
):
1042 '''check the project rules - ensuring the targets are sane'''
1044 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
1048 # build a list of task generators we are interested in
1052 if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON']:
1054 t
= bld
.name_to_obj(tgt
, bld
.env
)
1056 Logs
.error("Target %s of type %s has no task generator" % (tgt
, type))
1060 add_samba_attributes(bld
, tgt_list
)
1062 force_project_rules
= (Options
.options
.SHOWDEPS
or
1063 Options
.options
.SHOW_DUPLICATES
)
1065 if not force_project_rules
and load_samba_deps(bld
, tgt_list
):
1068 bld
.new_rules
= True
1069 Logs
.info("Checking project rules ...")
1071 debug('deps: project rules checking started')
1073 expand_subsystem_deps(bld
)
1074 replace_grouping_libraries(bld
, tgt_list
)
1075 build_direct_deps(bld
, tgt_list
)
1077 break_dependency_loops(bld
, tgt_list
)
1079 if Options
.options
.SHOWDEPS
:
1080 show_dependencies(bld
, Options
.options
.SHOWDEPS
, set())
1082 calculate_final_deps(bld
, tgt_list
, loops
)
1084 if Options
.options
.SHOW_DUPLICATES
:
1085 show_object_duplicates(bld
, tgt_list
)
1087 # run the various attribute generators
1088 for f
in [ build_dependencies
, build_includes
, add_init_functions
]:
1089 debug('deps: project rules checking %s', f
)
1090 for t
in tgt_list
: f(t
)
1092 debug('deps: project rules stage1 completed')
1094 #check_orpaned_targets(bld, tgt_list)
1096 if not check_duplicate_sources(bld
, tgt_list
):
1097 Logs
.error("Duplicate sources present - aborting")
1100 if not check_group_ordering(bld
, tgt_list
):
1101 Logs
.error("Bad group ordering - aborting")
1104 show_final_deps(bld
, tgt_list
)
1106 debug('deps: project rules checking completed - %u targets checked',
1109 if not bld
.is_install
:
1110 save_samba_deps(bld
, tgt_list
)
1112 Logs
.info("Project rules pass")
1115 def CHECK_PROJECT_RULES(bld
):
1116 '''enable checking of project targets for sanity'''
1117 if bld
.env
.added_project_rules
:
1119 bld
.env
.added_project_rules
= True
1120 bld
.add_pre_fun(check_project_rules
)
1121 Build
.BuildContext
.CHECK_PROJECT_RULES
= CHECK_PROJECT_RULES