~ubuntu-branches/ubuntu/precise/samba/precise

« back to all changes in this revision

Viewing changes to buildtools/wafsamba/samba_deps.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2011-12-21 13:18:04 UTC
  • mfrom: (0.39.21 sid)
  • Revision ID: package-import@ubuntu.com-20111221131804-xtlr39wx6njehxxr
Tags: 2:3.6.1-3ubuntu1
* Merge from Debian testing.  Remaining changes:
  + debian/patches/VERSION.patch:
    - set SAMBA_VERSION_SUFFIX to Ubuntu.
  + debian/patches/error-trans.fix-276472:
    - Add the translation of Unix Error code -ENOTSUP to NT Error Code
    - NT_STATUS_NOT_SUPPORTED to prevent the Permission denied error.
  + debian/smb.conf:
    - add "(Samba, Ubuntu)" to server string.
    - comment out the default [homes] share, and add a comment about
      "valid users = %S" to show users how to restrict access to
      \\server\username to only username.
    - Set 'usershare allow guests', so that usershare admins are 
      allowed to create public shares in addition to authenticated
      ones.
    - add map to guest = Bad user, maps bad username to guest access.
  + debian/samba-common.config:
    - Do not change priority to high if dhclient3 is installed.
    - Use priority medium instead of high for the workgroup question.
  + debian/control:
    - Don't build against or suggest ctdb.
    - Add dependency on samba-common-bin to samba.
  + Add ufw integration:
    - Created debian/samba.ufw.profile
    - debian/rules, debian/samba.dirs, debian/samba.files: install
      profile
    - debian/control: have samba suggest ufw
  + Add apport hook:
    - Created debian/source_samba.py.
    - debian/rules, debian/samba.dirs, debian/samba-common-bin.files: install
  + Switch to upstart:
    - Add debian/samba.{nmbd,smbd}.upstart.
  + debian/samba.logrotate, debian/samba-common.dhcp, debian/samba.if-up:
    - Make them upstart compatible
  + debian/samba.postinst: 
    - Avoid scary pdbedit warnings on first import.
  + debian/samba-common.postinst: Add more informative error message for
    the case where smb.conf was manually deleted
  + debian/patches/fix-debuglevel-name-conflict.patch: don't use 'debug_level'
    as a global variable name in an NSS module 
  + Dropped:
    - debian/patches/error-trans.fix-276472
    - debian/patches/fix-debuglevel-name-conflict.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Samba automatic dependency handling and project rules
 
2
 
 
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
 
7
 
 
8
@conf
 
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)
 
14
 
 
15
 
 
16
@conf
 
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
 
20
 
 
21
 
 
22
@conf
 
23
def SET_SYSLIB_DEPS(conf, target, deps):
 
24
    '''setup some implied dependencies for a SYSLIB'''
 
25
    cache = LOCAL_CACHE(conf, 'SYSLIB_DEPS')
 
26
    cache[target] = deps
 
27
 
 
28
 
 
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'''
 
34
 
 
35
    subsystem_list = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
 
36
    targets    = LOCAL_CACHE(bld, 'TARGET_TYPE')
 
37
 
 
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':
 
42
            continue
 
43
 
 
44
        # for example,
 
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)
 
49
 
 
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']:
 
56
                continue
 
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)
 
65
 
 
66
 
 
67
 
 
68
def build_dependencies(self):
 
69
    '''This builds the dependency list for a target. It runs after all the targets are declared
 
70
 
 
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.
 
73
    '''
 
74
 
 
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)
 
79
 
 
80
        # extra link flags from pkg_config
 
81
        libs = self.final_syslibs.copy()
 
82
 
 
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
 
87
 
 
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)
 
91
 
 
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)
 
94
 
 
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)
 
103
 
 
104
    if getattr(self, 'uselib', None):
 
105
        up_list = []
 
106
        for l in self.uselib:
 
107
           up_list.append(l.upper())
 
108
        self.uselib = up_list
 
109
 
 
110
 
 
111
def build_includes(self):
 
112
    '''This builds the right set of includes for a target.
 
113
 
 
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).
 
117
 
 
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=
 
122
    attribute
 
