build: removed debug line
[nivanova/samba-autobuild/.git] / buildtools / wafsamba / samba_deps.py
index fa34cb8fcf765c7319ee618740938aa452bbd166..56b971a44733208e2cdacde620564104c94c585d 100644 (file)
@@ -22,6 +22,13 @@ def TARGET_ALIAS(bld, target, alias):
 Build.BuildContext.TARGET_ALIAS = TARGET_ALIAS
 
 
+@conf
+def SET_SYSLIB_DEPS(conf, target, deps):
+    '''setup some implied dependencies for a SYSLIB'''
+    cache = LOCAL_CACHE(conf, 'SYSLIB_DEPS')
+    cache[target] = deps
+
+
 def EXPAND_ALIAS(bld, target):
     '''expand a target name via an alias'''
     aliases = LOCAL_CACHE(bld, 'TARGET_ALIAS')
@@ -66,26 +73,31 @@ def build_dependencies(self):
     the full dependency list for a target until we have all of the targets declared.
     '''
 
-    # we only should add extra library and object deps on libraries and binaries
-    if not self.samba_type in ['LIBRARY', 'BINARY', 'PYTHON']:
-        return
+    if self.samba_type in ['LIBRARY', 'BINARY', 'PYTHON']:
+        self.uselib        = list(self.final_syslibs)
+        self.uselib_local  = list(self.final_libs)
+        self.add_objects   = list(self.final_objects)
 
-    # we need to link against:
+        # extra link flags from pkg_config
+        libs = self.final_syslibs.copy()
 
-    #  1) any direct system libs
-    #  2) any indirect system libs that come from subsystem dependencies
-    #  3) any direct local libs
-    #  4) any indirect local libs that come from subsystem dependencies
-    #  5) any direct objects
-    #  6) any indirect objects that come from subsystem dependencies
+        (ccflags, ldflags) = library_flags(self, list(libs))
+        new_ldflags        = getattr(self, 'ldflags', [])
+        new_ldflags.extend(ldflags)
+        self.ldflags       = new_ldflags
 
-    self.uselib        = list(self.final_syslibs)
-    self.uselib_local  = list(self.final_libs)
-    self.add_objects   = list(self.final_objects)
+        debug('deps: computed dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
+              self.sname, self.uselib, self.uselib_local, self.add_objects)
 
-    debug('deps: computed dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
-          self.sname, self.uselib, self.uselib_local, self.add_objects)
+    if self.samba_type in ['SUBSYSTEM']:
+        # this is needed for the ccflags of libs that come from pkg_config
+        self.uselib = list(self.direct_syslibs)
 
+    if getattr(self, 'uselib', None):
+        up_list = []
+       for l in self.uselib:
+           up_list.append(l.upper())
+       self.uselib = up_list
 
 
 def build_includes(self):
@@ -107,7 +119,7 @@ def build_includes(self):
 
     bld = self.bld
 
-    inc_deps = self.includes_objects
+    inc_deps = includes_objects(bld, self, set(), {})
 
     includes = []
 
@@ -197,14 +209,20 @@ def add_init_functions(self):
 
     sentinal = getattr(self, 'init_function_sentinal', 'NULL')
 
+    targets    = LOCAL_CACHE(bld, 'TARGET_TYPE')
+
     cflags = getattr(self, 'samba_cflags', [])[:]
     for m in modules:
         bld.ASSERT(m in subsystems,
                    "No init_function defined for module '%s' in target '%s'" % (m, self.sname))
         init_fn_list = []
         for d in subsystems[m]:
-            init_fn_list.append(d['INIT_FUNCTION'])
-        cflags.append('-DSTATIC_%s_MODULES=%s' % (m, ','.join(init_fn_list) + ',' + sentinal))
+            if targets[d['TARGET']] != 'DISABLED':
+                init_fn_list.append(d['INIT_FUNCTION'])
+        if init_fn_list == []:
+            cflags.append('-DSTATIC_%s_MODULES=%s' % (m, sentinal))
+        else:
+            cflags.append('-DSTATIC_%s_MODULES=%s' % (m, ','.join(init_fn_list) + ',' + sentinal))
     self.ccflags = cflags
 
 
@@ -216,6 +234,15 @@ def check_duplicate_sources(bld, tgt_list):
     debug('deps: checking for duplicate sources')
 
     targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
+    ret = True
+
+    seen = set()
+
+    for t in tgt_list:
+        obj_sources = getattr(t, 'source', '')
+        tpath = os_path_relpath(t.path.abspath(bld.env), t.env['BUILD_DIRECTORY'] + '/default')
+        obj_sources = bld.SUBDIR(tpath, obj_sources)
+        t.samba_source_set = set(TO_LIST(obj_sources))
 
     for t in tgt_list:
         if not targets[t.sname] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
@@ -224,22 +251,20 @@ def check_duplicate_sources(bld, tgt_list):
         sources = []
         for obj in t.add_objects:
             t2 = t.bld.name_to_obj(obj, bld.env)
-            obj_sources = getattr(t2, 'source', '')
-            if obj_sources == '': continue
-            tpath = os_path_relpath(t2.path.abspath(bld.env), t.env['BUILD_DIRECTORY'] + '/default')
-            obj_sources = bld.SUBDIR(tpath, obj_sources)
-            sources.append( { 'dep':obj, 'src':set(TO_LIST(obj_sources)) } )
-            #debug('deps: dependency expansion for target %s add_object %s: %s',
-            #      t.sname, obj, obj_sources)
-            for s in sources:
-                for s2 in sources:
-                    if s['dep'] == s2['dep']: continue
-                    common = s['src'].intersection(s2['src'])
-                    if common:
-                        bld.ASSERT(False,
-                                   "Target %s has duplicate source files in %s and %s : %s" % (t.sname,
-                                                                                               s['dep'], s2['dep'],
-                                                                                               common))
+            source_set = getattr(t2, 'samba_source_set', set())
+            sources.append( { 'dep':obj, 'src':source_set} )
+        for s in sources:
+            for s2 in sources:
+                if s['dep'] == s2['dep']: continue
+                common = s['src'].intersection(s2['src'])
+                if common.difference(seen):
+                    print("Target %s has duplicate source files in %s and %s : %s" % (t.sname,
+                                                                                      s['dep'], s2['dep'],
+                                                                                      common))
+                    seen = seen.union(common)
+                    ret = False
+    return ret
+
 
 def check_orpaned_targets(bld, tgt_list):
     '''check if any build targets are orphaned'''
@@ -285,10 +310,12 @@ def add_samba_attributes(bld, tgt_list):
         t.samba_includes_extended = TO_LIST(t.samba_includes)[:]
         t.ccflags = getattr(t, 'samba_cflags', '')
 
+
 def build_direct_deps(bld, tgt_list):
     '''build the direct_objects and direct_libs sets for each target'''
 
     targets  = LOCAL_CACHE(bld, 'TARGET_TYPE')
+    syslib_deps  = LOCAL_CACHE(bld, 'SYSLIB_DEPS')
     global_deps = bld.env.GLOBAL_DEPENDENCIES
 
     for t in tgt_list:
@@ -299,6 +326,7 @@ def build_direct_deps(bld, tgt_list):
         deps.extend(global_deps)
         for d in deps:
             d = EXPAND_ALIAS(bld, d)
+            if d == t.sname: continue
             if not d in targets:
                 print "Unknown dependency %s in %s" % (d, t.sname)
                 raise
@@ -306,6 +334,9 @@ def build_direct_deps(bld, tgt_list):
                 continue
             if targets[d] == 'SYSLIB':
                 t.direct_syslibs.add(d)
+                if d in syslib_deps:
+                    for implied in TO_LIST(syslib_deps[d]):
+                        t.direct_libs.add(implied)
                 continue
             t2 = bld.name_to_obj(d, bld.env)
             if t2 is None:
@@ -317,8 +348,17 @@ def build_direct_deps(bld, tgt_list):
     debug('deps: built direct dependencies')
 
 
+def dependency_loop(loops, t, target):
+    '''add a dependency loop to the loops dictionary'''
+    if t.sname == target:
+        return
+    if not target in loops:
+        loops[target] = set()
+    if not t.sname in loops[target]:
+        loops[target].add(t.sname)
+
 
-def indirect_libs(bld, t, chain):
+def indirect_libs(bld, t, chain, loops):
     '''recursively calculate the indirect library dependencies for a target
 
     An indirect library is a library that results from a dependency on
