1
# Samba automatic dependency handling and project rules
3
import Build, os, sys, re, Environment, Logs, time
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
23
def SET_SYSLIB_DEPS(conf, target, deps):
24
'''setup some implied dependencies for a SYSLIB'''
25
cache = LOCAL_CACHE(conf, 'SYSLIB_DEPS')
29
def expand_subsystem_deps(bld):
30
'''expand the reverse dependencies resulting from subsystem
31
attributes of modules. This is walking over the complete list
32
of declared subsystems, and expands the samba_deps_extended list for any
33
module<->subsystem dependencies'''
35
subsystem_list = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
36
targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
38
for subsystem_name in subsystem_list:
39
bld.ASSERT(subsystem_name in targets, "Subsystem target %s not declared" % subsystem_name)
40
type = targets[subsystem_name]
41
if type == 'DISABLED' or type == 'EMPTY':
45
# subsystem_name = dcerpc_server (a subsystem)
46
# subsystem = dcerpc_server (a subsystem object)
47
# module_name = rpc_epmapper (a module within the dcerpc_server subsystem)
48
# module = rpc_epmapper (a module object within the dcerpc_server subsystem)
50
subsystem = bld.name_to_obj(subsystem_name, bld.env)
51
bld.ASSERT(subsystem is not None, "Unable to find subsystem %s" % subsystem_name)
52
for d in subsystem_list[subsystem_name]:
53
module_name = d['TARGET']
54
module_type = targets[module_name]
55
if module_type in ['DISABLED', 'EMPTY']:
57
bld.ASSERT(subsystem is not None,
58
"Subsystem target %s for %s (%s) not found" % (subsystem_name, module_name, module_type))
59
if module_type in ['SUBSYSTEM']:
60
# if a module is a plain object type (not a library) then the
61
# subsystem it is part of needs to have it as a dependency, so targets
62
# that depend on this subsystem get the modules of that subsystem
63
subsystem.samba_deps_extended.append(module_name)
64
subsystem.samba_deps_extended = unique_list(subsystem.samba_deps_extended)
68
def build_dependencies(self):
69
'''This builds the dependency list for a target. It runs after all the targets are declared
71
The reason this is not just done in the SAMBA_*() rules is that we have no way of knowing
72
the full dependency list for a target until we have all of the targets declared.
75
if self.samba_type in ['LIBRARY', 'BINARY', 'PYTHON']:
76
self.uselib = list(self.final_syslibs)
77
self.uselib_local = list(self.final_libs)
78
self.add_objects = list(self.final_objects)
80
# extra link flags from pkg_config
81
libs = self.final_syslibs.copy()
83
(ccflags, ldflags) = library_flags(self, list(libs))
84
new_ldflags = getattr(self, 'samba_ldflags', [])[:]
85
new_ldflags.extend(ldflags)
86
self.ldflags = new_ldflags
88
if getattr(self, 'allow_undefined_symbols', False) and self.env.undefined_ldflags:
89
for f in self.env.undefined_ldflags:
90
self.ldflags.remove(f)
92
debug('deps: computed dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
93
self.sname, self.uselib, self.uselib_local, self.add_objects)
95
if self.samba_type in ['SUBSYSTEM']:
96
# this is needed for the ccflags of libs that come from pkg_config
97
self.uselib = list(self.final_syslibs)
98
self.uselib.extend(list(self.direct_syslibs))
99
for lib in self.final_libs:
100
t = self.bld.name_to_obj(lib, self.bld.env)
101
self.uselib.extend(list(t.final_syslibs))
102
self.uselib = unique_list(self.uselib)
104
if getattr(self, 'uselib', None):
106
for l in self.uselib:
107
up_list.append(l.upper())
108
self.uselib = up_list
111
def build_includes(self):
112
'''This builds the right set of includes for a target.
114
One tricky part of this is that the includes= attribute for a
115
target needs to use paths which are relative to that targets
116
declaration directory (which we can get at via t.path).
118
The way this works is the includes list gets added as
119
samba_includes in the main build task declaration. Then this
120
function runs after all of the tasks are declared, and it
121
processes the samba_includes attribute to produce a includes=
125
if getattr(self, 'samba_includes', None) is None:
130
inc_deps = includes_objects(bld, self, set(), {})
134
# maybe add local includes
135
if getattr(self, 'local_include', True) == True and getattr(self, 'local_include_first', True):
138
includes.extend(self.samba_includes_extended)
140
if 'EXTRA_INCLUDES' in bld.env and getattr(self, 'global_include', True):
141
includes.extend(bld.env['EXTRA_INCLUDES'])
149
t = bld.name_to_obj(d, bld.env)
150
bld.ASSERT(t is not None, "Unable to find dependency %s for %s" % (d, self.sname))
151
inclist = getattr(t, 'samba_includes_extended', [])[:]
152
if getattr(t, 'local_include', True) == True:
156
tpath = t.samba_abspath
158
npath = tpath + '/' + inc
159
if not npath in inc_set:
160
inc_abs.append(npath)
163
mypath = self.path.abspath(bld.env)
165
relpath = os_path_relpath(inc, mypath)
166
includes.append(relpath)
168
if getattr(self, 'local_include', True) == True and not getattr(self, 'local_include_first', True):
171
# now transform the includes list to be relative to the top directory
172
# which is represented by '#' in waf. This allows waf to cache the
173
# includes lists more efficiently
177
# some are already top based
178
includes_top.append(i)
180
absinc = os.path.join(self.path.abspath(), i)
181
relinc = os_path_relpath(absinc, self.bld.srcnode.abspath())
182
includes_top.append('#' + relinc)
184
self.includes = unique_list(includes_top)
185
debug('deps: includes for target %s: includes=%s',
186
self.sname, self.includes)
191
def add_init_functions(self):
192
'''This builds the right set of init functions'''
196
subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
198
# cope with the separated object lists from BINARY and LIBRARY targets
200
if sname.endswith('.objlist'):
204
if sname in subsystems:
205
modules.append(sname)
207
m = getattr(self, 'samba_modules', None)
209
modules.extend(TO_LIST(m))
211
m = getattr(self, 'samba_subsystem', None)
215
sentinal = getattr(self, 'init_function_sentinal', 'NULL')
217
targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
218
cflags = getattr(self, 'samba_cflags', [])[:]
221
sname = sname.replace('-','_')
222
sname = sname.replace('/','_')
223
cflags.append('-DSTATIC_%s_MODULES=%s' % (sname, sentinal))
224
if sentinal == 'NULL':
225
cflags.append('-DSTATIC_%s_MODULES_PROTO' % sname)
226
self.ccflags = cflags
230
bld.ASSERT(m in subsystems,
231
"No init_function defined for module '%s' in target '%s'" % (m, self.sname))
233
for d in subsystems[m]:
234
if targets[d['TARGET']] != 'DISABLED':
235
init_fn_list.append(d['INIT_FUNCTION'])
236
if init_fn_list == []:
237
cflags.append('-DSTATIC_%s_MODULES=%s' % (m, sentinal))
238
if sentinal == 'NULL':
239
cflags.append('-DSTATIC_%s_MODULES_PROTO' % m)
241
cflags.append('-DSTATIC_%s_MODULES=%s' % (m, ','.join(init_fn_list) + ',' + sentinal))
243
for f in init_fn_list:
244
proto = proto + '_MODULE_PROTO(%s)' % f
245
cflags.append('-DSTATIC_%s_MODULES_PROTO=%s' % (m, proto))
246
self.ccflags = cflags
250
def check_duplicate_sources(bld, tgt_list):
251
'''see if we are compiling the same source file more than once
252
without an allow_duplicates attribute'''
254
debug('deps: checking for duplicate sources')
256
targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
262
source_list = TO_LIST(getattr(t, 'source', ''))
263
tpath = os.path.normpath(os_path_relpath(t.path.abspath(bld.env), t.env.BUILD_DIRECTORY + '/default'))
265
for s in source_list:
266
p = os.path.normpath(os.path.join(tpath, s))
268
Logs.error("ERROR: source %s appears twice in target '%s'" % (p, t.sname))
271
t.samba_source_set = obj_sources
275
# build a list of targets that each source file is part of
278
if not targets[t.sname] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
280
for obj in t.add_objects:
281
t2 = t.bld.name_to_obj(obj, bld.env)
282
source_set = getattr(t2, 'samba_source_set', set())
284
if not s in subsystems:
286
if not t.sname in subsystems[s]:
287
subsystems[s][t.sname] = []
288
subsystems[s][t.sname].append(t2.sname)
291
if len(subsystems[s]) > 1 and Options.options.SHOW_DUPLICATES:
292
Logs.warn("WARNING: source %s is in more than one target: %s" % (s, subsystems[s].keys()))
293
for tname in subsystems[s]:
294
if len(subsystems[s][tname]) > 1:
295
raise Utils.WafError("ERROR: source %s is in more than one subsystem of target '%s': %s" % (s, tname, subsystems[s][tname]))
300
def check_orpaned_targets(bld, tgt_list):
301
'''check if any build targets are orphaned'''
303
target_dict = LOCAL_CACHE(bld, 'TARGET_TYPE')
305
debug('deps: checking for orphaned targets')
308
if getattr(t, 'samba_used', False) == True:
310
type = target_dict[t.sname]
311
if not type in ['BINARY', 'LIBRARY', 'MODULE', 'ET', 'PYTHON']:
312
if re.search('^PIDL_', t.sname) is None:
313
Logs.warn("Target %s of type %s is unused by any other target" % (t.sname, type))
316
def check_group_ordering(bld, tgt_list):
317
'''see if we have any dependencies that violate the group ordering
319
It is an error for a target to depend on a target from a later
324
tm = bld.task_manager
325
return [x for x in tm.groups_names if id(tm.groups_names[x]) == id(g)][0]
327
for g in bld.task_manager.groups:
328
gname = group_name(g)
329
for t in g.tasks_gen:
330
t.samba_group = gname
334
for g in bld.task_manager.groups:
339
targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
343
tdeps = getattr(t, 'add_objects', []) + getattr(t, 'uselib_local', [])
345
t2 = bld.name_to_obj(d, bld.env)
348
map1 = grp_map[t.samba_group]
349
map2 = grp_map[t2.samba_group]
352
Logs.error("Target %r in build group %r depends on target %r from later build group %r" % (
353
t.sname, t.samba_group, t2.sname, t2.samba_group))
359
def show_final_deps(bld, tgt_list):
360
'''show the final dependencies for all targets'''
362
targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
365
if not targets[t.sname] in ['LIBRARY', 'BINARY', 'PYTHON', 'SUBSYSTEM']:
367
debug('deps: final dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
368
t.sname, t.uselib, getattr(t, 'uselib_local', []), getattr(t, 'add_objects', []))
371
def add_samba_attributes(bld, tgt_list):
372
'''ensure a target has a the required samba attributes'''
374
targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
381
t.samba_type = targets[t.sname]
382
t.samba_abspath = t.path.abspath(bld.env)
383
t.samba_deps_extended = t.samba_deps[:]
384
t.samba_includes_extended = TO_LIST(t.samba_includes)[:]
385
t.ccflags = getattr(t, 'samba_cflags', '')
387
def replace_grouping_libraries(bld, tgt_list):
388
'''replace dependencies based on grouping libraries
390
If a library is marked as a grouping library, then any target that
391
depends on a subsystem that is part of that grouping library gets
392
that dependency replaced with a dependency on the grouping library
395
targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
399
# find our list of grouping libraries, mapped from the subsystems they depend on
401
if not getattr(t, 'grouping_library', False):
403
for dep in t.samba_deps_extended:
404
bld.ASSERT(dep in targets, "grouping library target %s not declared in %s" % (dep, t.sname))
405
if targets[dep] == 'SUBSYSTEM':
406
grouping[dep] = t.sname
408
# now replace any dependencies on elements of grouping libraries
410
for i in range(len(t.samba_deps_extended)):
411
dep = t.samba_deps_extended[i]
413
if t.sname != grouping[dep]:
414
debug("deps: target %s: replacing dependency %s with grouping library %s" % (t.sname, dep, grouping[dep]))
415
t.samba_deps_extended[i] = grouping[dep]
419
def build_direct_deps(bld, tgt_list):
420
'''build the direct_objects and direct_libs sets for each target'''
422
targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
423
syslib_deps = LOCAL_CACHE(bld, 'SYSLIB_DEPS')
425
global_deps = bld.env.GLOBAL_DEPENDENCIES
426
global_deps_exclude = set()
427
for dep in global_deps:
428
t = bld.name_to_obj(dep, bld.env)
429
for d in t.samba_deps:
430
# prevent loops from the global dependencies list
431
global_deps_exclude.add(d)
432
global_deps_exclude.add(d + '.objlist')
435
t.direct_objects = set()
436
t.direct_libs = set()
437
t.direct_syslibs = set()
438
deps = t.samba_deps_extended[:]
439
if getattr(t, 'samba_use_global_deps', False) and not t.sname in global_deps_exclude:
440
deps.extend(global_deps)
442
if d == t.sname: continue
444
Logs.error("Unknown dependency '%s' in '%s'" % (d, t.sname))
446
if targets[d] in [ 'EMPTY', 'DISABLED' ]:
448
if targets[d] == 'PYTHON' and targets[t.sname] != 'PYTHON' and t.sname.find('.objlist') == -1:
449
# this check should be more restrictive, but for now we have pidl-generated python
450
# code that directly depends on other python modules
451
Logs.error('ERROR: Target %s has dependency on python module %s' % (t.sname, d))
453
if targets[d] == 'SYSLIB':
454
t.direct_syslibs.add(d)
456
for implied in TO_LIST(syslib_deps[d]):
457
if BUILTIN_LIBRARY(bld, implied):
458
t.direct_objects.add(implied)
459
elif targets[implied] == 'SYSLIB':
460
t.direct_syslibs.add(implied)
461
elif targets[implied] in ['LIBRARY', 'MODULE']:
462
t.direct_libs.add(implied)
464
Logs.error('Implied dependency %s in %s is of type %s' % (
465
implied, t.sname, targets[implied]))
468
t2 = bld.name_to_obj(d, bld.env)
470
Logs.error("no task %s of type %s in %s" % (d, targets[d], t.sname))
472
if t2.samba_type in [ 'LIBRARY', 'MODULE' ]:
474
elif t2.samba_type in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]:
475
t.direct_objects.add(d)
476
debug('deps: built direct dependencies')
479
def dependency_loop(loops, t, target):
480
'''add a dependency loop to the loops dictionary'''
481
if t.sname == target:
483
if not target in loops:
484
loops[target] = set()
485
if not t.sname in loops[target]:
486
loops[target].add(t.sname)
489
def indirect_libs(bld, t, chain, loops):
490
'''recursively calculate the indirect library dependencies for a target
492
An indirect library is a library that results from a dependency on
496
ret = getattr(t, 'indirect_libs', None)
501
for obj in t.direct_objects:
503
dependency_loop(loops, t, obj)
506
t2 = bld.name_to_obj(obj, bld.env)
507
r2 = indirect_libs(bld, t2, chain, loops)
509
ret = ret.union(t2.direct_libs)
512
for obj in indirect_objects(bld, t, set(), loops):
514
dependency_loop(loops, t, obj)
517
t2 = bld.name_to_obj(obj, bld.env)
518
r2 = indirect_libs(bld, t2, chain, loops)
520
ret = ret.union(t2.direct_libs)
523
t.indirect_libs = ret
528
def indirect_objects(bld, t, chain, loops):
529
'''recursively calculate the indirect object dependencies for a target
531
indirect objects are the set of objects from expanding the
532
subsystem dependencies
535
ret = getattr(t, 'indirect_objects', None)
536
if ret is not None: return ret
539
for lib in t.direct_objects:
541
dependency_loop(loops, t, lib)
544
t2 = bld.name_to_obj(lib, bld.env)
545
r2 = indirect_objects(bld, t2, chain, loops)
547
ret = ret.union(t2.direct_objects)
550
t.indirect_objects = ret
554
def extended_objects(bld, t, chain):
555
'''recursively calculate the extended object dependencies for a target
557
extended objects are the union of:
560
- direct and indirect objects of all direct and indirect libraries
563
ret = getattr(t, 'extended_objects', None)
564
if ret is not None: return ret
567
ret = ret.union(t.final_objects)
569
for lib in t.final_libs:
572
t2 = bld.name_to_obj(lib, bld.env)
574
r2 = extended_objects(bld, t2, chain)
576
ret = ret.union(t2.final_objects)
579
t.extended_objects = ret
583
def includes_objects(bld, t, chain, inc_loops):
584
'''recursively calculate the includes object dependencies for a target
586
includes dependencies come from either library or object dependencies
588
ret = getattr(t, 'includes_objects', None)
592
ret = t.direct_objects.copy()
593
ret = ret.union(t.direct_libs)
595
for obj in t.direct_objects:
597
dependency_loop(inc_loops, t, obj)
600
t2 = bld.name_to_obj(obj, bld.env)
601
r2 = includes_objects(bld, t2, chain, inc_loops)
603
ret = ret.union(t2.direct_objects)
606
for lib in t.direct_libs:
608
dependency_loop(inc_loops, t, lib)
611
t2 = bld.name_to_obj(lib, bld.env)
613
targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
614
Logs.error('Target %s of type %s not found in direct_libs for %s' % (
615
lib, targets[lib], t.sname))
617
r2 = includes_objects(bld, t2, chain, inc_loops)
619
ret = ret.union(t2.direct_objects)
622
t.includes_objects = ret
626
def break_dependency_loops(bld, tgt_list):
627
'''find and break dependency loops'''
631
# build up the list of loops
633
indirect_objects(bld, t, set(), loops)
634
indirect_libs(bld, t, set(), loops)
635
includes_objects(bld, t, set(), inc_loops)
640
for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
641
objs = getattr(t, attr, set())
642
setattr(t, attr, objs.difference(loops[t.sname]))
645
debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
647
for loop in inc_loops:
648
debug('deps: Found include loops for target %s : %s', loop, inc_loops[loop])
650
# expand the loops mapping by one level
651
for loop in loops.copy():
652
for tgt in loops[loop]:
654
loops[loop] = loops[loop].union(loops[tgt])
656
for loop in inc_loops.copy():
657
for tgt in inc_loops[loop]:
659
inc_loops[loop] = inc_loops[loop].union(inc_loops[tgt])
662
# expand indirect subsystem and library loops
663
for loop in loops.copy():
664
t = bld.name_to_obj(loop, bld.env)
665
if t.samba_type in ['SUBSYSTEM']:
666
loops[loop] = loops[loop].union(t.indirect_objects)
667
loops[loop] = loops[loop].union(t.direct_objects)
668
if t.samba_type in ['LIBRARY','PYTHON']:
669
loops[loop] = loops[loop].union(t.indirect_libs)
670
loops[loop] = loops[loop].union(t.direct_libs)
671
if loop in loops[loop]:
672
loops[loop].remove(loop)
674
# expand indirect includes loops
675
for loop in inc_loops.copy():
676
t = bld.name_to_obj(loop, bld.env)
677
inc_loops[loop] = inc_loops[loop].union(t.includes_objects)
678
if loop in inc_loops[loop]:
679
inc_loops[loop].remove(loop)
681
# add in the replacement dependencies
684
for attr in ['indirect_objects', 'indirect_libs']:
685
objs = getattr(t, attr, set())
687
diff = loops[loop].difference(objs)
691
debug('deps: Expanded target %s of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
692
objs = objs.union(diff)
693
setattr(t, attr, objs)
695
for loop in inc_loops:
696
objs = getattr(t, 'includes_objects', set())
698
diff = inc_loops[loop].difference(objs)
702
debug('deps: Expanded target %s includes of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
703
objs = objs.union(diff)
704
setattr(t, 'includes_objects', objs)
707
def reduce_objects(bld, tgt_list):
708
'''reduce objects by looking for indirect object dependencies'''
712
t.extended_objects = None
716
for type in ['BINARY', 'PYTHON', 'LIBRARY']:
718
if t.samba_type != type: continue
719
# if we will indirectly link to a target then we don't need it
720
new = t.final_objects.copy()
721
for l in t.final_libs:
722
t2 = bld.name_to_obj(l, bld.env)
723
t2_obj = extended_objects(bld, t2, set())
724
dup = new.intersection(t2_obj)
725
if t.sname in rely_on:
726
dup = dup.difference(rely_on[t.sname])
728
debug('deps: removing dups from %s of type %s: %s also in %s %s',
729
t.sname, t.samba_type, dup, t2.samba_type, l)
730
new = new.difference(dup)
734
rely_on[l] = rely_on[l].union(dup)
735
t.final_objects = new
740
# add back in any objects that were relied upon by the reduction rules
742
t = bld.name_to_obj(r, bld.env)
743
t.final_objects = t.final_objects.union(rely_on[r])
748
def show_library_loop(bld, lib1, lib2, path, seen):
749
'''show the detailed path of a library loop between lib1 and lib2'''
751
t = bld.name_to_obj(lib1, bld.env)
752
if not lib2 in getattr(t, 'final_libs', set()):
755
for d in t.samba_deps_extended:
759
path2 = path + '=>' + d
761
Logs.warn('library loop path: ' + path2)
763
show_library_loop(bld, d, lib2, path2, seen)
767
def calculate_final_deps(bld, tgt_list, loops):
768
'''calculate the final library and object dependencies'''
770
# start with the maximum possible list
771
t.final_libs = t.direct_libs.union(indirect_libs(bld, t, set(), loops))
772
t.final_objects = t.direct_objects.union(indirect_objects(bld, t, set(), loops))
775
# don't depend on ourselves
776
if t.sname in t.final_libs:
777
t.final_libs.remove(t.sname)
778
if t.sname in t.final_objects:
779
t.final_objects.remove(t.sname)
781
# handle any non-shared binaries
783
if t.samba_type == 'BINARY' and bld.NONSHARED_BINARY(t.sname):
784
subsystem_list = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
785
targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
787
# replace lib deps with objlist deps
788
for l in t.final_libs:
789
objname = l + '.objlist'
790
t2 = bld.name_to_obj(objname, bld.env)
792
Logs.error('ERROR: subsystem %s not found' % objname)
794
t.final_objects.add(objname)
795
t.final_objects = t.final_objects.union(extended_objects(bld, t2, set()))
796
if l in subsystem_list:
797
# its a subsystem - we also need the contents of any modules
798
for d in subsystem_list[l]:
799
module_name = d['TARGET']
800
if targets[module_name] == 'LIBRARY':
801
objname = module_name + '.objlist'
802
elif targets[module_name] == 'SUBSYSTEM':
803
objname = module_name
806
t2 = bld.name_to_obj(objname, bld.env)
808
Logs.error('ERROR: subsystem %s not found' % objname)
810
t.final_objects.add(objname)
811
t.final_objects = t.final_objects.union(extended_objects(bld, t2, set()))
814
# find any library loops
816
if t.samba_type in ['LIBRARY', 'PYTHON']:
817
for l in t.final_libs.copy():
818
t2 = bld.name_to_obj(l, bld.env)
819
if t.sname in t2.final_libs:
820
if getattr(bld.env, "ALLOW_CIRCULAR_LIB_DEPENDENCIES", False):
821
# we could break this in either direction. If one of the libraries
822
# has a version number, and will this be distributed publicly, then
823
# we should make it the lower level library in the DAG
824
Logs.warn('deps: removing library loop %s from %s' % (t.sname, t2.sname))
825
dependency_loop(loops, t, t2.sname)
826
t2.final_libs.remove(t.sname)
828
Logs.error('ERROR: circular library dependency between %s and %s'
829
% (t.sname, t2.sname))
830
show_library_loop(bld, t.sname, t2.sname, t.sname, set())
831
show_library_loop(bld, t2.sname, t.sname, t2.sname, set())
835
debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
837
# we now need to make corrections for any library loops we broke up
838
# any target that depended on the target of the loop and doesn't
839
# depend on the source of the loop needs to get the loop source added
840
for type in ['BINARY','PYTHON','LIBRARY','BINARY']:
842
if t.samba_type != type: continue
844
if loop in t.final_libs:
845
diff = loops[loop].difference(t.final_libs)
850
# make sure we don't recreate the loop again!
851
for d in diff.copy():
852
t2 = bld.name_to_obj(d, bld.env)
853
if t2.samba_type == 'LIBRARY':
854
if t.sname in t2.final_libs:
855
debug('deps: removing expansion %s from %s', d, t.sname)
858
debug('deps: Expanded target %s by loop %s libraries (loop %s) %s', t.sname, loop,
860
t.final_libs = t.final_libs.union(diff)
862
# remove objects that are also available in linked libs
864
while reduce_objects(bld, tgt_list):
867
Logs.warn("WARNING: Unable to remove all inter-target object duplicates")
869
debug('deps: Object reduction took %u iterations', count)
871
# add in any syslib dependencies
873
if not t.samba_type in ['BINARY','PYTHON','LIBRARY','SUBSYSTEM']:
876
for d in t.final_objects:
877
t2 = bld.name_to_obj(d, bld.env)
878
syslibs = syslibs.union(t2.direct_syslibs)
879
# this adds the indirect syslibs as well, which may not be needed
880
# depending on the linker flags
881
for d in t.final_libs:
882
t2 = bld.name_to_obj(d, bld.env)
883
syslibs = syslibs.union(t2.direct_syslibs)
884
t.final_syslibs = syslibs
887
# find any unresolved library loops
888
lib_loop_error = False
890
if t.samba_type in ['LIBRARY', 'PYTHON']:
891
for l in t.final_libs.copy():
892
t2 = bld.name_to_obj(l, bld.env)
893
if t.sname in t2.final_libs:
894
Logs.error('ERROR: Unresolved library loop %s from %s' % (t.sname, t2.sname))
895
lib_loop_error = True
899
debug('deps: removed duplicate dependencies')
902
def show_dependencies(bld, target, seen):
903
'''recursively show the dependencies of target'''
908
t = bld.name_to_obj(target, bld.env)
910
Logs.error("ERROR: Unable to find target '%s'" % target)
913
Logs.info('%s(OBJECTS): %s' % (target, t.direct_objects))
914
Logs.info('%s(LIBS): %s' % (target, t.direct_libs))
915
Logs.info('%s(SYSLIBS): %s' % (target, t.direct_syslibs))
919
for t2 in t.direct_objects:
920
show_dependencies(bld, t2, seen)
923
def show_object_duplicates(bld, tgt_list):
924
'''show a list of object files that are included in more than
925
one library or binary'''
927
targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
931
Logs.info("showing duplicate objects")
934
if not targets[t.sname] in [ 'LIBRARY', 'PYTHON' ]:
936
for n in getattr(t, 'final_objects', set()):
937
t2 = bld.name_to_obj(n, bld.env)
940
used_by[n].add(t.sname)
943
if len(used_by[n]) > 1:
944
Logs.info("target '%s' is used by %s" % (n, used_by[n]))
946
Logs.info("showing indirect dependency counts (sorted by count)")
948
def indirect_count(t1, t2):
949
return len(t2.indirect_objects) - len(t1.indirect_objects)
951
sorted_list = sorted(tgt_list, cmp=indirect_count)
952
for t in sorted_list:
953
if len(t.indirect_objects) > 1:
954
Logs.info("%s depends on %u indirect objects" % (t.sname, len(t.indirect_objects)))
957
######################################################################
958
# this provides a way to save our dependency calculations between runs
960
savedeps_inputs = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags',
961
'source', 'grouping_library', 'samba_ldflags', 'allow_undefined_symbols',
962
'use_global_deps', 'global_include' ]
963
savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags', 'ldflags', 'samba_deps_extended']
964
savedeps_outenv = ['INC_PATHS']
965
savedeps_envvars = ['NONSHARED_BINARIES', 'GLOBAL_DEPENDENCIES', 'EXTRA_CFLAGS', 'EXTRA_LDFLAGS', 'EXTRA_INCLUDES' ]
966
savedeps_caches = ['GLOBAL_DEPENDENCIES', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
967
savedeps_files = ['buildtools/wafsamba/samba_deps.py']
969
def save_samba_deps(bld, tgt_list):
970
'''save the dependency calculations between builds, to make
971
further builds faster'''
972
denv = Environment.Environment()
974
denv.version = savedeps_version
975
denv.savedeps_inputs = savedeps_inputs
976
denv.savedeps_outputs = savedeps_outputs
984
for f in savedeps_files:
985
denv.files[f] = os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime
987
for c in savedeps_caches:
988
denv.caches[c] = LOCAL_CACHE(bld, c)
990
for e in savedeps_envvars:
991
denv.envvar[e] = bld.env[e]
994
# save all the input attributes for each target
996
for attr in savedeps_inputs:
997
v = getattr(t, attr, None)
1001
denv.input[t.sname] = tdeps
1003
# save all the output attributes for each target
1005
for attr in savedeps_outputs:
1006
v = getattr(t, attr, None)
1010
denv.output[t.sname] = tdeps
1013
for attr in savedeps_outenv:
1015
tdeps[attr] = t.env[attr]
1017
denv.outenv[t.sname] = tdeps
1019
depsfile = os.path.join(bld.bdir, "sambadeps")
1020
denv.store(depsfile)
1024
def load_samba_deps(bld, tgt_list):
1025
'''load a previous set of build dependencies if possible'''
1026
depsfile = os.path.join(bld.bdir, "sambadeps")
1027
denv = Environment.Environment()
1029
debug('deps: checking saved dependencies')
1031
if (denv.version != savedeps_version or
1032
denv.savedeps_inputs != savedeps_inputs or
1033
denv.savedeps_outputs != savedeps_outputs):
1038
# check if critical files have changed
1039
for f in savedeps_files:
1040
if f not in denv.files:
1042
if denv.files[f] != os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime:
1045
# check if caches are the same
1046
for c in savedeps_caches:
1047
if c not in denv.caches or denv.caches[c] != LOCAL_CACHE(bld, c):
1050
# check if caches are the same
1051
for e in savedeps_envvars:
1052
if e not in denv.envvar or denv.envvar[e] != bld.env[e]:
1055
# check inputs are the same
1058
for attr in savedeps_inputs:
1059
v = getattr(t, attr, None)
1062
if t.sname in denv.input:
1063
olddeps = denv.input[t.sname]
1066
if tdeps != olddeps:
1067
#print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
1070
# put outputs in place
1072
if not t.sname in denv.output: continue
1073
tdeps = denv.output[t.sname]
1075
setattr(t, a, tdeps[a])
1077
# put output env vars in place
1079
if not t.sname in denv.outenv: continue
1080
tdeps = denv.outenv[t.sname]
1084
debug('deps: loaded saved dependencies')
1089
def check_project_rules(bld):
1090
'''check the project rules - ensuring the targets are sane'''
1095
tgt_list = get_tgt_list(bld)
1097
add_samba_attributes(bld, tgt_list)
1099
force_project_rules = (Options.options.SHOWDEPS or
1100
Options.options.SHOW_DUPLICATES)
1102
if not force_project_rules and load_samba_deps(bld, tgt_list):
1106
tstart = time.clock()
1108
bld.new_rules = True
1109
Logs.info("Checking project rules ...")
1111
debug('deps: project rules checking started')
1113
expand_subsystem_deps(bld)
1115
debug("deps: expand_subsystem_deps: %f" % (time.clock() - tstart))
1117
replace_grouping_libraries(bld, tgt_list)
1119
debug("deps: replace_grouping_libraries: %f" % (time.clock() - tstart))
1121
build_direct_deps(bld, tgt_list)
1123
debug("deps: build_direct_deps: %f" % (time.clock() - tstart))
1125
break_dependency_loops(bld, tgt_list)
1127
debug("deps: break_dependency_loops: %f" % (time.clock() - tstart))
1129
if Options.options.SHOWDEPS:
1130
show_dependencies(bld, Options.options.SHOWDEPS, set())
1132
calculate_final_deps(bld, tgt_list, loops)
1134
debug("deps: calculate_final_deps: %f" % (time.clock() - tstart))
1136
if Options.options.SHOW_DUPLICATES:
1137
show_object_duplicates(bld, tgt_list)
1139
# run the various attribute generators
1140
for f in [ build_dependencies, build_includes, add_init_functions ]:
1141
debug('deps: project rules checking %s', f)
1142
for t in tgt_list: f(t)
1143
debug("deps: %s: %f" % (f, time.clock() - tstart))
1145
debug('deps: project rules stage1 completed')
1147
#check_orpaned_targets(bld, tgt_list)
1149
if not check_duplicate_sources(bld, tgt_list):
1150
Logs.error("Duplicate sources present - aborting")
1153
debug("deps: check_duplicate_sources: %f" % (time.clock() - tstart))
1155
if not check_group_ordering(bld, tgt_list):
1156
Logs.error("Bad group ordering - aborting")
1159
debug("deps: check_group_ordering: %f" % (time.clock() - tstart))
1161
show_final_deps(bld, tgt_list)
1163
debug("deps: show_final_deps: %f" % (time.clock() - tstart))
1165
debug('deps: project rules checking completed - %u targets checked',
1168
if not bld.is_install:
1169
save_samba_deps(bld, tgt_list)
1171
debug("deps: save_samba_deps: %f" % (time.clock() - tstart))
1173
Logs.info("Project rules pass")
1176
def CHECK_PROJECT_RULES(bld):
1177
'''enable checking of project targets for sanity'''
1178
if bld.env.added_project_rules:
1180
bld.env.added_project_rules = True
1181
bld.add_pre_fun(check_project_rules)
1182
Build.BuildContext.CHECK_PROJECT_RULES = CHECK_PROJECT_RULES