123
    '''
 
124
 
 
125
    if getattr(self, 'samba_includes', None) is None:
 
126
        return
 
127
 
 
128
    bld = self.bld
 
129
 
 
130
    inc_deps = includes_objects(bld, self, set(), {})
 
131
 
 
132
    includes = []
 
133
 
 
134
    # maybe add local includes
 
135
    if getattr(self, 'local_include', True) == True and getattr(self, 'local_include_first', True):
 
136
        includes.append('.')
 
137
 
 
138
    includes.extend(self.samba_includes_extended)
 
139
 
 
140
    if 'EXTRA_INCLUDES' in bld.env and getattr(self, 'global_include', True):
 
141
        includes.extend(bld.env['EXTRA_INCLUDES'])
 
142
 
 
143
    includes.append('#')
 
144
 
 
145
    inc_set = set()
 
146
    inc_abs = []
 
147
 
 
148
    for d in inc_deps:
 
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:
 
153
            inclist.append('.')
 
154
        if inclist == []:
 
155
            continue
 
156
        tpath = t.samba_abspath
 
157
        for inc in inclist:
 
158
            npath = tpath + '/' + inc
 
159
            if not npath in inc_set:
 
160
                inc_abs.append(npath)
 
161
                inc_set.add(npath)
 
162
 
 
163
    mypath = self.path.abspath(bld.env)
 
164
    for inc in inc_abs:
 
165
        relpath = os_path_relpath(inc, mypath)
 
166
        includes.append(relpath)
 
167
 
 
168
    if getattr(self, 'local_include', True) == True and not getattr(self, 'local_include_first', True):
 
169
        includes.append('.')
 
170
 
 
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
 
174
    includes_top = []
 
175
    for i in includes:
 
176
        if i[0] == '#':
 
177
            # some are already top based
 
178
            includes_top.append(i)
 
179
            continue
 
180
        absinc = os.path.join(self.path.abspath(), i)
 
181
        relinc = os_path_relpath(absinc, self.bld.srcnode.abspath())
 
182
        includes_top.append('#' + relinc)
 
183
 
 
184
    self.includes = unique_list(includes_top)
 
185
    debug('deps: includes for target %s: includes=%s',
 
186
          self.sname, self.includes)
 
187
 
 
188
 
 
189
 
 
190
 
 
191
def add_init_functions(self):
 
192
    '''This builds the right set of init functions'''
 
193
 
 
194
    bld = self.bld
 
195
 
 
196
    subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
 
197
 
 
198
    # cope with the separated object lists from BINARY and LIBRARY targets
 
199
    sname = self.sname
 
200
    if sname.endswith('.objlist'):
 
201
        sname = sname[0:-8]
 
202
 
 
203
    modules = []
 
204
    if sname in subsystems:
 
205
        modules.append(sname)
 
206
 
 
207
    m = getattr(self, 'samba_modules', None)
 
208
    if m is not None:
 
209
        modules.extend(TO_LIST(m))
 
210
 
 
211
    m = getattr(self, 'samba_subsystem', None)
 
212
    if m is not None:
 
213
        modules.append(m)
 
214
 
 
215
    sentinal = getattr(self, 'init_function_sentinal', 'NULL')
 
216
 
 
217
    targets    = LOCAL_CACHE(bld, 'TARGET_TYPE')
 
218
    cflags = getattr(self, 'samba_cflags', [])[:]
 
219
 
 
220
    if modules == []:
 
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
 
227
        return
 
228
 
 
229
    for m in modules:
 
230
        bld.ASSERT(m in subsystems,
 
231
                   "No init_function defined for module '%s' in target '%s'" % (m, self.sname))
 
232
        init_fn_list = []
 
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)
 
240
        else:
 
241
            cflags.append('-DSTATIC_%s_MODULES=%s' % (m, ','.join(init_fn_list) + ',' + sentinal))
 
242
            proto=''
 
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
 
247
 
 
248
 
 
249
 
 
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'''
 
253
 
 
254
    debug('deps: checking for duplicate sources')
 
255
 
 
256
    targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
 
257
    ret = True
 
258
 
 
259
    global tstart
 
260
 
 
261
    for t in tgt_list:
 
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'))
 
264
        obj_sources = set()
 
265
        for s in source_list:
 
266
            p = os.path.normpath(os.path.join(tpath, s))
 
267
            if p in obj_sources:
 
268
                Logs.error("ERROR: source %s appears twice in target '%s'" % (p, t.sname))
 
269
                sys.exit(1)
 
270
            obj_sources.add(p)
 
271
        t.samba_source_set = obj_sources
 
272
 
 
273
    subsystems = {}
 
274
 
 
275
    # build a list of targets that each source file is part of
 
276
    for t in tgt_list:
 
277
        sources = []
 
278
        if not targets[t.sname] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
 
279
            continue
 
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())
 
283
            for s in source_set:
 
284
                if not s in subsystems:
 
285
                    subsystems[s] = {}
 
286
                if not t.sname in subsystems[s]:
 
287
                    subsystems[s][t.sname] = []
 
288
                subsystems[s][t.sname].append(t2.sname)
 
