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 sname
= sname
.replace('/','_')
234 cflags
.append('-DSTATIC_%s_MODULES=%s' % (sname
, sentinel
))
235 if sentinel
== 'NULL':
236 proto
= "extern void __%s_dummy_module_proto(void)" % (sname
)
237 cflags
.append('-DSTATIC_%s_MODULES_PROTO=%s' % (sname
, proto
))
238 self
.ccflags
= cflags
242 bld
.ASSERT(m
in subsystems
,
243 "No init_function defined for module '%s' in target '%s'" % (m
, self
.sname
))
245 for d
in subsystems
[m
]:
246 if targets
[d
['TARGET']] != 'DISABLED':
247 init_fn_list
.append(d
['INIT_FUNCTION'])
248 if init_fn_list
== []:
249 cflags
.append('-DSTATIC_%s_MODULES=%s' % (m
, sentinel
))
250 if sentinel
== 'NULL':
251 proto
= "extern void __%s_dummy_module_proto(void)" % (m
)
252 cflags
.append('-DSTATIC_%s_MODULES_PROTO=%s' % (m
, proto
))
254 cflags
.append('-DSTATIC_%s_MODULES=%s' % (m
, ','.join(init_fn_list
) + ',' + sentinel
))
256 for f
in init_fn_list
:
257 proto
+= '_MODULE_PROTO(%s)' % f
258 proto
+= "extern void __%s_dummy_module_proto(void)" % (m
)
259 cflags
.append('-DSTATIC_%s_MODULES_PROTO=%s' % (m
, proto
))
260 self
.ccflags
= cflags
263 def check_duplicate_sources(bld
, tgt_list
):
264 '''see if we are compiling the same source file more than once'''
266 debug('deps: checking for duplicate sources')
267 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
270 source_list
= TO_LIST(getattr(t
, 'source', ''))
271 tpath
= os
.path
.normpath(os_path_relpath(t
.path
.abspath(bld
.env
), t
.env
.BUILD_DIRECTORY
+ '/default'))
273 for s
in source_list
:
274 p
= os
.path
.normpath(os
.path
.join(tpath
, s
))
276 Logs
.error("ERROR: source %s appears twice in target '%s'" % (p
, t
.sname
))
279 t
.samba_source_set
= obj_sources
283 # build a list of targets that each source file is part of
285 if not targets
[t
.sname
] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
287 for obj
in t
.add_objects
:
288 t2
= t
.bld
.get_tgen_by_name(obj
)
289 source_set
= getattr(t2
, 'samba_source_set', set())
291 if not s
in subsystems
:
293 if not t
.sname
in subsystems
[s
]:
294 subsystems
[s
][t
.sname
] = []
295 subsystems
[s
][t
.sname
].append(t2
.sname
)
298 if len(subsystems
[s
]) > 1 and Options
.options
.SHOW_DUPLICATES
:
299 Logs
.warn("WARNING: source %s is in more than one target: %s" % (s
, subsystems
[s
].keys()))
300 for tname
in subsystems
[s
]:
301 if len(subsystems
[s
][tname
]) > 1:
302 raise Utils
.WafError("ERROR: source %s is in more than one subsystem of target '%s': %s" % (s
, tname
, subsystems
[s
][tname
]))
306 def check_group_ordering(bld
, tgt_list
):
307 '''see if we have any dependencies that violate the group ordering
309 It is an error for a target to depend on a target from a later
314 tm
= bld
.task_manager
315 return [x
for x
in tm
.groups_names
if id(tm
.groups_names
[x
]) == id(g
)][0]
317 for g
in bld
.task_manager
.groups
:
318 gname
= group_name(g
)
319 for t
in g
.tasks_gen
:
320 t
.samba_group
= gname
324 for g
in bld
.task_manager
.groups
:
329 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
333 tdeps
= getattr(t
, 'add_objects', []) + getattr(t
, 'uselib_local', [])
335 t2
= bld
.get_tgen_by_name(d
)
338 map1
= grp_map
[t
.samba_group
]
339 map2
= grp_map
[t2
.samba_group
]
342 Logs
.error("Target %r in build group %r depends on target %r from later build group %r" % (
343 t
.sname
, t
.samba_group
, t2
.sname
, t2
.samba_group
))
347 Build
.BuildContext
.check_group_ordering
= check_group_ordering
349 def show_final_deps(bld
, tgt_list
):
350 '''show the final dependencies for all targets'''
352 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
355 if not targets
[t
.sname
] in ['LIBRARY', 'BINARY', 'PYTHON', 'SUBSYSTEM']:
357 debug('deps: final dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
358 t
.sname
, t
.uselib
, getattr(t
, 'uselib_local', []), getattr(t
, 'add_objects', []))
361 def add_samba_attributes(bld
, tgt_list
):
362 '''ensure a target has a the required samba attributes'''
364 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
371 t
.samba_type
= targets
[t
.sname
]
372 t
.samba_abspath
= t
.path
.abspath(bld
.env
)
373 t
.samba_deps_extended
= t
.samba_deps
[:]
374 t
.samba_includes_extended
= TO_LIST(t
.samba_includes
)[:]
375 t
.ccflags
= getattr(t
, 'samba_cflags', '')
377 def replace_grouping_libraries(bld
, tgt_list
):
378 '''replace dependencies based on grouping libraries
380 If a library is marked as a grouping library, then any target that
381 depends on a subsystem that is part of that grouping library gets
382 that dependency replaced with a dependency on the grouping library
385 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
389 # find our list of grouping libraries, mapped from the subsystems they depend on
391 if not getattr(t
, 'grouping_library', False):
393 for dep
in t
.samba_deps_extended
:
394 bld
.ASSERT(dep
in targets
, "grouping library target %s not declared in %s" % (dep
, t
.sname
))
395 if targets
[dep
] == 'SUBSYSTEM':
396 grouping
[dep
] = t
.sname
398 # now replace any dependencies on elements of grouping libraries
400 for i
in range(len(t
.samba_deps_extended
)):
401 dep
= t
.samba_deps_extended
[i
]
403 if t
.sname
!= grouping
[dep
]:
404 debug("deps: target %s: replacing dependency %s with grouping library %s" % (t
.sname
, dep
, grouping
[dep
]))
405 t
.samba_deps_extended
[i
] = grouping
[dep
]
409 def build_direct_deps(bld
, tgt_list
):
410 '''build the direct_objects and direct_libs sets for each target'''
412 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
413 syslib_deps
= LOCAL_CACHE(bld
, 'SYSLIB_DEPS')
415 global_deps
= bld
.env
.GLOBAL_DEPENDENCIES
416 global_deps_exclude
= set()
417 for dep
in global_deps
:
418 t
= bld
.get_tgen_by_name(dep
)
419 for d
in t
.samba_deps
:
420 # prevent loops from the global dependencies list
421 global_deps_exclude
.add(d
)
422 global_deps_exclude
.add(d
+ '.objlist')
425 t
.direct_objects
= set()
426 t
.direct_libs
= set()
427 t
.direct_syslibs
= set()
428 deps
= t
.samba_deps_extended
[:]
429 if getattr(t
, 'samba_use_global_deps', False) and not t
.sname
in global_deps_exclude
:
430 deps
.extend(global_deps
)
432 if d
== t
.sname
: continue
434 Logs
.error("Unknown dependency '%s' in '%s'" % (d
, t
.sname
))
436 if targets
[d
] in [ 'EMPTY', 'DISABLED' ]:
438 if targets
[d
] == 'PYTHON' and targets
[t
.sname
] != 'PYTHON' and t
.sname
.find('.objlist') == -1:
439 # this check should be more restrictive, but for now we have pidl-generated python
440 # code that directly depends on other python modules
441 Logs
.error('ERROR: Target %s has dependency on python module %s' % (t
.sname
, d
))
443 if targets
[d
] == 'SYSLIB':
444 t
.direct_syslibs
.add(d
)
446 for implied
in TO_LIST(syslib_deps
[d
]):
447 if BUILTIN_LIBRARY(bld
, implied
):
448 t
.direct_objects
.add(implied
)
449 elif targets
[implied
] == 'SYSLIB':
450 t
.direct_syslibs
.add(implied
)
451 elif targets
[implied
] in ['LIBRARY', 'MODULE']:
452 t
.direct_libs
.add(implied
)
454 Logs
.error('Implied dependency %s in %s is of type %s' % (
455 implied
, t
.sname
, targets
[implied
]))
458 t2
= bld
.get_tgen_by_name(d
)
460 Logs
.error("no task %s of type %s in %s" % (d
, targets
[d
], t
.sname
))
462 if t2
.samba_type
in [ 'LIBRARY', 'MODULE' ]:
464 elif t2
.samba_type
in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]:
465 t
.direct_objects
.add(d
)
466 debug('deps: built direct dependencies')
469 def dependency_loop(loops
, t
, target
):
470 '''add a dependency loop to the loops dictionary'''
471 if t
.sname
== target
:
473 if not target
in loops
:
474 loops
[target
] = set()
475 if not t
.sname
in loops
[target
]:
476 loops
[target
].add(t
.sname
)
479 def indirect_libs(bld
, t
, chain
, loops
):
480 '''recursively calculate the indirect library dependencies for a target
482 An indirect library is a library that results from a dependency on
486 ret
= getattr(t
, 'indirect_libs', None)
491 for obj
in t
.direct_objects
:
493 dependency_loop(loops
, t
, obj
)
496 t2
= bld
.get_tgen_by_name(obj
)
497 r2
= indirect_libs(bld
, t2
, chain
, loops
)
499 ret
= ret
.union(t2
.direct_libs
)
502 for obj
in indirect_objects(bld
, t
, set(), loops
):
504 dependency_loop(loops
, t
, obj
)
507 t2
= bld
.get_tgen_by_name(obj
)
508 r2
= indirect_libs(bld
, t2
, chain
, loops
)
510 ret
= ret
.union(t2
.direct_libs
)
513 t
.indirect_libs
= ret
518 def indirect_objects(bld
, t
, chain
, loops
):
519 '''recursively calculate the indirect object dependencies for a target
521 indirect objects are the set of objects from expanding the
522 subsystem dependencies
525 ret
= getattr(t
, 'indirect_objects', None)
526 if ret
is not None: return ret
529 for lib
in t
.direct_objects
:
531 dependency_loop(loops
, t
, lib
)
534 t2
= bld
.get_tgen_by_name(lib
)
535 r2
= indirect_objects(bld
, t2
, chain
, loops
)
537 ret
= ret
.union(t2
.direct_objects
)
540 t
.indirect_objects
= ret
544 def extended_objects(bld
, t
, chain
):
545 '''recursively calculate the extended object dependencies for a target
547 extended objects are the union of:
550 - direct and indirect objects of all direct and indirect libraries
553 ret
= getattr(t
, 'extended_objects', None)
554 if ret
is not None: return ret
557 ret
= ret
.union(t
.final_objects
)
559 for lib
in t
.final_libs
:
562 t2
= bld
.get_tgen_by_name(lib
)
564 r2
= extended_objects(bld
, t2
, chain
)
566 ret
= ret
.union(t2
.final_objects
)
569 t
.extended_objects
= ret
573 def includes_objects(bld
, t
, chain
, inc_loops
):
574 '''recursively calculate the includes object dependencies for a target
576 includes dependencies come from either library or object dependencies
578 ret
= getattr(t
, 'includes_objects', None)
582 ret
= t
.direct_objects
.copy()
583 ret
= ret
.union(t
.direct_libs
)
585 for obj
in t
.direct_objects
:
587 dependency_loop(inc_loops
, t
, obj
)
590 t2
= bld
.get_tgen_by_name(obj
)
591 r2
= includes_objects(bld
, t2
, chain
, inc_loops
)
593 ret
= ret
.union(t2
.direct_objects
)
596 for lib
in t
.direct_libs
:
598 dependency_loop(inc_loops
, t
, lib
)
601 t2
= bld
.get_tgen_by_name(lib
)
603 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
604 Logs
.error('Target %s of type %s not found in direct_libs for %s' % (
605 lib
, targets
[lib
], t
.sname
))
607 r2
= includes_objects(bld
, t2
, chain
, inc_loops
)
609 ret
= ret
.union(t2
.direct_objects
)
612 t
.includes_objects
= ret
616 def break_dependency_loops(bld
, tgt_list
):
617 '''find and break dependency loops'''
621 # build up the list of loops
623 indirect_objects(bld
, t
, set(), loops
)
624 indirect_libs(bld
, t
, set(), loops
)
625 includes_objects(bld
, t
, set(), inc_loops
)
630 for attr
in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
631 objs
= getattr(t
, attr
, set())
632 setattr(t
, attr
, objs
.difference(loops
[t
.sname
]))
635 debug('deps: Found dependency loops for target %s : %s', loop
, loops
[loop
])
637 for loop
in inc_loops
:
638 debug('deps: Found include loops for target %s : %s', loop
, inc_loops
[loop
])
640 # expand the loops mapping by one level
641 for loop
in loops
.copy():
642 for tgt
in loops
[loop
]:
644 loops
[loop
] = loops
[loop
].union(loops
[tgt
])
646 for loop
in inc_loops
.copy():
647 for tgt
in inc_loops
[loop
]:
649 inc_loops
[loop
] = inc_loops
[loop
].union(inc_loops
[tgt
])
652 # expand indirect subsystem and library loops
653 for loop
in loops
.copy():
654 t
= bld
.get_tgen_by_name(loop
)
655 if t
.samba_type
in ['SUBSYSTEM']:
656 loops
[loop
] = loops
[loop
].union(t
.indirect_objects
)
657 loops
[loop
] = loops
[loop
].union(t
.direct_objects
)
658 if t
.samba_type
in ['LIBRARY','PYTHON']:
659 loops
[loop
] = loops
[loop
].union(t
.indirect_libs
)
660 loops
[loop
] = loops
[loop
].union(t
.direct_libs
)
661 if loop
in loops
[loop
]:
662 loops
[loop
].remove(loop
)
664 # expand indirect includes loops
665 for loop
in inc_loops
.copy():
666 t
= bld
.get_tgen_by_name(loop
)
667 inc_loops
[loop
] = inc_loops
[loop
].union(t
.includes_objects
)
668 if loop
in inc_loops
[loop
]:
669 inc_loops
[loop
].remove(loop
)
671 # add in the replacement dependencies
674 for attr
in ['indirect_objects', 'indirect_libs']:
675 objs
= getattr(t
, attr
, set())
677 diff
= loops
[loop
].difference(objs
)
681 debug('deps: Expanded target %s of type %s from loop %s by %s', t
.sname
, t
.samba_type
, loop
, diff
)
682 objs
= objs
.union(diff
)
683 setattr(t
, attr
, objs
)
685 for loop
in inc_loops
:
686 objs
= getattr(t
, 'includes_objects', set())
688 diff
= inc_loops
[loop
].difference(objs
)
692 debug('deps: Expanded target %s includes of type %s from loop %s by %s', t
.sname
, t
.samba_type
, loop
, diff
)
693 objs
= objs
.union(diff
)
694 setattr(t
, 'includes_objects', objs
)
697 def reduce_objects(bld
, tgt_list
):
698 '''reduce objects by looking for indirect object dependencies'''
702 t
.extended_objects
= None
706 for type in ['BINARY', 'PYTHON', 'LIBRARY']:
708 if t
.samba_type
!= type: continue
709 # if we will indirectly link to a target then we don't need it
710 new
= t
.final_objects
.copy()
711 for l
in t
.final_libs
:
712 t2
= bld
.get_tgen_by_name(l
)
713 t2_obj
= extended_objects(bld
, t2
, set())
714 dup
= new
.intersection(t2_obj
)
715 if t
.sname
in rely_on
:
716 dup
= dup
.difference(rely_on
[t
.sname
])
718 debug('deps: removing dups from %s of type %s: %s also in %s %s',
719 t
.sname
, t
.samba_type
, dup
, t2
.samba_type
, l
)
720 new
= new
.difference(dup
)
724 rely_on
[l
] = rely_on
[l
].union(dup
)
725 t
.final_objects
= new
730 # add back in any objects that were relied upon by the reduction rules
732 t
= bld
.get_tgen_by_name(r
)
733 t
.final_objects
= t
.final_objects
.union(rely_on
[r
])
738 def show_library_loop(bld
, lib1
, lib2
, path
, seen
):
739 '''show the detailed path of a library loop between lib1 and lib2'''
741 t
= bld
.get_tgen_by_name(lib1
)
742 if not lib2
in getattr(t
, 'final_libs', set()):
745 for d
in t
.samba_deps_extended
:
749 path2
= path
+ '=>' + d
751 Logs
.warn('library loop path: ' + path2
)
753 show_library_loop(bld
, d
, lib2
, path2
, seen
)
757 def calculate_final_deps(bld
, tgt_list
, loops
):
758 '''calculate the final library and object dependencies'''
760 # start with the maximum possible list
761 t
.final_libs
= t
.direct_libs
.union(indirect_libs(bld
, t
, set(), loops
))
762 t
.final_objects
= t
.direct_objects
.union(indirect_objects(bld
, t
, set(), loops
))
765 # don't depend on ourselves
766 if t
.sname
in t
.final_libs
:
767 t
.final_libs
.remove(t
.sname
)
768 if t
.sname
in t
.final_objects
:
769 t
.final_objects
.remove(t
.sname
)
771 # handle any non-shared binaries
773 if t
.samba_type
== 'BINARY' and bld
.NONSHARED_BINARY(t
.sname
):
774 subsystem_list
= LOCAL_CACHE(bld
, 'INIT_FUNCTIONS')
775 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
777 # replace lib deps with objlist deps
778 for l
in t
.final_libs
:
779 objname
= l
+ '.objlist'
780 t2
= bld
.get_tgen_by_name(objname
)
782 Logs
.error('ERROR: subsystem %s not found' % objname
)
784 t
.final_objects
.add(objname
)
785 t
.final_objects
= t
.final_objects
.union(extended_objects(bld
, t2
, set()))
786 if l
in subsystem_list
:
787 # its a subsystem - we also need the contents of any modules
788 for d
in subsystem_list
[l
]:
789 module_name
= d
['TARGET']
790 if targets
[module_name
] == 'LIBRARY':
791 objname
= module_name
+ '.objlist'
792 elif targets
[module_name
] == 'SUBSYSTEM':
793 objname
= module_name
796 t2
= bld
.get_tgen_by_name(objname
)
798 Logs
.error('ERROR: subsystem %s not found' % objname
)
800 t
.final_objects
.add(objname
)
801 t
.final_objects
= t
.final_objects
.union(extended_objects(bld
, t2
, set()))
804 # find any library loops
806 if t
.samba_type
in ['LIBRARY', 'PYTHON']:
807 for l
in t
.final_libs
.copy():
808 t2
= bld
.get_tgen_by_name(l
)
809 if t
.sname
in t2
.final_libs
:
810 if getattr(bld
.env
, "ALLOW_CIRCULAR_LIB_DEPENDENCIES", False):
811 # we could break this in either direction. If one of the libraries
812 # has a version number, and will this be distributed publicly, then
813 # we should make it the lower level library in the DAG
814 Logs
.warn('deps: removing library loop %s from %s' % (t
.sname
, t2
.sname
))
815 dependency_loop(loops
, t
, t2
.sname
)
816 t2
.final_libs
.remove(t
.sname
)
818 Logs
.error('ERROR: circular library dependency between %s and %s'
819 % (t
.sname
, t2
.sname
))
820 show_library_loop(bld
, t
.sname
, t2
.sname
, t
.sname
, set())
821 show_library_loop(bld
, t2
.sname
, t
.sname
, t2
.sname
, set())
825 debug('deps: Found dependency loops for target %s : %s', loop
, loops
[loop
])
827 # we now need to make corrections for any library loops we broke up
828 # any target that depended on the target of the loop and doesn't
829 # depend on the source of the loop needs to get the loop source added
830 for type in ['BINARY','PYTHON','LIBRARY','BINARY']:
832 if t
.samba_type
!= type: continue
834 if loop
in t
.final_libs
:
835 diff
= loops
[loop
].difference(t
.final_libs
)
840 # make sure we don't recreate the loop again!
841 for d
in diff
.copy():
842 t2
= bld
.get_tgen_by_name(d
)
843 if t2
.samba_type
== 'LIBRARY':
844 if t
.sname
in t2
.final_libs
:
845 debug('deps: removing expansion %s from %s', d
, t
.sname
)
848 debug('deps: Expanded target %s by loop %s libraries (loop %s) %s', t
.sname
, loop
,
850 t
.final_libs
= t
.final_libs
.union(diff
)
852 # remove objects that are also available in linked libs
854 while reduce_objects(bld
, tgt_list
):
857 Logs
.warn("WARNING: Unable to remove all inter-target object duplicates")
859 debug('deps: Object reduction took %u iterations', count
)
861 # add in any syslib dependencies
863 if not t
.samba_type
in ['BINARY','PYTHON','LIBRARY','SUBSYSTEM']:
866 for d
in t
.final_objects
:
867 t2
= bld
.get_tgen_by_name(d
)
868 syslibs
= syslibs
.union(t2
.direct_syslibs
)
869 # this adds the indirect syslibs as well, which may not be needed
870 # depending on the linker flags
871 for d
in t
.final_libs
:
872 t2
= bld
.get_tgen_by_name(d
)
873 syslibs
= syslibs
.union(t2
.direct_syslibs
)
874 t
.final_syslibs
= syslibs
877 # find any unresolved library loops
878 lib_loop_error
= False
880 if t
.samba_type
in ['LIBRARY', 'PYTHON']:
881 for l
in t
.final_libs
.copy():
882 t2
= bld
.get_tgen_by_name(l
)
883 if t
.sname
in t2
.final_libs
:
884 Logs
.error('ERROR: Unresolved library loop %s from %s' % (t
.sname
, t2
.sname
))
885 lib_loop_error
= True
889 debug('deps: removed duplicate dependencies')
892 def show_dependencies(bld
, target
, seen
):
893 '''recursively show the dependencies of target'''
898 t
= bld
.get_tgen_by_name(target
)
900 Logs
.error("ERROR: Unable to find target '%s'" % target
)
903 Logs
.info('%s(OBJECTS): %s' % (target
, t
.direct_objects
))
904 Logs
.info('%s(LIBS): %s' % (target
, t
.direct_libs
))
905 Logs
.info('%s(SYSLIBS): %s' % (target
, t
.direct_syslibs
))
909 for t2
in t
.direct_objects
:
910 show_dependencies(bld
, t2
, seen
)
913 def show_object_duplicates(bld
, tgt_list
):
914 '''show a list of object files that are included in more than
915 one library or binary'''
917 targets
= LOCAL_CACHE(bld
, 'TARGET_TYPE')
921 Logs
.info("showing duplicate objects")
924 if not targets
[t
.sname
] in [ 'LIBRARY', 'PYTHON' ]:
926 for n
in getattr(t
, 'final_objects', set()):
927 t2
= bld
.get_tgen_by_name(n
)
930 used_by
[n
].add(t
.sname
)
933 if len(used_by
[n
]) > 1:
934 Logs
.info("target '%s' is used by %s" % (n
, used_by
[n
]))
936 Logs
.info("showing indirect dependency counts (sorted by count)")
938 def indirect_count(t1
, t2
):
939 return len(t2
.indirect_objects
) - len(t1
.indirect_objects
)
941 sorted_list
= sorted(tgt_list
, cmp=indirect_count
)
942 for t
in sorted_list
:
943 if len(t
.indirect_objects
) > 1:
944 Logs
.info("%s depends on %u indirect objects" % (t
.sname
, len(t
.indirect_objects
)))
947 ######################################################################
948 # this provides a way to save our dependency calculations between runs
950 savedeps_inputs
= ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags',
951 'source', 'grouping_library', 'samba_ldflags', 'allow_undefined_symbols',
952 'use_global_deps', 'global_include' ]
953 savedeps_outputs
= ['uselib', 'uselib_local', 'add_objects', 'includes',
954 'ccflags', 'ldflags', 'samba_deps_extended', 'final_libs']
955 savedeps_outenv
= ['INC_PATHS']
956 savedeps_envvars
= ['NONSHARED_BINARIES', 'GLOBAL_DEPENDENCIES', 'EXTRA_CFLAGS', 'EXTRA_LDFLAGS', 'EXTRA_INCLUDES' ]
957 savedeps_caches
= ['GLOBAL_DEPENDENCIES', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
958 savedeps_files
= ['buildtools/wafsamba/samba_deps.py']
960 def save_samba_deps(bld
, tgt_list
):
961 '''save the dependency calculations between builds, to make
962 further builds faster'''
963 denv
= Environment
.Environment()
965 denv
.version
= savedeps_version
966 denv
.savedeps_inputs
= savedeps_inputs
967 denv
.savedeps_outputs
= savedeps_outputs
975 for f
in savedeps_files
:
976 denv
.files
[f
] = os
.stat(os
.path
.join(bld
.srcnode
.abspath(), f
)).st_mtime
978 for c
in savedeps_caches
:
979 denv
.caches
[c
] = LOCAL_CACHE(bld
, c
)
981 for e
in savedeps_envvars
:
982 denv
.envvar
[e
] = bld
.env
[e
]
985 # save all the input attributes for each target
987 for attr
in savedeps_inputs
:
988 v
= getattr(t
, attr
, None)
992 denv
.input[t
.sname
] = tdeps
994 # save all the output attributes for each target
996 for attr
in savedeps_outputs
:
997 v
= getattr(t
, attr
, None)
1001 denv
.output
[t
.sname
] = tdeps
1004 for attr
in savedeps_outenv
:
1006 tdeps
[attr
] = t
.env
[attr
]
1008 denv
.outenv
[t
.sname
] = tdeps
1010 depsfile
= os
.path
.join(bld
.bdir
, "sambadeps")
1011 denv
.store_fast(depsfile
)
1015 def load_samba_deps(bld
, tgt_list
):
1016 '''load a previous set of build dependencies if possible'''
1017 depsfile
= os
.path
.join(bld
.bdir
, "sambadeps")
1018 denv
= Environment
.Environment()
1020 debug('deps: checking saved dependencies')
1021 denv
.load_fast(depsfile
)
1022 if (denv
.version
!= savedeps_version
or
1023 denv
.savedeps_inputs
!= savedeps_inputs
or
1024 denv
.savedeps_outputs
!= savedeps_outputs
):
1029 # check if critical files have changed
1030 for f
in savedeps_files
:
1031 if f
not in denv
.files
:
1033 if denv
.files
[f
] != os
.stat(os
.path
.join(bld
.srcnode
.abspath(), f
)).st_mtime
:
1036 # check if caches are the same
1037 for c
in savedeps_caches
:
1038 if c
not in denv
.caches
or denv
.caches
[c
] != LOCAL_CACHE(bld
, c
):
1041 # check if caches are the same
1042 for e
in savedeps_envvars
:
1043 if e
not in denv
.envvar
or denv
.envvar
[e
] != bld
.env
[e
]:
1046 # check inputs are the same
1049 for attr
in savedeps_inputs
:
1050 v
= getattr(t
, attr
, None)
1053 if t
.sname
in denv
.input:
1054 olddeps
= denv
.input[t
.sname
]
1057 if tdeps
!= olddeps
:
1058 #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
1061 # put outputs in place
1063 if not t
.sname
in denv
.output
: continue
1064 tdeps
= denv
.output
[t
.sname
]
1066 setattr(t
, a
, tdeps
[a
])
1068 # put output env vars in place
1070 if not t
.sname
in denv
.outenv
: continue
1071 tdeps
= denv
.outenv
[t
.sname
]
1075 debug('deps: loaded saved dependencies')
1080 def check_project_rules(bld
):
1081 '''check the project rules - ensuring the targets are sane'''
1086 tgt_list
= get_tgt_list(bld
)
1088 add_samba_attributes(bld
, tgt_list
)
1090 force_project_rules
= (Options
.options
.SHOWDEPS
or
1091 Options
.options
.SHOW_DUPLICATES
)
1093 if not force_project_rules
and load_samba_deps(bld
, tgt_list
):
1097 tstart
= time
.clock()
1099 bld
.new_rules
= True
1100 Logs
.info("Checking project rules ...")
1102 debug('deps: project rules checking started')
1104 expand_subsystem_deps(bld
)
1106 debug("deps: expand_subsystem_deps: %f" % (time
.clock() - tstart
))
1108 replace_grouping_libraries(bld
, tgt_list
)
1110 debug("deps: replace_grouping_libraries: %f" % (time
.clock() - tstart
))
1112 build_direct_deps(bld
, tgt_list
)
1114 debug("deps: build_direct_deps: %f" % (time
.clock() - tstart
))
1116 break_dependency_loops(bld
, tgt_list
)
1118 debug("deps: break_dependency_loops: %f" % (time
.clock() - tstart
))
1120 if Options
.options
.SHOWDEPS
:
1121 show_dependencies(bld
, Options
.options
.SHOWDEPS
, set())
1123 calculate_final_deps(bld
, tgt_list
, loops
)
1125 debug("deps: calculate_final_deps: %f" % (time
.clock() - tstart
))
1127 if Options
.options
.SHOW_DUPLICATES
:
1128 show_object_duplicates(bld
, tgt_list
)
1130 # run the various attribute generators
1131 for f
in [ build_dependencies
, build_includes
, add_init_functions
]:
1132 debug('deps: project rules checking %s', f
)
1133 for t
in tgt_list
: f(t
)
1134 debug("deps: %s: %f" % (f
, time
.clock() - tstart
))
1136 debug('deps: project rules stage1 completed')
1138 if not check_duplicate_sources(bld
, tgt_list
):
1139 Logs
.error("Duplicate sources present - aborting")
1142 debug("deps: check_duplicate_sources: %f" % (time
.clock() - tstart
))
1144 if not bld
.check_group_ordering(tgt_list
):
1145 Logs
.error("Bad group ordering - aborting")
1148 debug("deps: check_group_ordering: %f" % (time
.clock() - tstart
))
1150 show_final_deps(bld
, tgt_list
)
1152 debug("deps: show_final_deps: %f" % (time
.clock() - tstart
))
1154 debug('deps: project rules checking completed - %u targets checked',
1157 if not bld
.is_install
:
1158 save_samba_deps(bld
, tgt_list
)
1160 debug("deps: save_samba_deps: %f" % (time
.clock() - tstart
))
1162 Logs
.info("Project rules pass")
1165 def CHECK_PROJECT_RULES(bld
):
1166 '''enable checking of project targets for sanity'''
1167 if bld
.env
.added_project_rules
:
1169 bld
.env
.added_project_rules
= True
1170 bld
.add_pre_fun(check_project_rules
)
1171 Build
.BuildContext
.CHECK_PROJECT_RULES
= CHECK_PROJECT_RULES