diff options
Diffstat (limited to 'buildtools/wafsamba/samba_deps.py')
-rw-r--r-- | buildtools/wafsamba/samba_deps.py | 823 |
1 files changed, 568 insertions, 255 deletions
diff --git a/buildtools/wafsamba/samba_deps.py b/buildtools/wafsamba/samba_deps.py index 41b786d6bf..d6b68f7c64 100644 --- a/buildtools/wafsamba/samba_deps.py +++ b/buildtools/wafsamba/samba_deps.py @@ -1,7 +1,6 @@ -# Samba automatic dependency handling +# Samba automatic dependency handling and project rules -from TaskGen import taskgen, before -import Build, os, string, Utils, re +import Build, os, re, Environment from samba_utils import * from samba_autoconf import * @@ -30,156 +29,66 @@ def EXPAND_ALIAS(bld, target): Build.BuildContext.EXPAND_ALIAS = EXPAND_ALIAS -def expand_dependencies(bld, dep, chain, path): - '''expand a dependency recursively - return a triple of (uselib, uselib_local, add_objects) - ''' - - dep = EXPAND_ALIAS(bld, dep) - - t = bld.name_to_obj(dep, bld.env) - - # check for a cached list - if t is not None: - expanded = getattr(t, 'expanded_dependencies', None) - if expanded is not None: - return expanded - - target_dict = LOCAL_CACHE(bld, 'TARGET_TYPE') - - uselib_local = [] - uselib = [] - add_objects = [] - - recurse = False - - bld.ASSERT(dep in target_dict, "Dependency %s not found in %s" % (dep, path)) - type = target_dict[dep] - if type == 'SYSLIB': - uselib.append(dep) - elif type == 'LIBRARY': - uselib_local.append(dep) - recurse = True - elif type == 'SUBSYSTEM': - add_objects.append(dep) - recurse = True - elif type == 'MODULE': - add_objects.append(dep) - recurse = True - elif type == 'PYTHON': - add_objects.append(dep) - recurse = True - elif type == 'ASN1': - add_objects.append(dep) - recurse = True - elif type == 'BINARY': - pass - elif type == 'EMPTY': - pass - elif type == 'DISABLED': - debug('deps: Ignoring dependency on disabled target %s: %s' % (dep, path)) - else: - bld.ASSERT(False, "Unknown target type %s for %s" % (type, dep)) - - # for some types we have to build the list recursively - if recurse: - bld.ASSERT(t is not None, "Unable to find target %s" % dep) - rec_deps = getattr(t, 'samba_deps', None) - bld.ASSERT(rec_deps is not None, "Unable to find dependencies of target %s" % dep) - for d2 in rec_deps: - try: - bld.ASSERT(d2 not in chain, "Circular dependency for %s: %s->%s" % (dep, path, d2)) - except: - print "Removing dependency %s from target %s" % (d2, dep) - rec_deps.remove(d2) - continue - c2 = chain.copy() - c2[d2] = True - (rec_uselib, rec_uselib_local, - rec_add_objects) = expand_dependencies(bld, d2, c2, "%s->%s" % (path, d2)) - uselib.extend(rec_uselib) - uselib_local.extend(rec_uselib_local) - add_objects.extend(rec_add_objects) - - if t is not None: - t.expanded_dependencies = (uselib, uselib_local, add_objects) - - return (uselib, uselib_local, add_objects) - - -def expand_deplist(self): - '''return an expanded list of dependencies from the samba_deps attribute''' - - if not getattr(self, 'samba_deps', None): - return ([], [], []) - - bld = self.bld - deps = self.samba_deps - - uselib_local = [] - uselib = [] - add_objects = [] - - for d in deps: - (u, ul, ao) = expand_dependencies(bld, d, { self.name:True }, self.name) - uselib.extend(u) - uselib_local.extend(ul) - add_objects.extend(ao) +def expand_subsystem_deps(bld): + '''expand the reverse dependencies resulting from subsystem + attributes of modules''' + subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS') + aliases = LOCAL_CACHE(bld, 'TARGET_ALIAS') + targets = LOCAL_CACHE(bld, 'TARGET_TYPE') + + for s in subsystems: + if s in aliases: + s = aliases[s] + bld.ASSERT(s in targets, "Subsystem target %s not declared" % s) + type = targets[s] + if type == 'DISABLED' or type == 'EMPTY': + continue - return (uselib, uselib_local, add_objects) + t = bld.name_to_obj(s, bld.env) + bld.ASSERT(t is not None, "Subsystem target %s not found" % s) + for d in subsystems[s]: + type = targets[d['TARGET']] + if type != 'DISABLED' and type != 'EMPTY': + t.samba_deps_extended.append(d['TARGET']) + t2 = bld.name_to_obj(d['TARGET'], bld.env) + t2.samba_includes_extended.extend(t.samba_includes_extended) + t2.samba_deps_extended.extend(t.samba_deps_extended) + t.samba_deps_extended = unique_list(t.samba_deps_extended) -@feature('cc', 'cshlib', 'cprogram') -@before('apply_lib_vars', 'apply_verif', 'apply_objdeps', 'apply_obj_vars', 'apply_incpaths', 'build_includes') -@after('default_cc') def build_dependencies(self): '''This builds the dependency list for a target. It runs after all the targets are declared The reason this is not just done in the SAMBA_*() rules is that we have no way of knowing - the full dependency list for a target until we have all of the targets declared. So what we do is - add a samba_deps attribute on the task generator when we declare it, then - this rule runs after all the task generators are declared and maps the samba_deps attribute - to a set of uselib, uselib_local and add_objects dependencies + the full dependency list for a target until we have all of the targets declared. ''' - if getattr(self, 'build_dependencies_done', False): - return - self.build_dependencies_done = True - - if getattr(self, 'samba_deps', None) is None: - return - - target_dict = LOCAL_CACHE(self.bld, 'TARGET_TYPE') - # we only should add extra library and object deps on libraries and binaries - type = target_dict[self.name] - if type != 'LIBRARY' and type != 'BINARY': + if not self.samba_type in ['LIBRARY', 'BINARY', 'PYTHON']: return - (uselib, uselib_local, add_objects) = expand_deplist(self) + # we need to link against: - if 'GLOBAL_DEPENDENCIES' in self.bld.env: - add_objects.extend(self.bld.env.GLOBAL_DEPENDENCIES) + # 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 - self.uselib = unique_list(uselib) - self.uselib_local = unique_list(uselib_local) - self.add_objects = unique_list(add_objects) + self.uselib = list(self.final_syslibs) + self.uselib_local = list(self.final_libs) + self.add_objects = list(self.final_objects) - debug('deps: dependency counts for %s: uselib=%u uselib_local=%u add_objects=%u' % ( - self.name, len(uselib), len(uselib_local), len(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) -@feature('cc', 'cshlib', 'cprogram') -@before('apply_lib_vars', 'apply_verif', 'apply_objdeps', 'apply_obj_vars', 'apply_incpaths', 'add_init_functions') -@after('build_dependencies') def build_includes(self): '''This builds the right set of includes for a target. - This is closely related to building the set of dependencies, and - calls into the same expand_dependencies() function to do the work. - One tricky part of this is that the includes= attribute for a target needs to use paths which are relative to that targets declaration directory (which we can get at via t.path). @@ -191,82 +100,68 @@ def build_includes(self): attribute ''' - if not getattr(self, 'build_dependencies_done', False): - build_dependencies(self) - if getattr(self, 'build_includes_done', False): - return - self.build_includes_done = True - if getattr(self, 'samba_includes', None) is None: return bld = self.bld - (uselib, uselib_local, add_objects) = expand_deplist(self) - - # get the list of all dependencies - all_deps = [] -# all_deps.extend(uselib) - all_deps.extend(uselib_local) - all_deps.extend(add_objects) - all_deps = unique_list(all_deps) + inc_deps = self.includes_objects includes = [] - # build a list of includes + # maybe add local includes if getattr(self, 'local_include', True) == True and getattr(self, 'local_include_first', True): includes.append('.') - includes.extend(TO_LIST(self.samba_includes)) + includes.extend(self.samba_includes_extended) if 'EXTRA_INCLUDES' in bld.env: includes.extend(bld.env['EXTRA_INCLUDES']) includes.append('#') - mypath = self.path.abspath(bld.env) + inc_set = set() + inc_abs = [] - for d in all_deps: + for d in inc_deps: t = bld.name_to_obj(d, bld.env) - bld.ASSERT(t is not None, "Unable to find dependency %s for %s" % (d, self.name)) - t.samba_used = True - samba_includes = getattr(t, 'samba_includes', None) - inclist = TO_LIST(samba_includes) + bld.ASSERT(t is not None, "Unable to find dependency %s for %s" % (d, self.sname)) + inclist = getattr(t, 'samba_includes_extended', []) if getattr(t, 'local_include', True) == True: inclist.append('.') if inclist == []: continue - tpath = t.path.abspath(bld.env) - relpath = os.path.relpath(tpath, mypath) + tpath = t.samba_abspath for inc in inclist: - includes.append(os.path.normpath(os.path.join(relpath, inc))) + npath = tpath + '/' + inc + if not npath in inc_set: + inc_abs.append(npath) + inc_set.add(npath) + + mypath = self.path.abspath(bld.env) + for inc in inc_abs: + relpath = os_path_relpath(inc, mypath) + includes.append(relpath) if getattr(self, 'local_include', True) == True and not getattr(self, 'local_include_first', True): includes.append('.') self.includes = unique_list(includes) - debug('deps: Target %s has includes=%s all_deps=%s' % (self.name, self.includes, all_deps)) + debug('deps: includes for target %s: includes=%s', + self.sname, self.includes) + -@feature('cc', 'cshlib', 'cprogram') -@before('apply_lib_vars', 'apply_verif', 'apply_objdeps', 'apply_obj_vars', 'apply_incpaths') -@after('build_includes') def add_init_functions(self): '''This builds the right set of init functions''' - if not getattr(self, 'build_includes_done', False): - build_includes(self) - if getattr(self, 'add_init_functions_done', False): - return - self.add_init_functions_done = True - bld = self.bld subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS') modules = [] - if self.name in subsystems: - modules.append(self.name) + if self.sname in subsystems: + modules.append(self.sname) m = getattr(self, 'samba_modules', None) if m is not None: @@ -279,112 +174,530 @@ def add_init_functions(self): if modules == []: return - cflags = getattr(self, 'ccflags', []) + sentinal = getattr(self, 'init_function_sentinal', 'NULL') + + cflags = getattr(self, 'samba_cflags', [])[:] for m in modules: - if not m in subsystems: - print "subsystems: %s" % subsystems bld.ASSERT(m in subsystems, - "No init_function defined for module '%s' in target '%s'" % (m, self.name)) - cflags.append('-DSTATIC_%s_MODULES="%s"' % (m, ','.join(subsystems[m]))) + "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)) self.ccflags = cflags -def check_orpaned_targets(bld): + +def check_duplicate_sources(bld, tgt_list): + '''see if we are compiling the same source file into multiple + subsystem targets for the same library or binary''' + + debug('deps: checking for duplicate sources') + + targets = LOCAL_CACHE(bld, 'TARGET_TYPE') + + for t in tgt_list: + if not targets[t.sname] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]: + continue + + 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)) + +def check_orpaned_targets(bld, tgt_list): '''check if any build targets are orphaned''' target_dict = LOCAL_CACHE(bld, 'TARGET_TYPE') - # make sure all the earlier functions have run - for t in bld.all_task_gen: - if not t.name in target_dict: + debug('deps: checking for orphaned targets') + + for t in tgt_list: + if getattr(t, 'samba_used', False) == True: continue - if not getattr(t, 'add_init_functions_done', False): - add_init_functions(t) + 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) + + +def show_final_deps(bld, tgt_list): + '''show the final dependencies for all targets''' + + targets = LOCAL_CACHE(bld, 'TARGET_TYPE') - for t in bld.all_task_gen: - if not t.name in target_dict: + for t in tgt_list: + if not targets[t.sname] in ['LIBRARY', 'BINARY', 'PYTHON']: continue - if getattr(t, 'samba_used', False) == True: + debug('deps: final dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s', + t.sname, t.uselib, t.uselib_local, t.add_objects) + + +def add_samba_attributes(bld, tgt_list): + '''ensure a target has a the required samba attributes''' + + targets = LOCAL_CACHE(bld, 'TARGET_TYPE') + + for t in tgt_list: + if t.name != '': + t.sname = t.name + else: + t.sname = t.target + t.samba_type = targets[t.sname] + t.samba_abspath = t.path.abspath(bld.env) + t.samba_deps_extended = t.samba_deps[:] + 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') + global_deps = bld.env.GLOBAL_DEPENDENCIES + + for t in tgt_list: + t.direct_objects = set() + t.direct_libs = set() + t.direct_syslibs = set() + deps = t.samba_deps_extended + deps.extend(global_deps) + for d in deps: + d = EXPAND_ALIAS(bld, d) + if not d in targets: + print "Unknown dependency %s in %s" % (d, t.sname) + raise + if targets[d] in [ 'EMPTY', 'DISABLED' ]: + continue + if targets[d] == 'SYSLIB': + t.direct_syslibs.add(d) + continue + t2 = bld.name_to_obj(d, bld.env) + if t2 is None: + print "no task %s type %s" % (d, targets[d]) + if t2.samba_type in [ 'LIBRARY', 'MODULE' ]: + t.direct_libs.add(d) + elif t2.samba_type in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]: + t.direct_objects.add(d) + debug('deps: built direct dependencies') + + + +def indirect_libs(bld, t, chain): + '''recursively calculate the indirect library dependencies for a target + + An indirect library is a library that results from a dependency on + a subsystem + ''' + + ret = getattr(t, 'indirect_libs', None) + if ret is not None: + return ret + + ret = set() + for obj in t.direct_objects: + if obj in chain: continue - type = target_dict[t.name] - if type != 'BINARY' and type != 'LIBRARY' and type != 'MODULE': - if re.search('^PIDL_', t.name) is None: - print "Target %s of type %s is unused by any other target" % (t.name, type) + chain.add(obj) + t2 = bld.name_to_obj(obj, bld.env) + r2 = indirect_libs(bld, t2, chain) + chain.remove(obj) + ret = ret.union(t2.direct_libs) + ret = ret.union(r2) + + for obj in t.indirect_objects: + if obj in chain: + continue + chain.add(obj) + t2 = bld.name_to_obj(obj, bld.env) + r2 = indirect_libs(bld, t2, chain) + chain.remove(obj) + ret = ret.union(t2.direct_libs) + ret = ret.union(r2) + t.indirect_libs = ret -def CHECK_ORPANED_TARGETS(bld): - bld.add_pre_fun(check_orpaned_targets) -Build.BuildContext.CHECK_ORPANED_TARGETS = CHECK_ORPANED_TARGETS + return ret -@feature('dfkj*') -def samba_post_process(self): - '''samba specific post processing of task''' - if getattr(self, 'meths', None) is None: - return - count = getattr(self, 'moved_to_end', 0) - if count < 10: - # there has got to be a better way!! - self.moved_to_end = count + 1 - self.meths.append('samba_post_process') - return +def indirect_syslibs(bld, t, chain): + '''recursively calculate the indirect system library dependencies for a target - samba_post = getattr(self, 'samba_post', None) - if samba_post is None: - return - (tgt, cmd) = samba_post - self.env.TARGET_DIRECTORY = self.path.abspath(self.env) - #print "cmd=%s tgt=%s" % (cmd, tgt) - cmd = Utils.subst_vars(cmd, self.env) - tgt = Utils.subst_vars(tgt, self.env) - if os.path.isfile(tgt): - debug('deps: post processing for %s: %s' % (self.name, cmd)) - ret = os.system(cmd) - self.bld.ASSERT(ret == 0, "Post processing for %s failed (%d): %s" % (self.name, ret, cmd)) - - -############################## -# handle the creation of links for libraries and binaries -# note that we use a relative symlink path to allow the whole tree -# to me moved/copied elsewhere without breaking the links -t = Task.simple_task_type('symlink_lib', 'ln -sf ../${SRC} ${LINK_TARGET}', color='PINK', - ext_in='.bin') -t.quiet = True - -@feature('symlink_lib') -@after('apply_link') -def symlink_lib(self): - tsk = self.create_task('symlink_lib', self.link_task.outputs[0]) - - # calculat the link target and put it in the environment - soext="" - vnum = getattr(self, 'vnum', None) - if vnum is not None: - soext = '.' + vnum.split('.')[0] - - libname = self.target - tsk.env.LINK_TARGET = '%s/lib%s.so%s' % (LIB_PATH, libname, soext) - debug('task_gen: LINK_TARGET for %s is %s', self.name, tsk.env.LINK_TARGET) - - -# for binaries we need to copy the executable to avoid the rpath changing -# in the local bin/ directory on install -t = Task.simple_task_type('copy_bin', 'rm -f ${BIN_TARGET} && cp ${SRC} ${BIN_TARGET}', color='PINK', - ext_in='.bin', shell=True) -t.quiet = True - -@feature('copy_bin') -@after('apply_link') -def copy_bin(self): - if Options.is_install: - # we don't want to copy the install binary, as - # that has the install rpath, not the build rpath - # The rpath of the binaries in bin/default/foo/blah is different - # during the install phase, as distros insist on not using rpath in installed binaries + 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): + '''recursively calculate the indirect object dependencies for a target + + indirect objects are the set of objects from expanding the + subsystem dependencies + ''' + + ret = getattr(t, 'indirect_objects', None) + if ret is not None: return ret + + ret = set() + for lib in t.direct_objects: + if lib in chain: + continue + chain.add(lib) + t2 = bld.name_to_obj(lib, bld.env) + r2 = indirect_objects(bld, t2, chain) + chain.remove(lib) + ret = ret.union(t2.direct_objects) + ret = ret.union(r2) + + t.indirect_objects = ret + return ret + + +def expanded_targets(bld, t, chain): + '''recursively calculate the expanded targets for a target + + expanded objects are the set of objects, libraries and syslibs + from expanding the subsystem dependencies, library dependencies + and syslib dependencies + ''' + + ret = getattr(t, 'expanded_targets', 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() + + 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) + ret = ret.union(r2) + + if t.sname in ret: + ret.remove(t.sname) + + t.expanded_targets = 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): + '''recursively calculate the includes object dependencies for a target + + includes dependencies come from either library or object dependencies + ''' + ret = getattr(t, 'includes_objects', None) + if ret is not None: + return ret + + ret = t.direct_objects.copy() + ret = ret.union(t.direct_libs) + + for obj in t.direct_objects: + if obj in chain: + continue + chain.add(obj) + t2 = bld.name_to_obj(obj, bld.env) + r2 = includes_objects(bld, t2, chain) + chain.remove(obj) + ret = ret.union(t2.direct_objects) + ret = ret.union(r2) + + for lib in t.direct_libs: + if lib in chain: + continue + chain.add(lib) + t2 = bld.name_to_obj(lib, bld.env) + r2 = includes_objects(bld, t2, chain) + chain.remove(lib) + ret = ret.union(t2.direct_objects) + ret = ret.union(r2) + + t.includes_objects = ret + 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 re_expand2(bld, tgt_list): + 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()) + for t in tgt_list: + expanded_targets2(bld, t, set()) + + +def calculate_final_deps(bld, tgt_list): + '''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) + + for t in tgt_list: + # don't depend on ourselves + if t.sname in t.final_libs: + t.final_libs.remove(t.sname) + 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']: + for l in t.final_libs.copy(): + t2 = bld.name_to_obj(l, bld.env) + if t.sname in t2.final_libs: + debug('deps: removing library loop %s<->%s', t.sname, l) + 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 + debug('deps: removed duplicate dependencies') + + +###################################################################### +# this provides a way to save our dependency calculations between runs +savedeps_version = 1 +savedeps_inputs = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags'] +savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags'] +savedeps_caches = ['GLOBAL_DEPENDENCIES', 'TARGET_ALIAS', 'TARGET_TYPE', 'INIT_FUNCTIONS'] + +def save_samba_deps(bld, tgt_list): + '''save the dependency calculations between builds, to make + further builds faster''' + denv = Environment.Environment() + + denv.version = savedeps_version + denv.savedeps_inputs = savedeps_inputs + denv.savedeps_outputs = savedeps_outputs + denv.input = {} + denv.output = {} + denv.caches = {} + + for c in savedeps_caches: + denv.caches[c] = LOCAL_CACHE(bld, c) + + for t in tgt_list: + # save all the input attributes for each target + tdeps = {} + for attr in savedeps_inputs: + v = getattr(t, attr, None) + if v is not None: + tdeps[attr] = v + if tdeps != {}: + denv.input[t.sname] = tdeps + + # save all the output attributes for each target + tdeps = {} + for attr in savedeps_outputs: + v = getattr(t, attr, None) + if v is not None: + tdeps[attr] = v + if tdeps != {}: + denv.output[t.sname] = tdeps + + depsfile = os.path.join(bld.bdir, "sambadeps") + 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") + denv = Environment.Environment() + try: + debug('deps: checking saved dependencies') + denv.load(depsfile) + if (denv.version != savedeps_version or + denv.savedeps_inputs != savedeps_inputs or + denv.savedeps_outputs != savedeps_outputs): + return False + except: + 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): + return False + + # check inputs are the same + for t in tgt_list: + tdeps = {} + for attr in savedeps_inputs: + v = getattr(t, attr, None) + if v is not None: + tdeps[attr] = v + if t.sname in denv.input: + olddeps = denv.input[t.sname] + else: + olddeps = {} + if tdeps != olddeps: + #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps) + return False + + # put outputs in place + for t in tgt_list: + if not t.sname in denv.output: continue + tdeps = denv.output[t.sname] + for a in tdeps: + setattr(t, a, tdeps[a]) + + debug('deps: loaded saved dependencies') + return True + + +def check_project_rules(bld): + '''check the project rules - ensuring the targets are sane''' + + targets = LOCAL_CACHE(bld, 'TARGET_TYPE') + + # build a list of task generators we are interested in + tgt_list = [] + for tgt in targets: + type = targets[tgt] + if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON']: + continue + t = bld.name_to_obj(tgt, bld.env) + tgt_list.append(t) + + add_samba_attributes(bld, tgt_list) + + if load_samba_deps(bld, tgt_list): return - tsk = self.create_task('copy_bin', self.link_task.outputs[0]) - tsk.env.BIN_TARGET = self.target - debug('task_gen: BIN_TARGET for %s is %s', self.name, tsk.env.BIN_TARGET) + 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) + + # run the various attribute generators + for f in [ build_dependencies, build_includes, add_init_functions ]: + debug('deps: project rules checking %s', f) + for t in tgt_list: f(t) + + debug('deps: project rules stage1 completed') + + #check_orpaned_targets(bld, tgt_list) + #check_duplicate_sources(bld, tgt_list) + show_final_deps(bld, tgt_list) + + debug('deps: project rules checking completed - %u targets checked', + len(tgt_list)) + + save_samba_deps(bld, tgt_list) + + +def CHECK_PROJECT_RULES(bld): + '''enable checking of project targets for sanity''' + if bld.env.added_project_rules: + return + bld.env.added_project_rules = True + bld.add_pre_fun(check_project_rules) +Build.BuildContext.CHECK_PROJECT_RULES = CHECK_PROJECT_RULES |