289
 
 
290
    for s in subsystems:
 
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]))
 
296
                
 
297
    return ret
 
298
 
 
299
 
 
300
def check_orpaned_targets(bld, tgt_list):
 
301
    '''check if any build targets are orphaned'''
 
302
 
 
303
    target_dict = LOCAL_CACHE(bld, 'TARGET_TYPE')
 
304
 
 
305
    debug('deps: checking for orphaned targets')
 
306
 
 
307
    for t in tgt_list:
 
308
        if getattr(t, 'samba_used', False) == True:
 
309
            continue
 
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))
 
314
 
 
315
 
 
316
def check_group_ordering(bld, tgt_list):
 
317
    '''see if we have any dependencies that violate the group ordering
 
318
 
 
319
    It is an error for a target to depend on a target from a later
 
320
    build group
 
321
    '''
 
322
 
 
323
    def group_name(g):
 
324
        tm = bld.task_manager
 
325
        return [x for x in tm.groups_names if id(tm.groups_names[x]) == id(g)][0]
 
326
 
 
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
 
331
 
 
332
    grp_map = {}
 
333
    idx = 0
 
334
    for g in bld.task_manager.groups:
 
335
        name = group_name(g)
 
336
        grp_map[name] = idx
 
337
        idx += 1
 
338
 
 
339
    targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
 
340
 
 
341
    ret = True
 
342
    for t in tgt_list:
 
343
        tdeps = getattr(t, 'add_objects', []) + getattr(t, 'uselib_local', [])
 
344
        for d in tdeps:
 
345
            t2 = bld.name_to_obj(d, bld.env)
 
346
            if t2 is None:
 
347
                continue
 
348
            map1 = grp_map[t.samba_group]
 
349
            map2 = grp_map[t2.samba_group]
 
350
 
 
351
            if map2 > map1:
 
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))
 
354
                ret = False
 
355
 
 
356
    return ret
 
357
 
 
358
 
 
359
def show_final_deps(bld, tgt_list):
 
360
    '''show the final dependencies for all targets'''
 
361
 
 
362
    targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
 
363
 
 
364
    for t in tgt_list:
 
365
        if not targets[t.sname] in ['LIBRARY', 'BINARY', 'PYTHON', 'SUBSYSTEM']:
 
366
            continue
 
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', []))
 
369
 
 
370
 
 
371
def add_samba_attributes(bld, tgt_list):
 
372
    '''ensure a target has a the required samba attributes'''
 
373
 
 
374
    targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
 
375
 
 
376
    for t in tgt_list:
 
377
        if t.name != '':
 
378
            t.sname = t.name
 
379
        else:
 
380
            t.sname = t.target
 
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', '')
 
386
 
 
387
def replace_grouping_libraries(bld, tgt_list):
 
388
    '''replace dependencies based on grouping libraries
 
389
 
 
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
 
393
    '''
 
394
 
 
395
    targets  = LOCAL_CACHE(bld, 'TARGET_TYPE')
 
396
 
 
397
    grouping = {}
 
398
 
 
399
    # find our list of grouping libraries, mapped from the subsystems they depend on
 
400
    for t in tgt_list:
 
401
        if not getattr(t, 'grouping_library', False):
 
402
            continue
 
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
 
407
 
 
408
    # now replace any dependencies on elements of grouping libraries
 
409
    for t in tgt_list:
 
410
        for i in range(len(t.samba_deps_extended)):
 
411
            dep = t.samba_deps_extended[i]
 
412
            if dep in grouping:
 
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]
 
416
 
 
417
 
 
418
 
 
419
def build_direct_deps(bld, tgt_list):
 
420
    '''build the direct_objects and direct_libs sets for each target'''
 
421
 
 
422
    targets  = LOCAL_CACHE(bld, 'TARGET_TYPE')
 
423
    syslib_deps  = LOCAL_CACHE(bld, 'SYSLIB_DEPS')
 
424
 
 
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')
 
433
 
 
434
    for t in tgt_list:
 
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)
 
441
        for d in deps:
 
442
            if d == t.sname: continue
 
443
            if not d in targets:
 
444
                Logs.error("Unknown dependency '%s' in '%s'" % (d, t.sname))
 
445
                sys.exit(1)
 
446
            if targets[d] in [ 'EMPTY', 'DISABLED' ]:
 
447
                continue
 
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))
 
452
                sys.exit(1)
 
453
            if targets[d] == 'SYSLIB':
 
454
                t.direct_syslibs.add(d)
 
455
                if d in syslib_deps:
 
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)
 
463
                        else:
 