@@ -332,20 +372,22 @@ def indirect_libs(bld, t, chain):
     ret = set()
     for obj in t.direct_objects:
         if obj in chain:
+            dependency_loop(loops, t, obj)
             continue
         chain.add(obj)
         t2 = bld.name_to_obj(obj, bld.env)
-        r2 = indirect_libs(bld, t2, chain)
+        r2 = indirect_libs(bld, t2, chain, loops)
         chain.remove(obj)
         ret = ret.union(t2.direct_libs)
         ret = ret.union(r2)
 
-    for obj in t.indirect_objects:
+    for obj in indirect_objects(bld, t, set(), loops):
         if obj in chain:
+            dependency_loop(loops, t, obj)
             continue
         chain.add(obj)
         t2 = bld.name_to_obj(obj, bld.env)
-        r2 = indirect_libs(bld, t2, chain)
+        r2 = indirect_libs(bld, t2, chain, loops)
         chain.remove(obj)
         ret = ret.union(t2.direct_libs)
         ret = ret.union(r2)
@@ -355,31 +397,7 @@ def indirect_libs(bld, t, chain):
     return ret
 
 
-def indirect_syslibs(bld, t, chain):
-    '''recursively calculate the indirect system library dependencies for a target
-
-    An indirect syslib results from a subsystem dependency
-    '''
-
-    ret = getattr(t, 'indirect_syslibs', None)
-    if ret is not None:
-        return ret
-    ret = set()
-    for obj in t.direct_objects:
-        if obj in chain:
-            continue
-        chain.add(obj)
-        t2 = bld.name_to_obj(obj, bld.env)
-        r2 = indirect_syslibs(bld, t2, chain)
-        chain.remove(obj)
-        ret = ret.union(t2.direct_syslibs)
-        ret = ret.union(r2)
-
-    t.indirect_syslibs = ret
-    return ret
-
-
-def indirect_objects(bld, t, chain):
+def indirect_objects(bld, t, chain, loops):
     '''recursively calculate the indirect object dependencies for a target
 
     indirect objects are the set of objects from expanding the
@@ -392,10 +410,11 @@ def indirect_objects(bld, t, chain):
     ret = set()
     for lib in t.direct_objects:
         if lib in chain:
+            dependency_loop(loops, t, lib)
             continue
         chain.add(lib)
         t2 = bld.name_to_obj(lib, bld.env)
-        r2 = indirect_objects(bld, t2, chain)
+        r2 = indirect_objects(bld, t2, chain, loops)
         chain.remove(lib)
         ret = ret.union(t2.direct_objects)
         ret = ret.union(r2)
@@ -404,71 +423,38 @@ def indirect_objects(bld, t, chain):
     return ret
 
 
-def expanded_targets(bld, t, chain):
-    '''recursively calculate the expanded targets for a target
+def extended_objects(bld, t, chain):
+    '''recursively calculate the extended object dependencies for a target
 
-    expanded objects are the set of objects, libraries and syslibs
-    from expanding the subsystem dependencies, library dependencies
-    and syslib dependencies
+    extended objects are the union of:
+       - direct objects
+       - indirect objects
+       - direct and indirect objects of all direct and indirect libraries
     '''
 
