build: fixed a typo that prevented --bundled-libraries from working correctly
[samba.git] / buildtools / wafsamba / samba_deps.py
index 02d4c421d55a0d4a14f01b525a176be33634f7c2..cca2febda9e5792491976cb7e4b1a5f78c43d8b5 100644 (file)
@@ -1,8 +1,9 @@
 # Samba automatic dependency handling and project rules
 
-import Build, os, re, Environment
+import Build, os, re, Environment, Logs
 from samba_utils import *
 from samba_autoconf import *
+from samba_bundled import BUILTIN_LIBRARY
 
 @conf
 def ADD_GLOBAL_DEPENDENCY(ctx, dep):
@@ -16,12 +17,19 @@ def TARGET_ALIAS(bld, target, alias):
     '''define an alias for a target name'''
     cache = LOCAL_CACHE(bld, 'TARGET_ALIAS')
     if alias in cache:
-        print("Target alias %s already set to %s : newalias %s" % (alias, cache[alias], target))
-        raise
+        Logs.error("Target alias %s already set to %s : newalias %s" % (alias, cache[alias], target))
+        sys.exit(1)
     cache[alias] = target
 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')
@@ -88,10 +96,9 @@ def build_dependencies(self):
 
     if getattr(self, 'uselib', None):
         up_list = []