464
                            Logs.error('Implied dependency %s in %s is of type %s' % (
 
465
                                implied, t.sname, targets[implied]))
 
466
                            sys.exit(1)
 
467
                continue
 
468
            t2 = bld.name_to_obj(d, bld.env)
 
469
            if t2 is None:
 
470
                Logs.error("no task %s of type %s in %s" % (d, targets[d], t.sname))
 
471
                sys.exit(1)
 
472
            if t2.samba_type in [ 'LIBRARY', 'MODULE' ]:
 
473
                t.direct_libs.add(d)
 
474
            elif t2.samba_type in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]:
 
475
                t.direct_objects.add(d)
 
476
    debug('deps: built direct dependencies')
 
477
 
 
478
 
 
479
def dependency_loop(loops, t, target):
 
480
    '''add a dependency loop to the loops dictionary'''
 
481
    if t.sname == target:
 
482
        return
 
483
    if not target in loops:
 
484
        loops[target] = set()
 
485
    if not t.sname in loops[target]:
 
486
        loops[target].add(t.sname)
 
487
 
 
488
 
 
489
def indirect_libs(bld, t, chain, loops):
 
490
    '''recursively calculate the indirect library dependencies for a target
 
491
 
 
492
    An indirect library is a library that results from a dependency on
 
493
    a subsystem
 
494
    '''
 
495
 
 
496
    ret = getattr(t, 'indirect_libs', None)
 
497
    if ret is not None:
 
498
        return ret
 
499
 
 
500
    ret = set()
 
501
    for obj in t.direct_objects:
 
502
        if obj in chain:
 
503
            dependency_loop(loops, t, obj)
 
504
            continue
 
505
        chain.add(obj)
 
506
        t2 = bld.name_to_obj(obj, bld.env)
 
507
        r2 = indirect_libs(bld, t2, chain, loops)
 
508
        chain.remove(obj)
 
509
        ret = ret.union(t2.direct_libs)
 
510
        ret = ret.union(r2)
 
511
 
 
512
    for obj in indirect_objects(bld, t, set(), loops):
 
513
        if obj in chain:
 
514
            dependency_loop(loops, t, obj)
 
515
            continue
 
516
        chain.add(obj)
 
517
        t2 = bld.name_to_obj(obj, bld.env)
 
518
        r2 = indirect_libs(bld, t2, chain, loops)
 
519
        chain.remove(obj)
 
520
        ret = ret.union(t2.direct_libs)
 
521
        ret = ret.union(r2)
 
522
 
 
523
    t.indirect_libs = ret
 
524
 
 
525
    return ret
 
526
 
 
527
 
 
528
def indirect_objects(bld, t, chain, loops):
 
529
    '''recursively calculate the indirect object dependencies for a target
 
530
 
 
531
    indirect objects are the set of objects from expanding the
 
532
    subsystem dependencies
 
533
    '''
 
534
 
 
535
    ret = getattr(t, 'indirect_objects', None)
 
536
    if ret is not None: return ret
 
537
 
 
538
    ret = set()
 
539
    for lib in t.direct_objects:
 
540
        if lib in chain:
 
541
            dependency_loop(loops, t, lib)
 
542
            continue
 
543
        chain.add(lib)
 
544
        t2 = bld.name_to_obj(lib, bld.env)
 
545
        r2 = indirect_objects(bld, t2, chain, loops)
 
546
        chain.remove(lib)
 
547
        ret = ret.union(t2.direct_objects)
 
548
        ret = ret.union(r2)
 
549
 
 
550
    t.indirect_objects = ret
 
551
    return ret
 
552
 
 
553
 
 
554
def extended_objects(bld, t, chain):
 
555
    '''recursively calculate the extended object dependencies for a target
 
556
 
 
557
    extended objects are the union of:
 
558
       - direct objects
 
559
       - indirect objects
 
560
       - direct and indirect objects of all direct and indirect libraries
 
561
    '''
 
562
 
 
563
    ret = getattr(t, 'extended_objects', None)
 
564
    if ret is not None: return ret
 
565
 
 
566
    ret = set()
 
567
    ret = ret.union(t.final_objects)
 
568
 
 
569
    for lib in t.final_libs:
 
570
        if lib in chain:
 
571
            continue
 
572
        t2 = bld.name_to_obj(lib, bld.env)
 
573
        chain.add(lib)
 
574
        r2 = extended_objects(bld, t2, chain)
 
575
        chain.remove(lib)
 
576
        ret = ret.union(t2.final_objects)
 
577
        ret = ret.union(r2)
 
578
 
 
579
    t.extended_objects = ret
 
580
    return ret
 