-    ret = getattr(t, 'expanded_targets', None)
+    ret = getattr(t, 'extended_objects', None)
     if ret is not None: return ret
 
-    ret = t.direct_objects.copy()
-    ret = ret.union(t.direct_libs)
-    ret = ret.union(t.direct_syslibs)
-
-    direct = ret.copy()
+    ret = set()
+    ret = ret.union(t.direct_objects)
+    ret = ret.union(t.indirect_objects)
 
-    for d in direct:
-        if d in chain: continue
-        chain.add(d)
-        t2 = bld.name_to_obj(d, bld.env)
-        if t2 is None: continue
-        r2 = expanded_targets(bld, t2, chain)
-        chain.remove(d)
+    for lib in t.direct_libs:
+        if lib in chain:
+            continue
+        t2 = bld.name_to_obj(lib, bld.env)
+        chain.add(lib)
+        r2 = extended_objects(bld, t2, chain)
+        chain.remove(lib)
+        ret = ret.union(t2.direct_objects)
+        ret = ret.union(t2.indirect_objects)
         ret = ret.union(r2)
 
-    if t.sname in ret:
-        ret.remove(t.sname)
-
-    t.expanded_targets = ret
+    t.extended_objects = ret
     return ret
 
 
-def expanded_targets2(bld, t, chain):
-    '''recursively calculate the expanded targets for a target
-
-    expanded objects are the set of objects from expanding the
-    subsystem dependencies and library dependencies
-    '''
-
-    ret = getattr(t, 'expanded_targets2', None)
-    if ret is not None: return ret
-
-    ret = t.final_objects.copy()
-
-    for attr in [ 'final_objects', 'final_libs' ]:
-        f = getattr(t, attr, set())
-        for d in f.copy():
-            if d in chain:
-                continue
-            chain.add(d)
-            t2 = bld.name_to_obj(d, bld.env)
-            if t2 is None: continue
-            r2 = expanded_targets2(bld, t2, chain)
-            chain.remove(d)
-            ret = ret.union(r2)
-
-    if t.sname in ret:
-        ret.remove(t.sname)
-
-    t.expanded_targets2 = ret
-    return ret
-
-
-def includes_objects(bld, t, chain):
+def includes_objects(bld, t, chain, inc_loops):
     '''recursively calculate the includes object dependencies for a target
 
     includes dependencies come from either library or object dependencies
@@ -482,20 +468,22 @@ def includes_objects(bld, t, chain):
 
     for obj in t.direct_objects:
         if obj in chain:
+            dependency_loop(inc_loops, t, obj)
             continue
         chain.add(obj)
         t2 = bld.name_to_obj(obj, bld.env)
-        r2 = includes_objects(bld, t2, chain)
+        r2 = includes_objects(bld, t2, chain, inc_loops)
         chain.remove(obj)
         ret = ret.union(t2.direct_objects)
         ret = ret.union(r2)
 
     for lib in t.direct_libs:
         if lib in chain:
+            dependency_loop(inc_loops, t, lib)
             continue
         chain.add(lib)
         t2 = bld.name_to_obj(lib, bld.env)
-        r2 = includes_objects(bld, t2, chain)
+        r2 = includes_objects(bld, t2, chain, inc_loops)
         chain.remove(lib)
         ret = ret.union(t2.direct_objects)
         ret = ret.union(r2)
@@ -504,35 +492,67 @@ def includes_objects(bld, t, chain):
     return ret
 
 
-def build_indirect_deps(bld, tgt_list):
-    '''build the indirect_objects and indirect_libs sets for each target'''
-    for t in tgt_list:
-        indirect_objects(bld, t, set())
-        indirect_libs(bld, t, set())
-        indirect_syslibs(bld, t, set())
-        includes_objects(bld, t, set())
-        expanded_targets(bld, t, set())
-    debug('deps: built indirect dependencies')
+def break_dependency_loops(bld, tgt_list):
+    '''find and break dependency loops'''
+    loops = {}
+    inc_loops = {}
 
+    # build up the list of loops
+    for t in tgt_list:
+        indirect_objects(bld, t, set(), loops)
+        indirect_libs(bld, t, set(), loops)
+        includes_objects(bld, t, set(), inc_loops)
 
-def re_expand2(bld, tgt_list):
+    # break the loops
     for t in tgt_list:
-        t.expanded_targets2 = None
-    for type in ['BINARY','LIBRARY','PYTHON']:
-        for t in tgt_list:
-            if t.samba_type == type:
-                expanded_targets2(bld, t, set())
+        if t.sname in loops:
+            for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
+                objs = getattr(t, attr, set())
+                setattr(t, attr, objs.difference(loops[t.sname]))
+
+    for loop in loops:
+        debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
+
+    # expand the loops mapping by one level
+    for loop in loops.copy():
+        for tgt in loops[loop]:
+            if tgt in loops:
+                loops[loop] = loops[loop].union(loops[tgt])
+
+    # expand indirect subsystem and library loops
+    for loop in loops.copy():
+        t = bld.name_to_obj(loop, bld.env)
+        if t.samba_type in ['SUBSYSTEM']:
+            loops[loop] = loops[loop].union(t.indirect_objects)
+            loops[loop] = loops[loop].union(t.direct_objects)
+        if t.samba_type in ['LIBRARY','PYTHON']:
+            loops[loop] = loops[loop].union(t.indirect_libs)
+            loops[loop] = loops[loop].union(t.direct_libs)
+        if loop in loops[loop]:
+            loops[loop].remove(loop)
+
+    # add in the replacement dependencies
     for t in tgt_list:
-        expanded_targets2(bld, t, set())
-
-
-def calculate_final_deps(bld, tgt_list):
+        for loop in loops:
+            for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
+                objs = getattr(t, attr, set())
+                if loop in objs:
+                    diff = loops[loop].difference(objs)
+                    if t.sname in diff:
+                        diff.remove(t.sname)
+                    if diff:
+                        debug('deps: Expanded target %s of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
+                        objs = objs.union(diff)
+                if t.sname == 'ldb_password_hash':
+                    debug('deps: setting %s %s to %s', t.sname, attr, objs)
+                setattr(t, attr, objs)
+
+def calculate_final_deps(bld, tgt_list, loops):
     '''calculate the final library and object dependencies'''
     for t in tgt_list:
         # start with the maximum possible list
-        t.final_syslibs = t.direct_syslibs.union(t.indirect_syslibs)
-        t.final_libs    = t.direct_libs.union(t.indirect_libs)
-        t.final_objects = t.direct_objects.union(t.indirect_objects)
+        t.final_libs    = t.direct_libs.union(indirect_libs(bld, t, set(), loops))
+        t.final_objects = t.direct_objects.union(indirect_objects(bld, t, set(), loops))
 
     for t in tgt_list:
         # don't depend on ourselves
@@ -541,10 +561,6 @@ def calculate_final_deps(bld, tgt_list):
         if t.sname in t.final_objects:
             t.final_objects.remove(t.sname)
 
-    re_expand2(bld, tgt_list)
-
-    loops = {}
-
     # find any library loops
     for t in tgt_list:
         if t.samba_type in ['LIBRARY', 'PYTHON']:
@@ -554,53 +570,71 @@ def calculate_final_deps(bld, tgt_list):
                     # we could break this in either direction. If one of the libraries
                     # has a version number, and will this be distributed publicly, then
                     # we should make it the lower level library in the DAG
-                    debug('deps: removing library loop %s<->%s', t.sname, l)
+                    debug('deps: removing library loop %s from %s', t.sname, t2.sname)
+                    dependency_loop(loops, t, t2.sname)
                     t2.final_libs.remove(t.sname)
-                    loops[t2.sname] = t.sname;
-
-    re_expand2(bld, tgt_list)
 
     for type in ['BINARY']:
-        while True:
-            changed = False
-            for t in tgt_list:
-                if t.samba_type != type: continue
-                # if we will indirectly link to a target then we don't need it
-                new = t.final_objects.copy()
-                for l in t.final_libs:
-                    t2 = bld.name_to_obj(l, bld.env)
-                    dup = new.intersection(t2.expanded_targets2)
-                    if dup:
-                        debug('deps: removing dups from %s: %s also in %s %s',
-                              t.sname, dup, t2.samba_type, l)
-                        new = new.difference(dup)
-                        changed = True
-                if changed:
-                    t.final_objects = new
-                    break
-            if not changed:
-                break
+        for t in tgt_list:
+            if t.samba_type != type: continue
+            # if we will indirectly link to a target then we don't need it
+            new = t.final_objects.copy()
+            for l in t.final_libs:
+                t2 = bld.name_to_obj(l, bld.env)
+                t2_obj = extended_objects(bld, t2, set())
+                dup = new.intersection(t2_obj)
+                if dup:
+                    debug('deps: removing dups from %s of type %s: %s also in %s %s',
+                          t.sname, t.samba_type, dup, t2.samba_type, l)
+                    new = new.difference(dup)
+                    changed = True
+            t.final_objects = new
+
+    for loop in loops:
+        debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
 
     # we now need to make corrections for any library loops we broke up
     # any target that depended on the target of the loop and doesn't
     # depend on the source of the loop needs to get the loop source added
-    for type in ['BINARY']:
+    for type in ['BINARY','PYTHON','LIBRARY']:
         for t in tgt_list:
             if t.samba_type != type: continue
             for loop in loops:
-                if loop in t.final_libs and loops[loop] not in t.final_libs:
-                    t.final_libs.add(loops[loop])
+                if loop in t.final_libs:
+                    diff = loops[loop].difference(t.final_libs)
+                    if t.sname in diff:
+                        diff.remove(t.sname)
+                    if diff:
+                        debug('deps: Expanded target %s by loop %s libraries %s', t.sname, loop, diff)
+                        t.final_libs = t.final_libs.union(diff)
+
+    # add in any syslib dependencies
+    for t in tgt_list:
+        if not t.samba_type in ['BINARY','PYTHON','LIBRARY']:
+            continue
+        syslibs = set()
+        for d in t.final_objects:
+            t2 = bld.name_to_obj(d, bld.env)
+            syslibs = syslibs.union(t2.direct_syslibs)
+        # this adds the indirect syslibs as well, which may not be needed
+        # depending on the linker flags
+        for d in t.final_libs:
+            t2 = bld.name_to_obj(d, bld.env)
+            syslibs = syslibs.union(t2.direct_syslibs)
+        t.final_syslibs = syslibs
 
     debug('deps: removed duplicate dependencies')
 
 
+
 ######################################################################
 # this provides a way to save our dependency calculations between runs
-savedeps_version = 2
-savedeps_inputs  = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags']
+savedeps_version = 3
+savedeps_inputs  = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags', 'source']
 savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags']
 savedeps_outenv  = ['INC_PATHS']
-savedeps_caches  = ['GLOBAL_DEPENDENCIES', 'TARGET_ALIAS', 'TARGET_TYPE', 'INIT_FUNCTIONS']
+savedeps_caches  = ['GLOBAL_DEPENDENCIES', 'TARGET_ALIAS', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
+savedeps_files   = ['buildtools/wafsamba/samba_deps.py']
 
 def save_samba_deps(bld, tgt_list):
     '''save the dependency calculations between builds, to make