-       for l in self.uselib:
-           up_list.append(l.upper())
-       self.uselib = up_list
-
+        for l in self.uselib:
+           up_list.append(l.upper())
+        self.uselib = up_list
 
 def build_includes(self):
     '''This builds the right set of includes for a target.
@@ -233,7 +240,7 @@ def check_duplicate_sources(bld, tgt_list):
 
     for t in tgt_list:
         obj_sources = getattr(t, 'source', '')
-        tpath = os_path_relpath(t.path.abspath(bld.env), t.env['BUILD_DIRECTORY'] + '/default')
+        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))
 
@@ -251,7 +258,7 @@ def check_duplicate_sources(bld, tgt_list):
                 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,
+                    Logs.error("Target %s has duplicate source files in %s and %s : %s" % (t.sname,
                                                                                       s['dep'], s2['dep'],
                                                                                       common))
                     seen = seen.union(common)
@@ -272,7 +279,7 @@ def check_orpaned_targets(bld, tgt_list):
         type = target_dict[t.sname]
         if not type in ['BINARY', 'LIBRARY', 'MODULE', 'ET', 'PYTHON']:
             if re.search('^PIDL_', t.sname) is None:
-                print "Target %s of type %s is unused by any other target" % (t.sname, type)
+                Logs.warn("Target %s of type %s is unused by any other target" % (t.sname, type))
 
 
 def show_final_deps(bld, tgt_list):
@@ -308,6 +315,7 @@ 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:
@@ -315,21 +323,29 @@ def build_direct_deps(bld, tgt_list):
         t.direct_libs = set()
         t.direct_syslibs = set()
         deps = t.samba_deps_extended
-        deps.extend(global_deps)
+        if getattr(t, 'samba_use_global_deps', False):
+            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
+                Logs.error("Unknown dependency %s in %s" % (d, t.sname))
+                sys.exit(1)
             if targets[d] in [ 'EMPTY', 'DISABLED' ]:
                 continue
             if targets[d] == 'SYSLIB':
                 t.direct_syslibs.add(d)
+                if d in syslib_deps:
+                    for implied in TO_LIST(syslib_deps[d]):
+                        if BUILTIN_LIBRARY(bld, implied):
+                            t.direct_objects.add(implied)
+                        else:
+                            t.direct_libs.add(implied)
                 continue
             t2 = bld.name_to_obj(d, bld.env)
             if t2 is None:
-                print "no task %s type %s" % (d, targets[d])
+                Logs.error("no task %s of type %s in %s" % (d, targets[d], t.sname))
+                sys.exit(1)
             if t2.samba_type in [ 'LIBRARY', 'MODULE' ]:
                 t.direct_libs.add(d)
             elif t2.samba_type in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]:
@@ -425,18 +441,16 @@ def extended_objects(bld, t, chain):
     if ret is not None: return ret
 
     ret = set()
-    ret = ret.union(t.direct_objects)
-    ret = ret.union(t.indirect_objects)
+    ret = ret.union(t.final_objects)
 
-    for lib in t.direct_libs:
+    for lib in t.final_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(t2.final_objects)
         ret = ret.union(r2)
 
     t.extended_objects = ret
@@ -502,12 +516,21 @@ def break_dependency_loops(bld, tgt_list):
     for loop in loops:
         debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
 
+    for loop in inc_loops:
+        debug('deps: Found include loops for target %s : %s', loop, inc_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])
 
+    for loop in inc_loops.copy():
+        for tgt in inc_loops[loop]:
+            if tgt in inc_loops:
+                inc_loops[loop] = inc_loops[loop].union(inc_loops[tgt])
+
+
     # expand indirect subsystem and library loops
     for loop in loops.copy():
         t = bld.name_to_obj(loop, bld.env)
@@ -520,6 +543,13 @@ def break_dependency_loops(bld, tgt_list):
         if loop in loops[loop]:
             loops[loop].remove(loop)
 
+    # expand indirect includes loops
+    for loop in inc_loops.copy():
+        t = bld.name_to_obj(loop, bld.env)
+        inc_loops[loop] = inc_loops[loop].union(t.includes_objects)
+        if loop in inc_loops[loop]:
+            inc_loops[loop].remove(loop)
+
     # add in the replacement dependencies
     for t in tgt_list:
         for loop in loops:
@@ -532,10 +562,59 @@ def break_dependency_loops(bld, tgt_list):
                     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)
 
+        for loop in inc_loops:
+            objs = getattr(t, 'includes_objects', set())
+            if loop in objs:
+                diff = inc_loops[loop].difference(objs)
+                if t.sname in diff:
+                    diff.remove(t.sname)
+                if diff:
+                    debug('deps: Expanded target %s includes of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
+                    objs = objs.union(diff)
+            setattr(t, 'includes_objects', objs)
+
+
+def reduce_objects(bld, tgt_list):
+    '''reduce objects by looking for indirect object dependencies'''
+    rely_on = {}
+
+    for t in tgt_list:
+        t.extended_objects = None
+
+    changed = False
+
+    for type in ['BINARY', 'PYTHON', 'LIBRARY']:
+        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
+                    if not l in rely_on:
+                        rely_on[l] = set()
+                    rely_on[l] = rely_on[l].union(dup)
+            t.final_objects = new
+
+    if not changed:
+        return False
+
+    # add back in any objects that were relied upon by the reduction rules
+    for r in rely_on:
+        t = bld.name_to_obj(r, bld.env)
+        t.final_objects = t.final_objects.union(rely_on[r])
+
+    return True
+
+
 def calculate_final_deps(bld, tgt_list, loops):
     '''calculate the final library and object dependencies'''
     for t in tgt_list:
@@ -550,6 +629,7 @@ def calculate_final_deps(bld, tgt_list, loops):
         if t.sname in t.final_objects:
             t.final_objects.remove(t.sname)
 
+
     # find any library loops
     for t in tgt_list:
         if t.samba_type in ['LIBRARY', 'PYTHON']:
@@ -563,21 +643,6 @@ def calculate_final_deps(bld, tgt_list, loops):
                     dependency_loop(loops, t, t2.sname)
                     t2.final_libs.remove(t.sname)
 
-    for type in ['BINARY']:
-        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])
@@ -585,7 +650,7 @@ def calculate_final_deps(bld, tgt_list, loops):
     # 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','PYTHON','LIBRARY']:
+    for type in ['BINARY','PYTHON','LIBRARY','BINARY']:
         for t in tgt_list:
             if t.samba_type != type: continue
             for loop in loops:
@@ -597,6 +662,15 @@ def calculate_final_deps(bld, tgt_list, loops):
                         debug('deps: Expanded target %s by loop %s libraries %s', t.sname, loop, diff)
                         t.final_libs = t.final_libs.union(diff)
 
+    # remove objects that are also available in linked libs
+    count = 0
+    while reduce_objects(bld, tgt_list):
+        count += 1
+        if count > 100:
+            Logs.warn("WARNING: Unable to remove all inter-target object duplicates")
+            break
+    debug('deps: Object reduction took %u iterations', count)
+
     # add in any syslib dependencies
     for t in tgt_list:
         if not t.samba_type in ['BINARY','PYTHON','LIBRARY']:
@@ -615,14 +689,13 @@ def calculate_final_deps(bld, tgt_list, loops):
     debug('deps: removed duplicate dependencies')
 
 
-
 ######################################################################
 # this provides a way to save our dependency calculations between runs
 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):
@@ -675,6 +748,7 @@ def save_samba_deps(bld, tgt_list):
     denv.store(depsfile)
 
 
+
 def load_samba_deps(bld, tgt_list):
     '''load a previous set of build dependencies if possible'''
     depsfile = os.path.join(bld.bdir, "sambadeps")
@@ -734,6 +808,7 @@ def load_samba_deps(bld, tgt_list):
     return True
 
 
+
 def check_project_rules(bld):
     '''check the project rules - ensuring the targets are sane'''
 
@@ -749,8 +824,8 @@ def check_project_rules(bld):
             continue
         t = bld.name_to_obj(tgt, bld.env)
         if t is None:
-            print "Target %s of type %s has no task generator" % (tgt, type)
-            raise
+            Logs.error("Target %s of type %s has no task generator" % (tgt, type))
+            sys.exit(1)
         tgt_list.append(t)
 
     add_samba_attributes(bld, tgt_list)
@@ -758,7 +833,7 @@ def check_project_rules(bld):
     if load_samba_deps(bld, tgt_list):
         return
 
-    print "Checking project rules ..."
+    Logs.info("Checking project rules ...")
 
     debug('deps: project rules checking started')
 
@@ -777,7 +852,7 @@ def check_project_rules(bld):
     #check_orpaned_targets(bld, tgt_list)
 
     if not check_duplicate_sources(bld, tgt_list):
-        print "Duplicate sources present - aborting"
+        Logs.error("Duplicate sources present - aborting")
         sys.exit(1)
 
     show_final_deps(bld, tgt_list)
@@ -787,7 +862,7 @@ def check_project_rules(bld):
 
     save_samba_deps(bld, tgt_list)
 
-    print "Project rules pass"
+    Logs.info("Project rules pass")
 
 
 def CHECK_PROJECT_RULES(bld):