581
 
 
582
 
 
583
def includes_objects(bld, t, chain, inc_loops):
 
584
    '''recursively calculate the includes object dependencies for a target
 
585
 
 
586
    includes dependencies come from either library or object dependencies
 
587
    '''
 
588
    ret = getattr(t, 'includes_objects', None)
 
589
    if ret is not None:
 
590
        return ret
 
591
 
 
592
    ret = t.direct_objects.copy()
 
593
    ret = ret.union(t.direct_libs)
 
594
 
 
595
    for obj in t.direct_objects:
 
596
        if obj in chain:
 
597
            dependency_loop(inc_loops, t, obj)
 
598
            continue
 
599
        chain.add(obj)
 
600
        t2 = bld.name_to_obj(obj, bld.env)
 
601
        r2 = includes_objects(bld, t2, chain, inc_loops)
 
602
        chain.remove(obj)
 
603
        ret = ret.union(t2.direct_objects)
 
604
        ret = ret.union(r2)
 
605
 
 
606
    for lib in t.direct_libs:
 
607
        if lib in chain:
 
608
            dependency_loop(inc_loops, t, lib)
 
609
            continue
 
610
        chain.add(lib)
 
611
        t2 = bld.name_to_obj(lib, bld.env)
 
612
        if t2 is None:
 
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))
 
616
            sys.exit(1)
 
617
        r2 = includes_objects(bld, t2, chain, inc_loops)
 
618
        chain.remove(lib)
 
619
        ret = ret.union(t2.direct_objects)
 
620
        ret = ret.union(r2)
 
621
 
 
622
    t.includes_objects = ret
 
623
    return ret
 
624
 
 
625
 
 
626
def break_dependency_loops(bld, tgt_list):
 
627
    '''find and break dependency loops'''
 
628
    loops = {}
 
629
    inc_loops = {}
 
630
 
 
631
    # build up the list of loops
 
632
    for t in tgt_list:
 
633
        indirect_objects(bld, t, set(), loops)
 
634
        indirect_libs(bld, t, set(), loops)
 
635
        includes_objects(bld, t, set(), inc_loops)
 
636
 
 
637
    # break the loops
 
638
    for t in tgt_list:
 
639
        if t.sname in 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]))
 
643
 
 
644
    for loop in loops:
 
645
        debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
 
646
 
 
647
    for loop in inc_loops:
 
648
        debug('deps: Found include loops for target %s : %s', loop, inc_loops[loop])
 
649
 
 
650
    # expand the loops mapping by one level
 
651
    for loop in loops.copy():
 
652
        for tgt in loops[loop]:
 
653
            if tgt in loops:
 
654
                loops[loop] = loops[loop].union(loops[tgt])
 
655
 
 
656
    for loop in inc_loops.copy():
 
657
        for tgt in inc_loops[loop]:
 
658
            if tgt in inc_loops:
 
659
                inc_loops[loop] = inc_loops[loop].union(inc_loops[tgt])
 
660
 
 
661
 
 
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)
 
673
 
 
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)
 
680
 
 
681
    # add in the replacement dependencies
 
682
    for t in tgt_list:
 
683
        for loop in loops:
 
684
            for attr in ['indirect_objects', 'indirect_libs']:
 
685
                objs = getattr(t, attr, set())
 
686
                if loop in objs:
 
687
                    diff = loops[loop].difference(objs)
 
688
                    if t.sname in diff:
 
689
                        diff.remove(t.sname)
 
690
                    if diff:
 
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)
 
694
 
 
695
        for loop in inc_loops:
 
696
            objs = getattr(t, 'includes_objects', set())
 
697
            if loop in objs:
 
698
                diff = inc_loops[loop].difference(objs)
 
699
                if t.sname in diff:
 
700
                    diff.remove(t.sname)
 
701
                if diff:
 
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)
 
705
 
 
706
 
 
707
def reduce_objects(bld, tgt_list):
 
708
    '''reduce objects by looking for indirect object dependencies'''
 
709
    rely_on = {}
 
710
 
 
711
    for t in tgt_list:
 
712
        t.extended_objects = None
 
713
 
 
714
    changed = False
 
715
 
 
716
    for type in ['BINARY', 'PYTHON', 'LIBRARY']:
 
717
        for t in tgt_list:
 
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])
 
727
                if dup:
 
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)
 
731
                    changed = True
 
732
                    if not l in rely_on:
 
733
                        rely_on[l] = set()
 
734
                    rely_on[l] = rely_on[l].union(dup)
 
735
            t.final_objects = new
 
736
 
 
737
    if not changed:
 
738
        return False
 
739
 
 
740
    # add back in any objects that were relied upon by the reduction rules
 