@@ -614,6 +648,10 @@ def save_samba_deps(bld, tgt_list):
     denv.output = {}
     denv.outenv = {}
     denv.caches = {}
+    denv.files  = {}
+
+    for f in savedeps_files:
+        denv.files[f] = os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime
 
     for c in savedeps_caches:
         denv.caches[c] = LOCAL_CACHE(bld, c)
@@ -662,6 +700,13 @@ def load_samba_deps(bld, tgt_list):
     except:
         return False
 
+    # check if critical files have changed
+    for f in savedeps_files:
+        if f not in denv.files:
+            return False
+        if denv.files[f] != os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime:
+            return False
+
     # check if caches are the same
     for c in savedeps_caches:
         if c not in denv.caches or denv.caches[c] != LOCAL_CACHE(bld, c):
@@ -704,6 +749,8 @@ def check_project_rules(bld):
     '''check the project rules - ensuring the targets are sane'''
 
     targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
+    loops = {}
+    inc_loops = {}
 
     # build a list of task generators we are interested in
     tgt_list = []
@@ -722,12 +769,14 @@ def check_project_rules(bld):
     if load_samba_deps(bld, tgt_list):
         return
 
+    print "Checking project rules ..."
+
     debug('deps: project rules checking started')
 
     expand_subsystem_deps(bld)
     build_direct_deps(bld, tgt_list)
-    build_indirect_deps(bld, tgt_list)
-    calculate_final_deps(bld, tgt_list)
+    break_dependency_loops(bld, tgt_list)
+    calculate_final_deps(bld, tgt_list, loops)
 
     # run the various attribute generators
     for f in [ build_dependencies, build_includes, add_init_functions ]:
@@ -737,7 +786,11 @@ def check_project_rules(bld):
     debug('deps: project rules stage1 completed')
 
     #check_orpaned_targets(bld, tgt_list)
-    #check_duplicate_sources(bld, tgt_list)
+
+    if not check_duplicate_sources(bld, tgt_list):
+        print "Duplicate sources present - aborting"
+        sys.exit(1)
+
     show_final_deps(bld, tgt_list)
 
     debug('deps: project rules checking completed - %u targets checked',
@@ -745,6 +798,8 @@ def check_project_rules(bld):
 
     save_samba_deps(bld, tgt_list)
 
+    print "Project rules pass"
+
 
 def CHECK_PROJECT_RULES(bld):
     '''enable checking of project targets for sanity'''