1 # Samba automatic dependency handling and project rules
3 import os
, sys
, re
, time
5 import Build
, Environment
, Options
, Logs
, Utils
7 from Configure
import conf
9 from samba_bundled
import BUILTIN_LIBRARY
10 from samba_utils
import LOCAL_CACHE
, TO_LIST
, get_tgt_list
, unique_list
, os_path_relpath
11 from samba_autoconf
import library_flags
14 def ADD_GLOBAL_DEPENDENCY(ctx
, dep
):
15 '''add a dependency for all binaries and libraries'''
16 if not 'GLOBAL_DEPENDENCIES' in ctx
.env
:
17 ctx
.env
.GLOBAL_DEPENDENCIES
= []
18 ctx
.env
.GLOBAL_DEPENDENCIES
.append(dep
)
22 def BREAK_CIRCULAR_LIBRARY_DEPENDENCIES(ctx
):
23 '''indicate that circular dependencies between libraries should be broken.'''
24 ctx
.env
.ALLOW_CIRCULAR_LIB_DEPENDENCIES
= True
28 def SET_SYSLIB_DEPS(conf
, target
, deps
):
29 '''setup some implied dependencies for a SYSLIB'''
30 cache
= LOCAL_CACHE(conf
, 'SYSLIB_DEPS')
34 def expand_subsystem_deps(bld
):
35 '''expand the reverse dependencies resulting from subsystem
36 attributes of modules. This is walking over the complete list
37 of declared subsystems, and expands the samba_deps_extended list for any
38 module<->subsystem dependencies'''
40 subsystem_list
= LOCAL_CACHE(bld
, 'INIT_FUNCTIONS')
41 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
43 for subsystem_name
in subsystem_list
:
44 bld
.ASSERT(subsystem_name
in targets
, "Subsystem target %s not declared" % subsystem_name
)
45 type = targets
[subsystem_name
]
46 if type == 'DISABLED' or type == 'EMPTY':
50 # subsystem_name = dcerpc_server (a subsystem)
51 # subsystem = dcerpc_server (a subsystem object)
52 # module_name = rpc_epmapper (a module within the dcerpc_server subsystem)
53 # module = rpc_epmapper (a module object within the dcerpc_server subsystem)
55 subsystem
= bld
.get_tgen_by_name(subsystem_name
)
56 bld
.ASSERT(subsystem
is not None, "Unable to find subsystem %s" % subsystem_name
)
57 for d
in subsystem_list
[subsystem_name
]:
58 module_name
= d
['TARGET']
59 module_type
= targets
[module_name
]
60 if module_type
in ['DISABLED', 'EMPTY']:
62 bld
.ASSERT(subsystem
is not None,
63 "Subsystem target %s for %s (%s) not found" % (subsystem_name
, module_name
, module_type
))
64 if module_type
in ['SUBSYSTEM']:
65 # if a module is a plain object type (not a library) then the
66 # subsystem it is part of needs to have it as a dependency, so targets
67 # that depend on this subsystem get the modules of that subsystem
68 subsystem
.samba_deps_extended
.append(module_name
)
69 subsystem
.samba_deps_extended
= unique_list(subsystem
.samba_deps_extended
)
73 def build_dependencies(self
):
74 '''This builds the dependency list for a target. It runs after all the targets are declared
76 The reason this is not just done in the SAMBA_*() rules is that we have no way of knowing
77 the full dependency list for a target until we have all of the targets declared.
80 if self
.samba_type
in ['LIBRARY', 'BINARY', 'PYTHON']:
81 self
.uselib
= list(self
.final_syslibs
)
82 self
.uselib_local
= list(self
.final_libs
)
83 self
.add_objects
= list(self
.final_objects
)
85 # extra link flags from pkg_config
86 libs
= self
.final_syslibs
.copy()
88 (ccflags
, ldflags
, cpppath
) = library_flags(self
, list(libs
))
89 new_ldflags
= getattr(self
, 'samba_ldflags', [])[:]
90 new_ldflags
.extend(ldflags
)
91 self
.ldflags
= new_ldflags
93 if getattr(self
, 'allow_undefined_symbols', False) and self
.env
.undefined_ldflags
:
94 for f
in self
.env
.undefined_ldflags
:
95 self
.ldflags
.remove(f
)
97 if getattr(self
, 'allow_undefined_symbols', False) and self
.env
.undefined_ignore_ldflags
:
98 for f
in self
.env
.undefined_ignore_ldflags
:
99 self
.ldflags
.append(f
)
101 debug('deps: computed dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
102 self
.sname
, self
.uselib
, self
.uselib_local
, self
.add_objects
)
104 if self
.samba_type
in ['SUBSYSTEM']:
105 # this is needed for the ccflags of libs that come from pkg_config
106 self
.uselib
= list(self
.final_syslibs
)
107 self
.uselib
.extend(list(self
.direct_syslibs
))
108 for lib
in self
.final_libs
:
109 t
= self
.bld
.get_tgen_by_name(lib
)
110 self
.uselib
.extend(list(t
.final_syslibs
))
111 self
.uselib
= unique_list(self
.uselib
)
113 if getattr(self
, 'uselib', None):
115 for l
in self
.uselib
:
116 up_list
.append(l
.upper())
117 self
.uselib
= up_list
120 def build_includes(self
):
121 '''This builds the right set of includes for a target.
123 One tricky part of this is that the includes= attribute for a
124 target needs to use paths which are relative to that targets
125 declaration directory (which we can get at via t.path).
127 The way this works is the includes list gets added as
128 samba_includes in the main build task declaration. Then this
129 function runs after all of the tasks are declared, and it
130 processes the samba_includes attribute to produce a includes=
134 if getattr(self
, 'samba_includes', None) is None:
139 inc_deps
= includes_objects(bld
, self
, set(), {})
143 # maybe add local includes
144 if getattr(self
, 'local_include', True) and getattr(self
, 'local_include_first', True):
147 includes
.extend(self
.samba_includes_extended
)
149 if 'EXTRA_INCLUDES' in bld
.env
and getattr(self
, 'global_include', True):
150 includes
.extend(bld
.env
['EXTRA_INCLUDES'])
158 t
= bld
.get_tgen_by_name(d
)
159 bld
.ASSERT(t
is not None, "Unable to find dependency %s for %s" % (d
, self
.sname
))
160 inclist
= getattr(t
, 'samba_includes_extended', [])[:]
161 if getattr(t
, 'local_include', True):
165 tpath
= t
.samba_abspath
167 npath
= tpath
+ '/' + inc
168 if not npath
in inc_set
:
169 inc_abs
.append(npath
)
172 mypath
= self
.path
.abspath(bld
.env
)
174 relpath
= os_path_relpath(inc
, mypath
)
175 includes
.append(relpath
)
177 if getattr(self
, 'local_include', True) and not getattr(self
, 'local_include_first', True):
180 # now transform the includes list to be relative to the top directory
181 # which is represented by '#' in waf. This allows waf to cache the
182 # includes lists more efficiently
186 # some are already top based
187 includes_top
.append(i
)
189 absinc
= os
.path
.join(self
.path
.abspath(), i
)
190 relinc
= os_path_relpath(absinc
, self
.bld
.srcnode
.abspath())
191 includes_top
.append('#' + relinc
)
193 self
.includes
= unique_list(includes_top
)
194 debug('deps: includes for target %s: includes=%s',
195 self
.sname
, self
.includes
)
198 def add_init_functions(self
):
199 '''This builds the right set of init functions'''
203 subsystems
= LOCAL_CACHE(bld
, 'INIT_FUNCTIONS')
205 # cope with the separated object lists from BINARY and LIBRARY targets
207 if sname
.endswith('.objlist'):
211 if sname
in subsystems
:
212 modules
.append(sname
)
214 m
= getattr(self
, 'samba_modules', None)
216 modules
.extend(TO_LIST(m
))
218 m
= getattr(self
, 'samba_subsystem', None)
222 if 'pyembed' in self
.features
:
225 sentinel
= getattr(self
, 'init_function_sentinel', 'NULL')
227 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
228 cflags
= getattr(self
, 'samba_cflags', [])[:]
231 sname
= sname
.replace('-','_')
232 sname
= sname
.replace('/','_')
233 cflags
.append('-DSTATIC_%s_MODULES=%s' % (sname
, sentinel
))
234 if sentinel
== 'NULL':
235 proto
= "extern void __%s_dummy_module_proto(void)" % (sname
)
236 cflags
.append('-DSTATIC_%s_MODULES_PROTO=%s' % (sname
, proto
))
237 self
.ccflags
= cflags
241 bld
.ASSERT(m
in subsystems
,
242 "No init_function defined for module '%s' in target '%s'" % (m
, self
.sname
))
244 for d
in subsystems
[m
]:
245 if targets
[d
['TARGET']] != 'DISABLED':
246 init_fn_list
.append(d
['INIT_FUNCTION'])
247 if init_fn_list
== []:
248 cflags
.append('-DSTATIC_%s_MODULES=%s' % (m
, sentinel
))
249 if sentinel
== 'NULL':
250 proto
= "extern void __%s_dummy_module_proto(void)" % (m
)
251 cflags
.append('-DSTATIC_%s_MODULES_PROTO=%s' % (m
, proto
))
253 cflags
.append('-DSTATIC_%s_MODULES=%s' % (m
, ','.join(init_fn_list
) + ',' + sentinel
))
255 for f
in init_fn_list
:
256 proto
+= '_MODULE_PROTO(%s)' % f
257 proto
+= "extern void __%s_dummy_module_proto(void)" % (m
)
258 cflags
.append('-DSTATIC_%s_MODULES_PROTO=%s' % (m
, proto
))
259 self
.ccflags
= cflags
262 def check_duplicate_sources(bld
, tgt_list
):
263 '''see if we are compiling the same source file more than once'''
265 debug('deps: checking for duplicate sources')
266 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
269 source_list
= TO_LIST(getattr(t
, 'source', ''))
270 tpath
= os
.path
.normpath(os_path_relpath(t
.path
.abspath(bld
.env
), t
.env
.BUILD_DIRECTORY
+ '/default'))
272 for s
in source_list
:
273 p
= os
.path
.normpath(os
.path
.join(tpath
, s
))
275 Logs
.error("ERROR: source %s appears twice in target '%s'" % (p
, t
.sname
))
278 t
.samba_source_set
= obj_sources
282 # build a list of targets that each source file is part of
284 if not targets
[t
.sname
] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
286 for obj
in t
.add_objects
:
287 t2
= t
.bld
.get_tgen_by_name(obj
)
288 source_set
= getattr(t2
, 'samba_source_set', set())
290 if not s
in subsystems
:
292 if not t
.sname
in subsystems
[s
]:
293 subsystems
[s
][t
.sname
] = []
294 subsystems
[s
][t
.sname
].append(t2
.sname
)
297 if len(subsystems
[s
]) > 1 and Options
.options
.SHOW_DUPLICATES
:
298 Logs
.warn("WARNING: source %s is in more than one target: %s" % (s
, subsystems
[s
].keys()))
299 for tname
in subsystems
[s
]:
300 if len(subsystems
[s
][tname
]) > 1:
301 raise Utils
.WafError("ERROR: source %s is in more than one subsystem of target '%s': %s" % (s
, tname
, subsystems
[s
][tname
]))
305 def check_group_ordering(bld
, tgt_list
):
306 '''see if we have any dependencies that violate the group ordering
308 It is an error for a target to depend on a target from a later
313 tm
= bld
.task_manager
314 return [x
for x
in tm
.groups_names
if id(tm
.groups_names
[x
]) == id(g
)][0]
316 for g
in bld
.task_manager
.groups
:
317 gname
= group_name(g
)
318 for t
in g
.tasks_gen
:
319 t
.samba_group
= gname
323 for g
in bld
.task_manager
.groups
:
328 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
332 tdeps
= getattr(t
, 'add_objects', []) + getattr(t
, 'uselib_local', [])
334 t2
= bld
.get_tgen_by_name(d
)
337 map1
= grp_map
[t
.samba_group
]
338 map2
= grp_map
[t2
.samba_group
]
341 Logs
.error("Target %r in build group %r depends on target %r from later build group %r" % (
342 t
.sname
, t
.samba_group
, t2
.sname
, t2
.samba_group
))
346 Build
.BuildContext
.check_group_ordering
= check_group_ordering
348 def show_final_deps(bld
, tgt_list
):
349 '''show the final dependencies for all targets'''
351 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
354 if not targets
[t
.sname
] in ['LIBRARY', 'BINARY', 'PYTHON', 'SUBSYSTEM']:
356 debug('deps: final dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
357 t
.sname
, t
.uselib
, getattr(t
, 'uselib_local', []), getattr(t
, 'add_objects', []))
360 def add_samba_attributes(bld
, tgt_list
):
361 '''ensure a target has a the required samba attributes'''
363 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
370 t
.samba_type
= targets
[t
.sname
]
371 t
.samba_abspath
= t
.path
.abspath(bld
.env
)
372 t
.samba_deps_extended
= t
.samba_deps
[:]
373 t
.samba_includes_extended
= TO_LIST(t
.samba_includes
)[:]
374 t
.ccflags
= getattr(t
, 'samba_cflags', '')
376 def replace_grouping_libraries(bld
, tgt_list
):
377 '''replace dependencies based on grouping libraries
379 If a library is marked as a grouping library, then any target that
380 depends on a subsystem that is part of that grouping library gets
381 that dependency replaced with a dependency on the grouping library
384 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
388 # find our list of grouping libraries, mapped from the subsystems they depend on
390 if not getattr(t
, 'grouping_library', False):
392 for dep
in t
.samba_deps_extended
:
393 bld
.ASSERT(dep
in targets
, "grouping library target %s not declared in %s" % (dep
, t
.sname
))
394 if targets
[dep
] == 'SUBSYSTEM':
395 grouping
[dep
] = t
.sname
397 # now replace any dependencies on elements of grouping libraries
399 for i
in range(len(t
.samba_deps_extended
)):
400 dep
= t
.samba_deps_extended
[i
]
402 if t
.sname
!= grouping
[dep
]:
403 debug("deps: target %s: replacing dependency %s with grouping library %s" % (t
.sname
, dep
, grouping
[dep
]))
404 t
.samba_deps_extended
[i
] = grouping
[dep
]
408 def build_direct_deps(bld
, tgt_list
):
409 '''build the direct_objects and direct_libs sets for each target'''
411 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
412 syslib_deps
= LOCAL_CACHE(bld
, 'SYSLIB_DEPS')
414 global_deps
= bld
.env
.GLOBAL_DEPENDENCIES
415 global_deps_exclude
= set()
416 for dep
in global_deps
:
417 t
= bld
.get_tgen_by_name(dep
)
418 for d
in t
.samba_deps
:
419 # prevent loops from the global dependencies list
420 global_deps_exclude
.add(d
)
421 global_deps_exclude
.add(d
+ '.objlist')
424 t
.direct_objects
= set()
425 t
.direct_libs
= set()
426 t
.direct_syslibs
= set()
427 deps
= t
.samba_deps_extended
[:]
428 if getattr(t
, 'samba_use_global_deps', False) and not t
.sname
in global_deps_exclude
:
429 deps
.extend(global_deps
)
431 if d
== t
.sname
: continue
433 Logs
.error("Unknown dependency '%s' in '%s'" % (d
, t
.sname
))
435 if targets
[d
] in [ 'EMPTY', 'DISABLED' ]:
437 if targets
[d
] == 'PYTHON' and targets
[t
.sname
] != 'PYTHON' and t
.sname
.find('.objlist') == -1:
438 # this check should be more restrictive, but for now we have pidl-generated python
439 # code that directly depends on other python modules
440 Logs
.error('ERROR: Target %s has dependency on python module %s' % (t
.sname
, d
))
442 if targets
[d
] == 'SYSLIB':
443 t
.direct_syslibs
.add(d
)
445 for implied
in TO_LIST(syslib_deps
[d
]):
446 if BUILTIN_LIBRARY(bld
, implied
):
447 t
.direct_objects
.add(implied
)
448 elif targets
[implied
] == 'SYSLIB':
449 t
.direct_syslibs
.add(implied
)
450 elif targets
[implied
] in ['LIBRARY', 'MODULE']:
451 t
.direct_libs
.add(implied
)
453 Logs
.error('Implied dependency %s in %s is of type %s' % (
454 implied
, t
.sname
, targets
[implied
]))
457 t2
= bld
.get_tgen_by_name(d
)
459 Logs
.error("no task %s of type %s in %s" % (d
, targets
[d
], t
.sname
))
461 if t2
.samba_type
in [ 'LIBRARY', 'MODULE' ]:
463 elif t2
.samba_type
in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]:
464 t
.direct_objects
.add(d
)
465 debug('deps: built direct dependencies')
468 def dependency_loop(loops
, t
, target
):
469 '''add a dependency loop to the loops dictionary'''
470 if t
.sname
== target
:
472 if not target
in loops
:
473 loops
[target
] = set()
474 if not t
.sname
in loops
[target
]:
475 loops
[target
].add(t
.sname
)
478 def indirect_libs(bld
, t
, chain
, loops
):
479 '''recursively calculate the indirect library dependencies for a target
481 An indirect library is a library that results from a dependency on
485 ret
= getattr(t
, 'indirect_libs', None)
490 for obj
in t
.direct_objects
:
492 dependency_loop(loops
, t
, obj
)
495 t2
= bld
.get_tgen_by_name(obj
)
496 r2
= indirect_libs(bld
, t2
, chain
, loops
)
498 ret
= ret
.union(t2
.direct_libs
)
501 for obj
in indirect_objects(bld
, t
, set(), loops
):
503 dependency_loop(loops
, t
, obj
)
506 t2
= bld
.get_tgen_by_name(obj
)
507 r2
= indirect_libs(bld
, t2
, chain
, loops
)
509 ret
= ret
.union(t2
.direct_libs
)
512 t
.indirect_libs
= ret
517 def indirect_objects(bld
, t
, chain
, loops
):
518 '''recursively calculate the indirect object dependencies for a target
520 indirect objects are the set of objects from expanding the
521 subsystem dependencies
524 ret
= getattr(t
, 'indirect_objects', None)
525 if ret
is not None: return ret
528 for lib
in t
.direct_objects
:
530 dependency_loop(loops
, t
, lib
)
533 t2
= bld
.get_tgen_by_name(lib
)
534 r2
= indirect_objects(bld
, t2
, chain
, loops
)
536 ret
= ret
.union(t2
.direct_objects
)
539 t
.indirect_objects
= ret
543 def extended_objects(bld
, t
, chain
):
544 '''recursively calculate the extended object dependencies for a target
546 extended objects are the union of:
549 - direct and indirect objects of all direct and indirect libraries
552 ret
= getattr(t
, 'extended_objects', None)
553 if ret
is not None: return ret
556 ret
= ret
.union(t
.final_objects
)
558 for lib
in t
.final_libs
:
561 t2
= bld
.get_tgen_by_name(lib
)
563 r2
= extended_objects(bld
, t2
, chain
)
565 ret
= ret
.union(t2
.final_objects
)
568 t
.extended_objects
= ret
572 def includes_objects(bld
, t
, chain
, inc_loops
):
573 '''recursively calculate the includes object dependencies for a target
575 includes dependencies come from either library or object dependencies
577 ret
= getattr(t
, 'includes_objects', None)
581 ret
= t
.direct_objects
.copy()
582 ret
= ret
.union(t
.direct_libs
)
584 for obj
in t
.direct_objects
:
586 dependency_loop(inc_loops
, t
, obj
)
589 t2
= bld
.get_tgen_by_name(obj
)
590 r2
= includes_objects(bld
, t2
, chain
, inc_loops
)
592 ret
= ret
.union(t2
.direct_objects
)
595 for lib
in t
.direct_libs
:
597 dependency_loop(inc_loops
, t
, lib
)
600 t2
= bld
.get_tgen_by_name(lib
)
602 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
603 Logs
.error('Target %s of type %s not found in direct_libs for %s' % (
604 lib
, targets
[lib
], t
.sname
))
606 r2
= includes_objects(bld
, t2
, chain
, inc_loops
)
608 ret
= ret
.union(t2
.direct_objects
)
611 t
.includes_objects
= ret
615 def break_dependency_loops(bld
, tgt_list
):
616 '''find and break dependency loops'''
620 # build up the list of loops
622 indirect_objects(bld
, t
, set(), loops
)
623 indirect_libs(bld
, t
, set(), loops
)
624 includes_objects(bld
, t
, set(), inc_loops
)
629 for attr
in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
630 objs
= getattr(t
, attr
, set())
631 setattr(t
, attr
, objs
.difference(loops
[t
.sname
]))
634 debug('deps: Found dependency loops for target %s : %s', loop
, loops
[loop
])
636 for loop
in inc_loops
:
637 debug('deps: Found include loops for target %s : %s', loop
, inc_loops
[loop
])
639 # expand the loops mapping by one level
640 for loop
in loops
.copy():
641 for tgt
in loops
[loop
]:
643 loops
[loop
] = loops
[loop
].union(loops
[tgt
])
645 for loop
in inc_loops
.copy():
646 for tgt
in inc_loops
[loop
]:
648 inc_loops
[loop
] = inc_loops
[loop
].union(inc_loops
[tgt
])
651 # expand indirect subsystem and library loops
652 for loop
in loops
.copy():
653 t
= bld
.get_tgen_by_name(loop
)
654 if t
.samba_type
in ['SUBSYSTEM']:
655 loops
[loop
] = loops
[loop
].union(t
.indirect_objects
)
656 loops
[loop
] = loops
[loop
].union(t
.direct_objects
)
657 if t
.samba_type
in ['LIBRARY','PYTHON']:
658 loops
[loop
] = loops
[loop
].union(t
.indirect_libs
)
659 loops
[loop
] = loops
[loop
].union(t
.direct_libs
)
660 if loop
in loops
[loop
]:
661 loops
[loop
].remove(loop
)
663 # expand indirect includes loops
664 for loop
in inc_loops
.copy():
665 t
= bld
.get_tgen_by_name(loop
)
666 inc_loops
[loop
] = inc_loops
[loop
].union(t
.includes_objects
)
667 if loop
in inc_loops
[loop
]:
668 inc_loops
[loop
].remove(loop
)
670 # add in the replacement dependencies
673 for attr
in ['indirect_objects', 'indirect_libs']:
674 objs
= getattr(t
, attr
, set())
676 diff
= loops
[loop
].difference(objs
)
680 debug('deps: Expanded target %s of type %s from loop %s by %s', t
.sname
, t
.samba_type
, loop
, diff
)
681 objs
= objs
.union(diff
)
682 setattr(t
, attr
, objs
)
684 for loop
in inc_loops
:
685 objs
= getattr(t
, 'includes_objects', set())
687 diff
= inc_loops
[loop
].difference(objs
)
691 debug('deps: Expanded target %s includes of type %s from loop %s by %s', t
.sname
, t
.samba_type
, loop
, diff
)
692 objs
= objs
.union(diff
)
693 setattr(t
, 'includes_objects', objs
)
696 def reduce_objects(bld
, tgt_list
):
697 '''reduce objects by looking for indirect object dependencies'''
701 t
.extended_objects
= None
705 for type in ['BINARY', 'PYTHON', 'LIBRARY']:
707 if t
.samba_type
!= type: continue
708 # if we will indirectly link to a target then we don't need it
709 new
= t
.final_objects
.copy()
710 for l
in t
.final_libs
:
711 t2
= bld
.get_tgen_by_name(l
)
712 t2_obj
= extended_objects(bld
, t2
, set())
713 dup
= new
.intersection(t2_obj
)
714 if t
.sname
in rely_on
:
715 dup
= dup
.difference(rely_on
[t
.sname
])
717 debug('deps: removing dups from %s of type %s: %s also in %s %s',
718 t
.sname
, t
.samba_type
, dup
, t2
.samba_type
, l
)
719 new
= new
.difference(dup
)
723 rely_on
[l
] = rely_on
[l
].union(dup
)
724 t
.final_objects
= new
729 # add back in any objects that were relied upon by the reduction rules
731 t
= bld
.get_tgen_by_name(r
)
732 t
.final_objects
= t
.final_objects
.union(rely_on
[r
])
737 def show_library_loop(bld
, lib1
, lib2
, path
, seen
):
738 '''show the detailed path of a library loop between lib1 and lib2'''
740 t
= bld
.get_tgen_by_name(lib1
)
741 if not lib2
in getattr(t
, 'final_libs', set()):
744 for d
in t
.samba_deps_extended
:
748 path2
= path
+ '=>' + d
750 Logs
.warn('library loop path: ' + path2
)
752 show_library_loop(bld
, d
, lib2
, path2
, seen
)
756 def calculate_final_deps(bld
, tgt_list
, loops
):
757 '''calculate the final library and object dependencies'''
759 # start with the maximum possible list
760 t
.final_libs
= t
.direct_libs
.union(indirect_libs(bld
, t
, set(), loops
))
761 t
.final_objects
= t
.direct_objects
.union(indirect_objects(bld
, t
, set(), loops
))
764 # don't depend on ourselves
765 if t
.sname
in t
.final_libs
:
766 t
.final_libs
.remove(t
.sname
)
767 if t
.sname
in t
.final_objects
:
768 t
.final_objects
.remove(t
.sname
)
770 # handle any non-shared binaries
772 if t
.samba_type
== 'BINARY' and bld
.NONSHARED_BINARY(t
.sname
):
773 subsystem_list
= LOCAL_CACHE(bld
, 'INIT_FUNCTIONS')
774 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
776 # replace lib deps with objlist deps
777 for l
in t
.final_libs
:
778 objname
= l
+ '.objlist'
779 t2
= bld
.get_tgen_by_name(objname
)
781 Logs
.error('ERROR: subsystem %s not found' % objname
)
783 t
.final_objects
.add(objname
)
784 t
.final_objects
= t
.final_objects
.union(extended_objects(bld
, t2
, set()))
785 if l
in subsystem_list
:
786 # its a subsystem - we also need the contents of any modules
787 for d
in subsystem_list
[l
]:
788 module_name
= d
['TARGET']
789 if targets
[module_name
] == 'LIBRARY':
790 objname
= module_name
+ '.objlist'
791 elif targets
[module_name
] == 'SUBSYSTEM':
792 objname
= module_name
795 t2
= bld
.get_tgen_by_name(objname
)
797 Logs
.error('ERROR: subsystem %s not found' % objname
)
799 t
.final_objects
.add(objname
)
800 t
.final_objects
= t
.final_objects
.union(extended_objects(bld
, t2
, set()))
803 # find any library loops
805 if t
.samba_type
in ['LIBRARY', 'PYTHON']:
806 for l
in t
.final_libs
.copy():
807 t2
= bld
.get_tgen_by_name(l
)
808 if t
.sname
in t2
.final_libs
:
809 if getattr(bld
.env
, "ALLOW_CIRCULAR_LIB_DEPENDENCIES", False):
810 # we could break this in either direction. If one of the libraries
811 # has a version number, and will this be distributed publicly, then
812 # we should make it the lower level library in the DAG
813 Logs
.warn('deps: removing library loop %s from %s' % (t
.sname
, t2
.sname
))
814 dependency_loop(loops
, t
, t2
.sname
)
815 t2
.final_libs
.remove(t
.sname
)
817 Logs
.error('ERROR: circular library dependency between %s and %s'
818 % (t
.sname
, t2
.sname
))
819 show_library_loop(bld
, t
.sname
, t2
.sname
, t
.sname
, set())
820 show_library_loop(bld
, t2
.sname
, t
.sname
, t2
.sname
, set())
824 debug('deps: Found dependency loops for target %s : %s', loop
, loops
[loop
])
826 # we now need to make corrections for any library loops we broke up
827 # any target that depended on the target of the loop and doesn't
828 # depend on the source of the loop needs to get the loop source added
829 for type in ['BINARY','PYTHON','LIBRARY','BINARY']:
831 if t
.samba_type
!= type: continue
833 if loop
in t
.final_libs
:
834 diff
= loops
[loop
].difference(t
.final_libs
)
839 # make sure we don't recreate the loop again!
840 for d
in diff
.copy():
841 t2
= bld
.get_tgen_by_name(d
)
842 if t2
.samba_type
== 'LIBRARY':
843 if t
.sname
in t2
.final_libs
:
844 debug('deps: removing expansion %s from %s', d
, t
.sname
)
847 debug('deps: Expanded target %s by loop %s libraries (loop %s) %s', t
.sname
, loop
,
849 t
.final_libs
= t
.final_libs
.union(diff
)
851 # remove objects that are also available in linked libs
853 while reduce_objects(bld
, tgt_list
):
856 Logs
.warn("WARNING: Unable to remove all inter-target object duplicates")
858 debug('deps: Object reduction took %u iterations', count
)
860 # add in any syslib dependencies
862 if not t
.samba_type
in ['BINARY','PYTHON','LIBRARY','SUBSYSTEM']:
865 for d
in t
.final_objects
:
866 t2
= bld
.get_tgen_by_name(d
)
867 syslibs
= syslibs
.union(t2
.direct_syslibs
)
868 # this adds the indirect syslibs as well, which may not be needed
869 # depending on the linker flags
870 for d
in t
.final_libs
:
871 t2
= bld
.get_tgen_by_name(d
)
872 syslibs
= syslibs
.union(t2
.direct_syslibs
)
873 t
.final_syslibs
= syslibs
876 # find any unresolved library loops
877 lib_loop_error
= False
879 if t
.samba_type
in ['LIBRARY', 'PYTHON']:
880 for l
in t
.final_libs
.copy():
881 t2
= bld
.get_tgen_by_name(l
)
882 if t
.sname
in t2
.final_libs
:
883 Logs
.error('ERROR: Unresolved library loop %s from %s' % (t
.sname
, t2
.sname
))
884 lib_loop_error
= True
888 debug('deps: removed duplicate dependencies')
891 def show_dependencies(bld
, target
, seen
):
892 '''recursively show the dependencies of target'''
897 t
= bld
.get_tgen_by_name(target
)
899 Logs
.error("ERROR: Unable to find target '%s'" % target
)
902 Logs
.info('%s(OBJECTS): %s' % (target
, t
.direct_objects
))
903 Logs
.info('%s(LIBS): %s' % (target
, t
.direct_libs
))
904 Logs
.info('%s(SYSLIBS): %s' % (target
, t
.direct_syslibs
))
908 for t2
in t
.direct_objects
:
909 show_dependencies(bld
, t2
, seen
)
912 def show_object_duplicates(bld
, tgt_list
):
913 '''show a list of object files that are included in more than
914 one library or binary'''
916 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
920 Logs
.info("showing duplicate objects")
923 if not targets
[t
.sname
] in [ 'LIBRARY', 'PYTHON' ]:
925 for n
in getattr(t
, 'final_objects', set()):
926 t2
= bld
.get_tgen_by_name(n
)
929 used_by
[n
].add(t
.sname
)
932 if len(used_by
[n
]) > 1:
933 Logs
.info("target '%s' is used by %s" % (n
, used_by
[n
]))
935 Logs
.info("showing indirect dependency counts (sorted by count)")
937 def indirect_count(t1
, t2
):
938 return len(t2
.indirect_objects
) - len(t1
.indirect_objects
)
940 sorted_list
= sorted(tgt_list
, cmp=indirect_count
)
941 for t
in sorted_list
:
942 if len(t
.indirect_objects
) > 1:
943 Logs
.info("%s depends on %u indirect objects" % (t
.sname
, len(t
.indirect_objects
)))
946 ######################################################################
947 # this provides a way to save our dependency calculations between runs
949 savedeps_inputs
= ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags',
950 'source', 'grouping_library', 'samba_ldflags', 'allow_undefined_symbols',
951 'use_global_deps', 'global_include' ]
952 savedeps_outputs
= ['uselib', 'uselib_local', 'add_objects', 'includes',
953 'ccflags', 'ldflags', 'samba_deps_extended', 'final_libs']
954 savedeps_outenv
= ['INC_PATHS']
955 savedeps_envvars
= ['NONSHARED_BINARIES', 'GLOBAL_DEPENDENCIES', 'EXTRA_CFLAGS', 'EXTRA_LDFLAGS', 'EXTRA_INCLUDES' ]
956 savedeps_caches
= ['GLOBAL_DEPENDENCIES', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
957 savedeps_files
= ['buildtools/wafsamba/samba_deps.py']
959 def save_samba_deps(bld
, tgt_list
):
960 '''save the dependency calculations between builds, to make
961 further builds faster'''
962 denv
= Environment
.Environment()
964 denv
.version
= savedeps_version
965 denv
.savedeps_inputs
= savedeps_inputs
966 denv
.savedeps_outputs
= savedeps_outputs
974 for f
in savedeps_files
:
975 denv
.files
[f
] = os
.stat(os
.path
.join(bld
.srcnode
.abspath(), f
)).st_mtime
977 for c
in savedeps_caches
:
978 denv
.caches
[c
] = LOCAL_CACHE(bld
, c
)
980 for e
in savedeps_envvars
:
981 denv
.envvar
[e
] = bld
.env
[e
]
984 # save all the input attributes for each target
986 for attr
in savedeps_inputs
:
987 v
= getattr(t
, attr
, None)
991 denv
.input[t
.sname
] = tdeps
993 # save all the output attributes for each target
995 for attr
in savedeps_outputs
:
996 v
= getattr(t
, attr
, None)
1000 denv
.output
[t
.sname
] = tdeps
1003 for attr
in savedeps_outenv
:
1005 tdeps
[attr
] = t
.env
[attr
]
1007 denv
.outenv
[t
.sname
] = tdeps
1009 depsfile
= os
.path
.join(bld
.bdir
, "sambadeps")
1010 denv
.store_fast(depsfile
)
1014 def load_samba_deps(bld
, tgt_list
):
1015 '''load a previous set of build dependencies if possible'''
1016 depsfile
= os
.path
.join(bld
.bdir
, "sambadeps")
1017 denv
= Environment
.Environment()
1019 debug('deps: checking saved dependencies')
1020 denv
.load_fast(depsfile
)
1021 if (denv
.version
!= savedeps_version
or
1022 denv
.savedeps_inputs
!= savedeps_inputs
or
1023 denv
.savedeps_outputs
!= savedeps_outputs
):
1028 # check if critical files have changed
1029 for f
in savedeps_files
:
1030 if f
not in denv
.files
:
1032 if denv
.files
[f
] != os
.stat(os
.path
.join(bld
.srcnode
.abspath(), f
)).st_mtime
:
1035 # check if caches are the same
1036 for c
in savedeps_caches
:
1037 if c
not in denv
.caches
or denv
.caches
[c
] != LOCAL_CACHE(bld
, c
):
1040 # check if caches are the same
1041 for e
in savedeps_envvars
:
1042 if e
not in denv
.envvar
or denv
.envvar
[e
] != bld
.env
[e
]:
1045 # check inputs are the same
1048 for attr
in savedeps_inputs
:
1049 v
= getattr(t
, attr
, None)
1052 if t
.sname
in denv
.input:
1053 olddeps
= denv
.input[t
.sname
]
1056 if tdeps
!= olddeps
:
1057 #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
1060 # put outputs in place
1062 if not t
.sname
in denv
.output
: continue
1063 tdeps
= denv
.output
[t
.sname
]
1065 setattr(t
, a
, tdeps
[a
])
1067 # put output env vars in place
1069 if not t
.sname
in denv
.outenv
: continue
1070 tdeps
= denv
.outenv
[t
.sname
]
1074 debug('deps: loaded saved dependencies')
1079 def check_project_rules(bld
):
1080 '''check the project rules - ensuring the targets are sane'''
1085 tgt_list
= get_tgt_list(bld
)
1087 add_samba_attributes(bld
, tgt_list
)
1089 force_project_rules
= (Options
.options
.SHOWDEPS
or
1090 Options
.options
.SHOW_DUPLICATES
)
1092 if not force_project_rules
and load_samba_deps(bld
, tgt_list
):
1096 tstart
= time
.clock()
1098 bld
.new_rules
= True
1099 Logs
.info("Checking project rules ...")
1101 debug('deps: project rules checking started')
1103 expand_subsystem_deps(bld
)
1105 debug("deps: expand_subsystem_deps: %f" % (time
.clock() - tstart
))
1107 replace_grouping_libraries(bld
, tgt_list
)
1109 debug("deps: replace_grouping_libraries: %f" % (time
.clock() - tstart
))
1111 build_direct_deps(bld
, tgt_list
)
1113 debug("deps: build_direct_deps: %f" % (time
.clock() - tstart
))
1115 break_dependency_loops(bld
, tgt_list
)
1117 debug("deps: break_dependency_loops: %f" % (time
.clock() - tstart
))
1119 if Options
.options
.SHOWDEPS
:
1120 show_dependencies(bld
, Options
.options
.SHOWDEPS
, set())
1122 calculate_final_deps(bld
, tgt_list
, loops
)
1124 debug("deps: calculate_final_deps: %f" % (time
.clock() - tstart
))
1126 if Options
.options
.SHOW_DUPLICATES
:
1127 show_object_duplicates(bld
, tgt_list
)
1129 # run the various attribute generators
1130 for f
in [ build_dependencies
, build_includes
, add_init_functions
]:
1131 debug('deps: project rules checking %s', f
)
1132 for t
in tgt_list
: f(t
)
1133 debug("deps: %s: %f" % (f
, time
.clock() - tstart
))
1135 debug('deps: project rules stage1 completed')
1137 if not check_duplicate_sources(bld
, tgt_list
):
1138 Logs
.error("Duplicate sources present - aborting")
1141 debug("deps: check_duplicate_sources: %f" % (time
.clock() - tstart
))
1143 if not bld
.check_group_ordering(tgt_list
):
1144 Logs
.error("Bad group ordering - aborting")
1147 debug("deps: check_group_ordering: %f" % (time
.clock() - tstart
))
1149 show_final_deps(bld
, tgt_list
)
1151 debug("deps: show_final_deps: %f" % (time
.clock() - tstart
))
1153 debug('deps: project rules checking completed - %u targets checked',
1156 if not bld
.is_install
:
1157 save_samba_deps(bld
, tgt_list
)
1159 debug("deps: save_samba_deps: %f" % (time
.clock() - tstart
))
1161 Logs
.info("Project rules pass")
1164 def CHECK_PROJECT_RULES(bld
):
1165 '''enable checking of project targets for sanity'''
1166 if bld
.env
.added_project_rules
:
1168 bld
.env
.added_project_rules
= True
1169 bld
.add_pre_fun(check_project_rules
)
1170 Build
.BuildContext
.CHECK_PROJECT_RULES
= CHECK_PROJECT_RULES