741
    for r in rely_on:
 
742
        t = bld.name_to_obj(r, bld.env)
 
743
        t.final_objects = t.final_objects.union(rely_on[r])
 
744
 
 
745
    return True
 
746
 
 
747
 
 
748
def show_library_loop(bld, lib1, lib2, path, seen):
 
749
    '''show the detailed path of a library loop between lib1 and lib2'''
 
750
 
 
751
    t = bld.name_to_obj(lib1, bld.env)
 
752
    if not lib2 in getattr(t, 'final_libs', set()):
 
753
        return
 
754
 
 
755
    for d in t.samba_deps_extended:
 
756
        if d in seen:
 
757
            continue
 
758
        seen.add(d)
 
759
        path2 = path + '=>' + d
 
760
        if d == lib2:
 
761
            Logs.warn('library loop path: ' + path2)
 
762
            return
 
763
        show_library_loop(bld, d, lib2, path2, seen)
 
764
        seen.remove(d)
 
765
 
 
766
 
 
767
def calculate_final_deps(bld, tgt_list, loops):
 
768
    '''calculate the final library and object dependencies'''
 
769
    for t in tgt_list:
 
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))
 
773
 
 
774
    for t in tgt_list:
 
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)
 
780
 
 
781
    # handle any non-shared binaries
 
782
    for t in tgt_list:
 
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')
 
786
 
 
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)
 
791
                if t2 is None:
 
792
                    Logs.error('ERROR: subsystem %s not found' % objname)
 
793
                    sys.exit(1)
 
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
 
804
                        else:
 
805
                            continue
 
806
                        t2 = bld.name_to_obj(objname, bld.env)
 
807
                        if t2 is None:
 
808
                            Logs.error('ERROR: subsystem %s not found' % objname)
 
809
                            sys.exit(1)
 
810
                        t.final_objects.add(objname)
 
811
                        t.final_objects = t.final_objects.union(extended_objects(bld, t2, set()))
 
812
            t.final_libs = set()
 
813
 
 
814
    # find any library loops
 
815
    for t in tgt_list:
 
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)
 
827
                    else:
 
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())
 
832
                        sys.exit(1)
 
833
 
 
834
    for loop in loops:
 
835
        debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
 
836
 
 
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']:
 
841
        for t in tgt_list:
 
842
            if t.samba_type != type: continue
 
843
            for loop in loops:
 
844
                if loop in t.final_libs:
 
845
                    diff = loops[loop].difference(t.final_libs)
 
846
                    if t.sname in diff:
 
847
                        diff.remove(t.sname)
 
848
                    if t.sname in diff:
 
849
                        diff.remove(t.sname)
 
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)
 
856
                                diff.remove(d)
 
857
                    if diff:
 
858
                        debug('deps: Expanded target %s by loop %s libraries (loop %s) %s', t.sname, loop,
 
859
                              loops[loop], diff)
 
860
                        t.final_libs = t.final_libs.union(diff)
 
861
 
 
862
    # remove objects that are also available in linked libs
 
863
    count = 0
 
864
    while reduce_objects(bld, tgt_list):
 
865
        count += 1
 
866
        if count > 100:
 
867
            Logs.warn("WARNING: Unable to remove all inter-target object duplicates")
 
868
            break
 
869
    debug('deps: Object reduction took %u iterations', count)
 
870
 
 
871
    # add in any syslib dependencies
 
872
    for t in tgt_list:
 
873
        if not t.samba_type in ['BINARY','PYTHON','LIBRARY','SUBSYSTEM']:
 
874
            continue
 
875
        syslibs = set()
 
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
 
885
 
 
886
 
 
887
    # find any unresolved library loops
 
888
    lib_loop_error = False
 
889
    for t in tgt_list:
 
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
 
896
    if lib_loop_error:
 
897
        sys.exit(1)
 
898
 
 
899
    debug('deps: removed duplicate dependencies')
 
900
 
 
901
 
 
902
def show_dependencies(bld, target, seen):
 
903
    '''recursively show the dependencies of target'''
 
904
 
 
905
    if target in seen:
 
906
        return
 
907
 
 
908
    t = bld.name_to_obj(target, bld.env)
 
909
    if t is None:
 
910
        Logs.error("ERROR: Unable to find target '%s'" % target)
 
911
        sys.exit(1)
 
912
 
 
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))
 
916
 
 
917
    seen.add(target)
 
918
 
 
919
    for t2 in t.direct_objects:
 
920
        show_dependencies(bld, t2, seen)
 
921
 
 
922
 
 
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'''
 
926
 
 
927
    targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
 
928
 
 
929
    used_by = {}
 
930
 
 
931
    Logs.info("showing duplicate objects")
 
932
 
 
933
    for t in tgt_list:
 
934
        if not targets[t.sname] in [ 'LIBRARY', 'PYTHON' ]:
 
935
            continue
 
936
        for n in getattr(t, 'final_objects', set()):
 
937
            t2 = bld.name_to_obj(n, bld.env)
 
938
            if not n in used_by:
 
939
                used_by[n] = set()
 
940
            used_by[n].add(t.sname)
 
941
 
 
942
    for n in used_by:
 
943
        if len(used_by[n]) > 1:
 
944
            Logs.info("target '%s' is used by %s" % (n, used_by[n]))
 
945
 
 
946
    Logs.info("showing indirect dependency counts (sorted by count)")
 
947
 
 
948
    def indirect_count(t1, t2):
 
949
        return len(t2.indirect_objects) - len(t1.indirect_objects)
 
950
 
 
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)))
 
955
 
 
956
 
 
957
######################################################################
 
958
# this provides a way to save our dependency calculations between runs
 
959
savedeps_version = 3
 
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']
 
968
 
 
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()
 
973
 
 
974
    denv.version = savedeps_version
 
975
    denv.savedeps_inputs = savedeps_inputs
 
976
    denv.savedeps_outputs = savedeps_outputs
 
977
    denv.input = {}
 
978
    denv.output = {}
 
979
    denv.outenv = {}
 
980
    denv.caches = {}
 
981
    denv.envvar = {}
 
982
    denv.files  = {}
 
983
 
 
984
    for f in savedeps_files:
 
985
        denv.files[f] = os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime
 
986
 
 
987
    for c in savedeps_caches:
 
988
        denv.caches[c] = LOCAL_CACHE(bld, c)
 
989
 
 
990
    for e in savedeps_envvars:
 
991
        denv.envvar[e] = bld.env[e]
 
992
 
 
993
    for t in tgt_list:
 
994
        # save all the input attributes for each target
 
995
        tdeps = {}
 
996
        for attr in savedeps_inputs:
 
997
            v = getattr(t, attr, None)
 
998
            if v is not None:
 
999
                tdeps[attr] = v
 
1000
        if tdeps != {}:
 
1001
            denv.input[t.sname] = tdeps
 
1002
 
 
1003
        # save all the output attributes for each target
 
1004
        tdeps = {}
 
1005
        for attr in savedeps_outputs:
 
1006
            v = getattr(t, attr, None)
 
1007
            if v is not None:
 
1008
                tdeps[attr] = v
 
1009
        if tdeps != {}:
 
1010
            denv.output[t.sname] = tdeps
 
1011
 
 
1012
        tdeps = {}
 
1013
        for attr in savedeps_outenv:
 
1014
            if attr in t.env:
 
1015
                tdeps[attr] = t.env[attr]
 
1016
        if tdeps != {}:
 
1017
            denv.outenv[t.sname] = tdeps
 
1018
 
 
1019
    depsfile = os.path.join(bld.bdir, "sambadeps")
 
1020
    denv.store(depsfile)
 
1021
 
 
1022
 
 
1023
 
 
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()
 
1028
    try:
 
1029
        debug('deps: checking saved dependencies')
 
1030
        denv.load(depsfile)
 
1031
        if (denv.version != savedeps_version or
 
1032
            denv.savedeps_inputs != savedeps_inputs or
 
1033
            denv.savedeps_outputs != savedeps_outputs):
 
1034
            return False
 
1035
    except:
 
1036
        return False
 
1037
 
 
1038
    # check if critical files have changed
 
1039
    for f in savedeps_files:
 
1040
        if f not in denv.files:
 
1041
            return False
 
1042
        if denv.files[f] != os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime:
 
1043
            return False
 
1044
 
 
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):
 
1048
            return False
 
1049
 
 
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]:
 
1053
            return False
 
1054
 
 
1055
    # check inputs are the same
 
1056
    for t in tgt_list:
 
1057
        tdeps = {}
 
1058
        for attr in savedeps_inputs:
 
1059
            v = getattr(t, attr, None)
 
1060
            if v is not None:
 
1061
                tdeps[attr] = v
 
1062
        if t.sname in denv.input:
 
1063
            olddeps = denv.input[t.sname]
 
1064
        else:
 
1065
            olddeps = {}
 
1066
        if tdeps != olddeps:
 
1067
            #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
 
1068
            return False
 
1069
 
 
1070
    # put outputs in place
 
1071
    for t in tgt_list:
 
1072
        if not t.sname in denv.output: continue
 
1073
        tdeps = denv.output[t.sname]
 
1074
        for a in tdeps:
 
1075
            setattr(t, a, tdeps[a])
 
1076
 
 
1077
    # put output env vars in place
 
1078
    for t in tgt_list:
 
1079
        if not t.sname in denv.outenv: continue
 
1080
        tdeps = denv.outenv[t.sname]
 
1081
        for a in tdeps:
 
1082
            t.env[a] = tdeps[a]
 
1083
 
 
1084
    debug('deps: loaded saved dependencies')
 
1085
    return True
 
1086
 
 
1087
 
 
1088
 
 
1089
def check_project_rules(bld):
 
1090
    '''check the project rules - ensuring the targets are sane'''
 
1091
 
 
1092
    loops = {}
 
1093
    inc_loops = {}
 
1094
 
 
1095
    tgt_list = get_tgt_list(bld)
 
1096
 
 
1097
    add_samba_attributes(bld, tgt_list)
 
1098
 
 
1099
    force_project_rules = (Options.options.SHOWDEPS or
 
1100
                           Options.options.SHOW_DUPLICATES)
 
1101
 
 
1102
    if not force_project_rules and load_samba_deps(bld, tgt_list):
 
1103
        return
 
1104
 
 
1105
    global tstart
 
1106
    tstart = time.clock()
 
1107
 
 
1108
    bld.new_rules = True
 
1109
    Logs.info("Checking project rules ...")
 
1110
 
 
1111
    debug('deps: project rules checking started')
 
1112
 
 
1113
    expand_subsystem_deps(bld)
 
1114
 
 
1115
    debug("deps: expand_subsystem_deps: %f" % (time.clock() - tstart))
 
1116
 
 
1117
    replace_grouping_libraries(bld, tgt_list)
 
1118
 
 
1119
    debug("deps: replace_grouping_libraries: %f" % (time.clock() - tstart))
 
1120
 
 
1121
    build_direct_deps(bld, tgt_list)
 
1122
 
 
1123
    debug("deps: build_direct_deps: %f" % (time.clock() - tstart))
 
1124
 
 
1125
    break_dependency_loops(bld, tgt_list)
 
1126
 
 
1127
    debug("deps: break_dependency_loops: %f" % (time.clock() - tstart))
 
1128
 
 
1129
    if Options.options.SHOWDEPS:
 
1130
            show_dependencies(bld, Options.options.SHOWDEPS, set())
 
1131
 
 
1132
    calculate_final_deps(bld, tgt_list, loops)
 
1133
 
 
1134
    debug("deps: calculate_final_deps: %f" % (time.clock() - tstart))
 
1135
 
 
1136
    if Options.options.SHOW_DUPLICATES:
 
1137
            show_object_duplicates(bld, tgt_list)
 
1138
 
 
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))
 
1144
 
 
1145
    debug('deps: project rules stage1 completed')
 
1146
 
 
1147
    #check_orpaned_targets(bld, tgt_list)
 
1148
 
 
1149
    if not check_duplicate_sources(bld, tgt_list):
 
1150
        Logs.error("Duplicate sources present - aborting")
 
1151
        sys.exit(1)
 
1152
 
 
1153
    debug("deps: check_duplicate_sources: %f" % (time.clock() - tstart))
 
1154
 
 
1155
    if not check_group_ordering(bld, tgt_list):
 
1156
        Logs.error("Bad group ordering - aborting")
 
1157
        sys.exit(1)
 
1158
 
 
1159
    debug("deps: check_group_ordering: %f" % (time.clock() - tstart))
 
1160
 
 
1161
    show_final_deps(bld, tgt_list)
 
1162
 
 
1163
    debug("deps: show_final_deps: %f" % (time.clock() - tstart))
 
1164
 
 
1165
    debug('deps: project rules checking completed - %u targets checked',
 
1166
          len(tgt_list))
 
1167
 
 
1168
    if not bld.is_install:
 
1169
        save_samba_deps(bld, tgt_list)
 
1170
 
 
1171
    debug("deps: save_samba_deps: %f" % (time.clock() - tstart))
 
1172
 
 
1173
    Logs.info("Project rules pass")
 
1174
 
 
1175
 
 
1176
def CHECK_PROJECT_RULES(bld):
 
1177
    '''enable checking of project targets for sanity'''
 
1178
    if bld.env.added_project_rules:
 
1179
        return
 
1180
    bld.env.added_project_rules = True
 
1181
    bld.add_pre_fun(check_project_rules)
 
1182
Build.BuildContext.CHECK_PROJECT_RULES = CHECK_PROJECT_RULES
 
1183
 
 
1184