diff options
Diffstat (limited to 'src/engine/SCons/Tool/__init__.py')
-rw-r--r-- | src/engine/SCons/Tool/__init__.py | 601 |
1 files changed, 360 insertions, 241 deletions
diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py index 9265b81..271f214 100644 --- a/src/engine/SCons/Tool/__init__.py +++ b/src/engine/SCons/Tool/__init__.py @@ -14,7 +14,7 @@ tool definition. """ # -# Copyright (c) 2001 - 2017 The SCons Foundation +# Copyright (c) 2001 - 2019 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -35,16 +35,13 @@ tool definition. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "src/engine/SCons/Tool/__init__.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" +__revision__ = "src/engine/SCons/Tool/__init__.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan" -import imp -import importlib import sys import re import os import shutil - import SCons.Builder import SCons.Errors import SCons.Node.FS @@ -54,9 +51,14 @@ import SCons.Scanner.D import SCons.Scanner.LaTeX import SCons.Scanner.Prog import SCons.Scanner.SWIG -import collections +try: + # Python 3 + from collections.abc import Callable +except ImportError: + # Python 2.7 + from collections import Callable -DefaultToolpath=[] +DefaultToolpath = [] CScanner = SCons.Scanner.C.CScanner() DScanner = SCons.Scanner.D.DScanner() @@ -97,20 +99,22 @@ for suffix in LaTeXSuffixes: SourceFileScanner.add_scanner(suffix, LaTeXScanner) SourceFileScanner.add_scanner(suffix, PDFLaTeXScanner) - # Tool aliases are needed for those tools whos module names also # occur in the python standard library. This causes module shadowing and # can break using python library functions under python3 TOOL_ALIASES = { - 'gettext':'gettext_tool', + 'gettext': 'gettext_tool', 'clang++': 'clangxx', } + class Tool(object): - def __init__(self, name, toolpath=[], **kw): + def __init__(self, name, toolpath=None, **kw): + if toolpath is None: + toolpath = [] # Rename if there's a TOOL_ALIAS for this tool - self.name = TOOL_ALIASES.get(name,name) + self.name = TOOL_ALIASES.get(name, name) self.toolpath = toolpath + DefaultToolpath # remember these so we can merge them into the call self.init_kw = kw @@ -122,6 +126,8 @@ class Tool(object): self.options = module.options def _load_dotted_module_py2(self, short_name, full_name, searchpaths=None): + import imp + splitname = short_name.split('.') index = 0 srchpths = searchpaths @@ -136,7 +142,7 @@ class Tool(object): sys.path = self.toolpath + sys.path # sys.stderr.write("Tool:%s\nPATH:%s\n"%(self.name,sys.path)) - if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] in (0,1,2,3,4)): + if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] in (0, 1, 2, 3, 4)): # Py 2 code try: try: @@ -149,8 +155,8 @@ class Tool(object): file.close() except ImportError as e: splitname = self.name.split('.') - if str(e)!="No module named %s"%splitname[0]: - raise SCons.Errors.EnvironmentError(e) + if str(e) != "No module named %s" % splitname[0]: + raise SCons.Errors.SConsEnvironmentError(e) try: import zipimport except ImportError: @@ -184,46 +190,48 @@ class Tool(object): add_to_scons_tools_namespace = False for path in self.toolpath: sepname = self.name.replace('.', os.path.sep) - file_path = os.path.join(path, "%s.py"%sepname) + file_path = os.path.join(path, "%s.py" % sepname) file_package = os.path.join(path, sepname) - if debug: sys.stderr.write("Trying:%s %s\n"%(file_path, file_package)) + if debug: sys.stderr.write("Trying:%s %s\n" % (file_path, file_package)) if os.path.isfile(file_path): spec = importlib.util.spec_from_file_location(self.name, file_path) - if debug: print("file_Path:%s FOUND"%file_path) + if debug: print("file_Path:%s FOUND" % file_path) break elif os.path.isdir(file_package): file_package = os.path.join(file_package, '__init__.py') spec = importlib.util.spec_from_file_location(self.name, file_package) - if debug: print("PACKAGE:%s Found"%file_package) + if debug: print("PACKAGE:%s Found" % file_package) break else: continue if spec is None: - if debug: sys.stderr.write("NO SPEC :%s\n"%self.name) - spec = importlib.util.find_spec("."+self.name, package='SCons.Tool') + if debug: sys.stderr.write("NO SPEC :%s\n" % self.name) + spec = importlib.util.find_spec("." + self.name, package='SCons.Tool') if spec: - found_name = 'SCons.Tool.'+self.name + found_name = 'SCons.Tool.' + self.name add_to_scons_tools_namespace = True - if debug: sys.stderr.write("Spec Found? .%s :%s\n"%(self.name, spec)) + if debug: sys.stderr.write("Spec Found? .%s :%s\n" % (self.name, spec)) if spec is None: - error_string = "No module named %s"%self.name - raise SCons.Errors.EnvironmentError(error_string) + error_string = "No module named %s" % self.name + raise SCons.Errors.SConsEnvironmentError(error_string) module = importlib.util.module_from_spec(spec) if module is None: - if debug: print("MODULE IS NONE:%s"%self.name) - error_string = "No module named %s"%self.name - raise SCons.Errors.EnvironmentError(error_string) + if debug: print("MODULE IS NONE:%s" % self.name) + error_string = "No module named %s" % self.name + raise SCons.Errors.SConsEnvironmentError(error_string) # Don't reload a tool we already loaded. - sys_modules_value = sys.modules.get(found_name,False) + sys_modules_value = sys.modules.get(found_name, False) + + found_module = None if sys_modules_value and sys_modules_value.__file__ == spec.origin: - return sys.modules[found_name] + found_module = sys.modules[found_name] else: # Not sure what to do in the case that there already # exists sys.modules[self.name] but the source file is @@ -235,8 +243,11 @@ class Tool(object): # If we found it in SCons.Tool, then add it to the module setattr(SCons.Tool, self.name, module) - return module + found_module = module + if found_module is not None: + sys.path = oldpythonpath + return found_module sys.path = oldpythonpath @@ -253,20 +264,20 @@ class Tool(object): file.close() return module except ImportError as e: - if str(e)!="No module named %s"%self.name: - raise SCons.Errors.EnvironmentError(e) + if str(e) != "No module named %s" % self.name: + raise SCons.Errors.SConsEnvironmentError(e) try: import zipimport - importer = zipimport.zipimporter( sys.modules['SCons.Tool'].__path__[0] ) + importer = zipimport.zipimporter(sys.modules['SCons.Tool'].__path__[0]) module = importer.load_module(full_name) setattr(SCons.Tool, self.name, module) return module except ImportError as e: m = "No tool named '%s': %s" % (self.name, e) - raise SCons.Errors.EnvironmentError(m) + raise SCons.Errors.SConsEnvironmentError(m) except ImportError as e: m = "No tool named '%s': %s" % (self.name, e) - raise SCons.Errors.EnvironmentError(m) + raise SCons.Errors.SConsEnvironmentError(m) def __call__(self, env, *args, **kw): if self.init_kw is not None: @@ -278,13 +289,13 @@ class Tool(object): kw.update(call_kw) else: kw = self.init_kw - env.Append(TOOLS = [ self.name ]) + env.Append(TOOLS=[self.name]) if hasattr(self, 'options'): import SCons.Variables if 'options' not in env: from SCons.Script import ARGUMENTS - env['options']=SCons.Variables.Variables(args=ARGUMENTS) - opts=env['options'] + env['options'] = SCons.Variables.Variables(args=ARGUMENTS) + opts = env['options'] self.options(opts) opts.Update(env) @@ -294,6 +305,7 @@ class Tool(object): def __str__(self): return self.name + ########################################################################## # Create common executable program / library / object builders @@ -308,13 +320,13 @@ def createProgBuilder(env): program = env['BUILDERS']['Program'] except KeyError: import SCons.Defaults - program = SCons.Builder.Builder(action = SCons.Defaults.LinkAction, - emitter = '$PROGEMITTER', - prefix = '$PROGPREFIX', - suffix = '$PROGSUFFIX', - src_suffix = '$OBJSUFFIX', - src_builder = 'Object', - target_scanner = ProgramScanner) + program = SCons.Builder.Builder(action=SCons.Defaults.LinkAction, + emitter='$PROGEMITTER', + prefix='$PROGPREFIX', + suffix='$PROGSUFFIX', + src_suffix='$OBJSUFFIX', + src_builder='Object', + target_scanner=ProgramScanner) env['BUILDERS']['Program'] = program return program @@ -330,23 +342,24 @@ def createStaticLibBuilder(env): try: static_lib = env['BUILDERS']['StaticLibrary'] except KeyError: - action_list = [ SCons.Action.Action("$ARCOM", "$ARCOMSTR") ] - if env.get('RANLIB',False) or env.Detect('ranlib'): + action_list = [SCons.Action.Action("$ARCOM", "$ARCOMSTR")] + if env.get('RANLIB', False) or env.Detect('ranlib'): ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR") action_list.append(ranlib_action) - static_lib = SCons.Builder.Builder(action = action_list, - emitter = '$LIBEMITTER', - prefix = '$LIBPREFIX', - suffix = '$LIBSUFFIX', - src_suffix = '$OBJSUFFIX', - src_builder = 'StaticObject') + static_lib = SCons.Builder.Builder(action=action_list, + emitter='$LIBEMITTER', + prefix='$LIBPREFIX', + suffix='$LIBSUFFIX', + src_suffix='$OBJSUFFIX', + src_builder='StaticObject') env['BUILDERS']['StaticLibrary'] = static_lib env['BUILDERS']['Library'] = static_lib return static_lib -def _call_linker_cb(env, callback, args, result = None): + +def _call_linker_cb(env, callback, args, result=None): """Returns the result of env['LINKCALLBACKS'][callback](*args) if env['LINKCALLBACKS'] is a dictionary and env['LINKCALLBACKS'][callback] is callable. If these conditions are not met, return the value provided as @@ -370,136 +383,163 @@ def _call_linker_cb(env, callback, args, result = None): if Verbose: print('_call_linker_cb: env["LINKCALLBACKS"][%r] found' % callback) print('_call_linker_cb: env["LINKCALLBACKS"][%r]=%r' % (callback, cbfun)) - if(isinstance(cbfun, collections.Callable)): + if isinstance(cbfun, Callable): if Verbose: print('_call_linker_cb: env["LINKCALLBACKS"][%r] is callable' % callback) result = cbfun(env, *args) return result + def _call_env_subst(env, string, *args, **kw): kw2 = {} for k in ('raw', 'target', 'source', 'conv', 'executor'): - try: kw2[k] = kw[k] - except KeyError: pass + try: + kw2[k] = kw[k] + except KeyError: + pass return env.subst(string, *args, **kw2) + class _ShLibInfoSupport(object): - def get_libtype(self): + @property + def libtype(self): return 'ShLib' + def get_lib_prefix(self, env, *args, **kw): - return _call_env_subst(env,'$SHLIBPREFIX', *args, **kw) + return _call_env_subst(env, '$SHLIBPREFIX', *args, **kw) + def get_lib_suffix(self, env, *args, **kw): - return _call_env_subst(env,'$SHLIBSUFFIX', *args, **kw) + return _call_env_subst(env, '$SHLIBSUFFIX', *args, **kw) + def get_lib_version(self, env, *args, **kw): - return _call_env_subst(env,'$SHLIBVERSION', *args, **kw) + return _call_env_subst(env, '$SHLIBVERSION', *args, **kw) + def get_lib_noversionsymlinks(self, env, *args, **kw): - return _call_env_subst(env,'$SHLIBNOVERSIONSYMLINKS', *args, **kw) + return _call_env_subst(env, '$SHLIBNOVERSIONSYMLINKS', *args, **kw) + class _LdModInfoSupport(object): - def get_libtype(self): + @property + def libtype(self): return 'LdMod' + def get_lib_prefix(self, env, *args, **kw): - return _call_env_subst(env,'$LDMODULEPREFIX', *args, **kw) + return _call_env_subst(env, '$LDMODULEPREFIX', *args, **kw) + def get_lib_suffix(self, env, *args, **kw): - return _call_env_subst(env,'$LDMODULESUFFIX', *args, **kw) + return _call_env_subst(env, '$LDMODULESUFFIX', *args, **kw) + def get_lib_version(self, env, *args, **kw): - return _call_env_subst(env,'$LDMODULEVERSION', *args, **kw) + return _call_env_subst(env, '$LDMODULEVERSION', *args, **kw) + def get_lib_noversionsymlinks(self, env, *args, **kw): - return _call_env_subst(env,'$LDMODULENOVERSIONSYMLINKS', *args, **kw) + return _call_env_subst(env, '$LDMODULENOVERSIONSYMLINKS', *args, **kw) + class _ImpLibInfoSupport(object): - def get_libtype(self): + @property + def libtype(self): return 'ImpLib' + def get_lib_prefix(self, env, *args, **kw): - return _call_env_subst(env,'$IMPLIBPREFIX', *args, **kw) + return _call_env_subst(env, '$IMPLIBPREFIX', *args, **kw) + def get_lib_suffix(self, env, *args, **kw): - return _call_env_subst(env,'$IMPLIBSUFFIX', *args, **kw) + return _call_env_subst(env, '$IMPLIBSUFFIX', *args, **kw) + def get_lib_version(self, env, *args, **kw): - version = _call_env_subst(env,'$IMPLIBVERSION', *args, **kw) + version = _call_env_subst(env, '$IMPLIBVERSION', *args, **kw) if not version: - try: lt = kw['implib_libtype'] - except KeyError: pass + try: + lt = kw['implib_libtype'] + except KeyError: + pass else: if lt == 'ShLib': - version = _call_env_subst(env,'$SHLIBVERSION', *args, **kw) + version = _call_env_subst(env, '$SHLIBVERSION', *args, **kw) elif lt == 'LdMod': - version = _call_env_subst(env,'$LDMODULEVERSION', *args, **kw) + version = _call_env_subst(env, '$LDMODULEVERSION', *args, **kw) return version + def get_lib_noversionsymlinks(self, env, *args, **kw): disable = None - try: env['IMPLIBNOVERSIONSYMLINKS'] + try: + env['IMPLIBNOVERSIONSYMLINKS'] except KeyError: - try: lt = kw['implib_libtype'] - except KeyError: pass + try: + lt = kw['implib_libtype'] + except KeyError: + pass else: if lt == 'ShLib': - disable = _call_env_subst(env,'$SHLIBNOVERSIONSYMLINKS', *args, **kw) + disable = _call_env_subst(env, '$SHLIBNOVERSIONSYMLINKS', *args, **kw) elif lt == 'LdMod': - disable = _call_env_subst(env,'$LDMODULENOVERSIONSYMLINKS', *args, **kw) + disable = _call_env_subst(env, '$LDMODULENOVERSIONSYMLINKS', *args, **kw) else: - disable = _call_env_subst(env,'$IMPLIBNOVERSIONSYMLINKS', *args, **kw) + disable = _call_env_subst(env, '$IMPLIBNOVERSIONSYMLINKS', *args, **kw) return disable + class _LibInfoGeneratorBase(object): """Generator base class for library-related info such as suffixes for versioned libraries, symlink maps, sonames etc. It handles commonities of SharedLibrary and LoadableModule """ - _support_classes = { 'ShLib' : _ShLibInfoSupport, - 'LdMod' : _LdModInfoSupport, - 'ImpLib' : _ImpLibInfoSupport } + _support_classes = {'ShLib': _ShLibInfoSupport, + 'LdMod': _LdModInfoSupport, + 'ImpLib': _ImpLibInfoSupport} + def __init__(self, libtype, infoname): - self.set_libtype(libtype) - self.set_infoname(infoname) + self.libtype = libtype + self.infoname = infoname + + @property + def libtype(self): + return self._support.libtype - def set_libtype(self, libtype): + @libtype.setter + def libtype(self, libtype): try: support_class = self._support_classes[libtype] except KeyError: raise ValueError('unsupported libtype %r' % libtype) self._support = support_class() - def get_libtype(self): - return self._support.get_libtype() - - def set_infoname(self, infoname): - self.infoname = infoname - - def get_infoname(self): - return self.infoname - def get_lib_prefix(self, env, *args, **kw): - return self._support.get_lib_prefix(env,*args,**kw) + return self._support.get_lib_prefix(env, *args, **kw) def get_lib_suffix(self, env, *args, **kw): - return self._support.get_lib_suffix(env,*args,**kw) + return self._support.get_lib_suffix(env, *args, **kw) def get_lib_version(self, env, *args, **kw): - return self._support.get_lib_version(env,*args,**kw) + return self._support.get_lib_version(env, *args, **kw) def get_lib_noversionsymlinks(self, env, *args, **kw): - return self._support.get_lib_noversionsymlinks(env,*args,**kw) + return self._support.get_lib_noversionsymlinks(env, *args, **kw) # Returns name of generator linker callback that shall be used to generate # our info for a versioned library. For example, if our libtype is 'ShLib' # and infoname is 'Prefix', it would return 'VersionedShLibPrefix'. def get_versioned_lib_info_generator(self, **kw): - try: libtype = kw['generator_libtype'] - except KeyError: libtype = self.get_libtype() - infoname = self.get_infoname() - return 'Versioned%s%s' % (libtype, infoname) + try: + libtype = kw['generator_libtype'] + except KeyError: + libtype = self.libtype + return 'Versioned%s%s' % (libtype, self.infoname) - def generate_versioned_lib_info(self, env, args, result = None, **kw): + def generate_versioned_lib_info(self, env, args, result=None, **kw): callback = self.get_versioned_lib_info_generator(**kw) return _call_linker_cb(env, callback, args, result) + class _LibPrefixGenerator(_LibInfoGeneratorBase): """Library prefix generator, used as target_prefix in SharedLibrary and LoadableModule builders""" + def __init__(self, libtype): super(_LibPrefixGenerator, self).__init__(libtype, 'Prefix') - def __call__(self, env, sources = None, **kw): + def __call__(self, env, sources=None, **kw): Verbose = False if sources and 'source' not in kw: @@ -508,7 +548,7 @@ class _LibPrefixGenerator(_LibInfoGeneratorBase): else: kw2 = kw - prefix = self.get_lib_prefix(env,**kw2) + prefix = self.get_lib_prefix(env, **kw2) if Verbose: print("_LibPrefixGenerator: input prefix=%r" % prefix) @@ -523,17 +563,20 @@ class _LibPrefixGenerator(_LibInfoGeneratorBase): print("_LibPrefixGenerator: return prefix=%r" % prefix) return prefix -ShLibPrefixGenerator = _LibPrefixGenerator('ShLib') -LdModPrefixGenerator = _LibPrefixGenerator('LdMod') + +ShLibPrefixGenerator = _LibPrefixGenerator('ShLib') +LdModPrefixGenerator = _LibPrefixGenerator('LdMod') ImpLibPrefixGenerator = _LibPrefixGenerator('ImpLib') + class _LibSuffixGenerator(_LibInfoGeneratorBase): """Library suffix generator, used as target_suffix in SharedLibrary and LoadableModule builders""" + def __init__(self, libtype): super(_LibSuffixGenerator, self).__init__(libtype, 'Suffix') - def __call__(self, env, sources = None, **kw): + def __call__(self, env, sources=None, **kw): Verbose = False if sources and 'source' not in kw: @@ -557,13 +600,16 @@ class _LibSuffixGenerator(_LibInfoGeneratorBase): print("_LibSuffixGenerator: return suffix=%r" % suffix) return suffix -ShLibSuffixGenerator = _LibSuffixGenerator('ShLib') -LdModSuffixGenerator = _LibSuffixGenerator('LdMod') + +ShLibSuffixGenerator = _LibSuffixGenerator('ShLib') +LdModSuffixGenerator = _LibSuffixGenerator('LdMod') ImpLibSuffixGenerator = _LibSuffixGenerator('ImpLib') + class _LibSymlinkGenerator(_LibInfoGeneratorBase): """Library symlink map generator. It generates a list of symlinks that should be created by SharedLibrary or LoadableModule builders""" + def __init__(self, libtype): super(_LibSymlinkGenerator, self).__init__(libtype, 'Symlinks') @@ -588,18 +634,20 @@ class _LibSymlinkGenerator(_LibInfoGeneratorBase): print('_LibSymlinkGenerator: disable=%r' % disable) if version and not disable: - prefix = self.get_lib_prefix(env,**kw2) - suffix = self.get_lib_suffix(env,**kw2) + prefix = self.get_lib_prefix(env, **kw2) + suffix = self.get_lib_suffix(env, **kw2) symlinks = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2) if Verbose: print('_LibSymlinkGenerator: return symlinks=%r' % StringizeLibSymlinks(symlinks)) return symlinks -ShLibSymlinkGenerator = _LibSymlinkGenerator('ShLib') -LdModSymlinkGenerator = _LibSymlinkGenerator('LdMod') + +ShLibSymlinkGenerator = _LibSymlinkGenerator('ShLib') +LdModSymlinkGenerator = _LibSymlinkGenerator('LdMod') ImpLibSymlinkGenerator = _LibSymlinkGenerator('ImpLib') + class _LibNameGenerator(_LibInfoGeneratorBase): """Generates "unmangled" library name from a library file node. @@ -614,6 +662,7 @@ class _LibNameGenerator(_LibInfoGeneratorBase): the _LibNameGenerator shall return "libfoo.so". Other link tools may implement it's own way of library name unmangling. """ + def __init__(self, libtype): super(_LibNameGenerator, self).__init__(libtype, 'Name') @@ -636,8 +685,8 @@ class _LibNameGenerator(_LibInfoGeneratorBase): name = None if version: - prefix = self.get_lib_prefix(env,**kw2) - suffix = self.get_lib_suffix(env,**kw2) + prefix = self.get_lib_prefix(env, **kw2) + suffix = self.get_lib_suffix(env, **kw2) name = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2) if not name: @@ -648,13 +697,16 @@ class _LibNameGenerator(_LibInfoGeneratorBase): return name -ShLibNameGenerator = _LibNameGenerator('ShLib') -LdModNameGenerator = _LibNameGenerator('LdMod') + +ShLibNameGenerator = _LibNameGenerator('ShLib') +LdModNameGenerator = _LibNameGenerator('LdMod') ImpLibNameGenerator = _LibNameGenerator('ImpLib') + class _LibSonameGenerator(_LibInfoGeneratorBase): """Library soname generator. Returns library soname (e.g. libfoo.so.0) for a given node (e.g. /foo/bar/libfoo.so.0.1.2)""" + def __init__(self, libtype): super(_LibSonameGenerator, self).__init__(libtype, 'Soname') @@ -673,17 +725,17 @@ class _LibSonameGenerator(_LibInfoGeneratorBase): soname = _call_env_subst(env, '$SONAME', **kw2) if not soname: - version = self.get_lib_version(env,**kw2) + version = self.get_lib_version(env, **kw2) if Verbose: print("_LibSonameGenerator: version=%r" % version) if version: - prefix = self.get_lib_prefix(env,**kw2) - suffix = self.get_lib_suffix(env,**kw2) + prefix = self.get_lib_prefix(env, **kw2) + suffix = self.get_lib_suffix(env, **kw2) soname = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2) if not soname: # fallback to library name (as returned by appropriate _LibNameGenerator) - soname = _LibNameGenerator(self.get_libtype())(env, libnode) + soname = _LibNameGenerator(self.libtype)(env, libnode) if Verbose: print("_LibSonameGenerator: FALLBACK: soname=%r" % soname) @@ -692,40 +744,44 @@ class _LibSonameGenerator(_LibInfoGeneratorBase): return soname -ShLibSonameGenerator = _LibSonameGenerator('ShLib') -LdModSonameGenerator = _LibSonameGenerator('LdMod') + +ShLibSonameGenerator = _LibSonameGenerator('ShLib') +LdModSonameGenerator = _LibSonameGenerator('LdMod') + def StringizeLibSymlinks(symlinks): """Converts list with pairs of nodes to list with pairs of node paths (strings). Used mainly for debugging.""" if SCons.Util.is_List(symlinks): try: - return [ (k.get_path(), v.get_path()) for k,v in symlinks ] + return [(k.get_path(), v.get_path()) for k, v in symlinks] except (TypeError, ValueError): return symlinks else: return symlinks + def EmitLibSymlinks(env, symlinks, libnode, **kw): """Used by emitters to handle (shared/versioned) library symlinks""" Verbose = False # nodes involved in process... all symlinks + library - nodes = list(set([ x for x,y in symlinks ] + [libnode])) + nodes = list(set([x for x, y in symlinks] + [libnode])) clean_targets = kw.get('clean_targets', []) if not SCons.Util.is_List(clean_targets): - clean_targets = [ clean_targets ] + clean_targets = [clean_targets] for link, linktgt in symlinks: env.SideEffect(link, linktgt) - if(Verbose): + if (Verbose): print("EmitLibSymlinks: SideEffect(%r,%r)" % (link.get_path(), linktgt.get_path())) clean_list = [x for x in nodes if x != linktgt] env.Clean(list(set([linktgt] + clean_targets)), clean_list) - if(Verbose): + if (Verbose): print("EmitLibSymlinks: Clean(%r,%r)" % (linktgt.get_path(), [x.get_path() for x in clean_list])) + def CreateLibSymlinks(env, symlinks): """Physically creates symlinks. The symlinks argument must be a list in form [ (link, linktarget), ... ], where link and linktarget are SCons @@ -736,38 +792,40 @@ def CreateLibSymlinks(env, symlinks): for link, linktgt in symlinks: linktgt = link.get_dir().rel_path(linktgt) link = link.get_path() - if(Verbose): + if (Verbose): print("CreateLibSymlinks: preparing to add symlink %r -> %r" % (link, linktgt)) # Delete the (previously created) symlink if exists. Let only symlinks # to be deleted to prevent accidental deletion of source files... if env.fs.islink(link): env.fs.unlink(link) - if(Verbose): + if (Verbose): print("CreateLibSymlinks: removed old symlink %r" % link) # If a file or directory exists with the same name as link, an OSError # will be thrown, which should be enough, I think. env.fs.symlink(linktgt, link) - if(Verbose): + if (Verbose): print("CreateLibSymlinks: add symlink %r -> %r" % (link, linktgt)) return 0 + def LibSymlinksActionFunction(target, source, env): for tgt in target: - symlinks = getattr(getattr(tgt,'attributes', None), 'shliblinks', None) + symlinks = getattr(getattr(tgt, 'attributes', None), 'shliblinks', None) if symlinks: CreateLibSymlinks(env, symlinks) return 0 + def LibSymlinksStrFun(target, source, env, *args): cmd = None for tgt in target: - symlinks = getattr(getattr(tgt,'attributes', None), 'shliblinks', None) + symlinks = getattr(getattr(tgt, 'attributes', None), 'shliblinks', None) if symlinks: if cmd is None: cmd = "" if cmd: cmd += "\n" cmd += "Create symlinks for: %r" % tgt.get_path() try: - linkstr = ', '.join([ "%r->%r" %(k,v) for k,v in StringizeLibSymlinks(symlinks)]) + linkstr = ', '.join(["%r->%r" % (k, v) for k, v in StringizeLibSymlinks(symlinks)]) except (KeyError, ValueError): pass else: @@ -789,20 +847,21 @@ def createSharedLibBuilder(env): shared_lib = env['BUILDERS']['SharedLibrary'] except KeyError: import SCons.Defaults - action_list = [ SCons.Defaults.SharedCheck, - SCons.Defaults.ShLinkAction, - LibSymlinksAction ] - shared_lib = SCons.Builder.Builder(action = action_list, - emitter = "$SHLIBEMITTER", - prefix = ShLibPrefixGenerator, - suffix = ShLibSuffixGenerator, - target_scanner = ProgramScanner, - src_suffix = '$SHOBJSUFFIX', - src_builder = 'SharedObject') + action_list = [SCons.Defaults.SharedCheck, + SCons.Defaults.ShLinkAction, + LibSymlinksAction] + shared_lib = SCons.Builder.Builder(action=action_list, + emitter="$SHLIBEMITTER", + prefix=ShLibPrefixGenerator, + suffix=ShLibSuffixGenerator, + target_scanner=ProgramScanner, + src_suffix='$SHOBJSUFFIX', + src_builder='SharedObject') env['BUILDERS']['SharedLibrary'] = shared_lib return shared_lib + def createLoadableModuleBuilder(env): """This is a utility function that creates the LoadableModule Builder in an Environment if it is not there already. @@ -814,20 +873,21 @@ def createLoadableModuleBuilder(env): ld_module = env['BUILDERS']['LoadableModule'] except KeyError: import SCons.Defaults - action_list = [ SCons.Defaults.SharedCheck, - SCons.Defaults.LdModuleLinkAction, - LibSymlinksAction ] - ld_module = SCons.Builder.Builder(action = action_list, - emitter = "$LDMODULEEMITTER", - prefix = LdModPrefixGenerator, - suffix = LdModSuffixGenerator, - target_scanner = ProgramScanner, - src_suffix = '$SHOBJSUFFIX', - src_builder = 'SharedObject') + action_list = [SCons.Defaults.SharedCheck, + SCons.Defaults.LdModuleLinkAction, + LibSymlinksAction] + ld_module = SCons.Builder.Builder(action=action_list, + emitter="$LDMODULEEMITTER", + prefix=LdModPrefixGenerator, + suffix=LdModSuffixGenerator, + target_scanner=ProgramScanner, + src_suffix='$SHOBJSUFFIX', + src_builder='SharedObject') env['BUILDERS']['LoadableModule'] = ld_module return ld_module + def createObjBuilders(env): """This is a utility function that creates the StaticObject and SharedObject Builders in an Environment if they @@ -841,34 +901,34 @@ def createObjBuilders(env): The return is a 2-tuple of (StaticObject, SharedObject) """ - try: static_obj = env['BUILDERS']['StaticObject'] except KeyError: - static_obj = SCons.Builder.Builder(action = {}, - emitter = {}, - prefix = '$OBJPREFIX', - suffix = '$OBJSUFFIX', - src_builder = ['CFile', 'CXXFile'], - source_scanner = SourceFileScanner, - single_source = 1) + static_obj = SCons.Builder.Builder(action={}, + emitter={}, + prefix='$OBJPREFIX', + suffix='$OBJSUFFIX', + src_builder=['CFile', 'CXXFile'], + source_scanner=SourceFileScanner, + single_source=1) env['BUILDERS']['StaticObject'] = static_obj env['BUILDERS']['Object'] = static_obj try: shared_obj = env['BUILDERS']['SharedObject'] except KeyError: - shared_obj = SCons.Builder.Builder(action = {}, - emitter = {}, - prefix = '$SHOBJPREFIX', - suffix = '$SHOBJSUFFIX', - src_builder = ['CFile', 'CXXFile'], - source_scanner = SourceFileScanner, - single_source = 1) + shared_obj = SCons.Builder.Builder(action={}, + emitter={}, + prefix='$SHOBJPREFIX', + suffix='$SHOBJSUFFIX', + src_builder=['CFile', 'CXXFile'], + source_scanner=SourceFileScanner, + single_source=1) env['BUILDERS']['SharedObject'] = shared_obj return (static_obj, shared_obj) + def createCFileBuilders(env): """This is a utility function that creates the CFile/CXXFile Builders in an Environment if they @@ -885,95 +945,109 @@ def createCFileBuilders(env): try: c_file = env['BUILDERS']['CFile'] except KeyError: - c_file = SCons.Builder.Builder(action = {}, - emitter = {}, - suffix = {None:'$CFILESUFFIX'}) + c_file = SCons.Builder.Builder(action={}, + emitter={}, + suffix={None: '$CFILESUFFIX'}) env['BUILDERS']['CFile'] = c_file - env.SetDefault(CFILESUFFIX = '.c') + env.SetDefault(CFILESUFFIX='.c') try: cxx_file = env['BUILDERS']['CXXFile'] except KeyError: - cxx_file = SCons.Builder.Builder(action = {}, - emitter = {}, - suffix = {None:'$CXXFILESUFFIX'}) + cxx_file = SCons.Builder.Builder(action={}, + emitter={}, + suffix={None: '$CXXFILESUFFIX'}) env['BUILDERS']['CXXFile'] = cxx_file - env.SetDefault(CXXFILESUFFIX = '.cc') + env.SetDefault(CXXFILESUFFIX='.cc') return (c_file, cxx_file) + ########################################################################## # Create common Java builders def CreateJarBuilder(env): + """The Jar builder expects a list of class files + which it can package into a jar file. + + The jar tool provides an interface for passing other types + of java files such as .java, directories or swig interfaces + and will build them to class files in which it can package + into the jar. + """ try: - java_jar = env['BUILDERS']['Jar'] + java_jar = env['BUILDERS']['JarFile'] except KeyError: fs = SCons.Node.FS.get_default_fs() jar_com = SCons.Action.Action('$JARCOM', '$JARCOMSTR') - java_jar = SCons.Builder.Builder(action = jar_com, - suffix = '$JARSUFFIX', - src_suffix = '$JAVACLASSSUFFIX', - src_builder = 'JavaClassFile', - source_factory = fs.Entry) - env['BUILDERS']['Jar'] = java_jar + java_jar = SCons.Builder.Builder(action=jar_com, + suffix='$JARSUFFIX', + src_suffix='$JAVACLASSSUFFIX', + src_builder='JavaClassFile', + source_factory=fs.Entry) + env['BUILDERS']['JarFile'] = java_jar return java_jar + def CreateJavaHBuilder(env): try: java_javah = env['BUILDERS']['JavaH'] except KeyError: fs = SCons.Node.FS.get_default_fs() java_javah_com = SCons.Action.Action('$JAVAHCOM', '$JAVAHCOMSTR') - java_javah = SCons.Builder.Builder(action = java_javah_com, - src_suffix = '$JAVACLASSSUFFIX', - target_factory = fs.Entry, - source_factory = fs.File, - src_builder = 'JavaClassFile') + java_javah = SCons.Builder.Builder(action=java_javah_com, + src_suffix='$JAVACLASSSUFFIX', + target_factory=fs.Entry, + source_factory=fs.File, + src_builder='JavaClassFile') env['BUILDERS']['JavaH'] = java_javah return java_javah + def CreateJavaClassFileBuilder(env): try: java_class_file = env['BUILDERS']['JavaClassFile'] except KeyError: fs = SCons.Node.FS.get_default_fs() javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR') - java_class_file = SCons.Builder.Builder(action = javac_com, - emitter = {}, - #suffix = '$JAVACLASSSUFFIX', - src_suffix = '$JAVASUFFIX', - src_builder = ['JavaFile'], - target_factory = fs.Entry, - source_factory = fs.File) + java_class_file = SCons.Builder.Builder(action=javac_com, + emitter={}, + # suffix = '$JAVACLASSSUFFIX', + src_suffix='$JAVASUFFIX', + src_builder=['JavaFile'], + target_factory=fs.Entry, + source_factory=fs.File) env['BUILDERS']['JavaClassFile'] = java_class_file return java_class_file + def CreateJavaClassDirBuilder(env): try: java_class_dir = env['BUILDERS']['JavaClassDir'] except KeyError: fs = SCons.Node.FS.get_default_fs() javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR') - java_class_dir = SCons.Builder.Builder(action = javac_com, - emitter = {}, - target_factory = fs.Dir, - source_factory = fs.Dir) + java_class_dir = SCons.Builder.Builder(action=javac_com, + emitter={}, + target_factory=fs.Dir, + source_factory=fs.Dir) env['BUILDERS']['JavaClassDir'] = java_class_dir return java_class_dir + def CreateJavaFileBuilder(env): try: java_file = env['BUILDERS']['JavaFile'] except KeyError: - java_file = SCons.Builder.Builder(action = {}, - emitter = {}, - suffix = {None:'$JAVASUFFIX'}) + java_file = SCons.Builder.Builder(action={}, + emitter={}, + suffix={None: '$JAVASUFFIX'}) env['BUILDERS']['JavaFile'] = java_file env['JAVASUFFIX'] = '.java' return java_file + class ToolInitializerMethod(object): """ This is added to a construction environment in place of a @@ -984,6 +1058,7 @@ class ToolInitializerMethod(object): whatever builder was (presumably) added to the construction environment in place of this particular instance. """ + def __init__(self, name, initializer): """ Note: we store the tool name as __name__ so it can be used by @@ -1022,6 +1097,7 @@ class ToolInitializerMethod(object): return [], [] return builder(*args, **kw) + class ToolInitializer(object): """ A class for delayed initialization of Tools modules. @@ -1033,6 +1109,7 @@ class ToolInitializer(object): ToolInitializerMethod objects for the various Builder methods that we want to use to delay Tool searches until necessary. """ + def __init__(self, env, tools, names): if not SCons.Util.is_List(tools): tools = [tools] @@ -1067,24 +1144,30 @@ class ToolInitializer(object): env.Tool(tool) return - # If we fall through here, there was no tool module found. - # This is where we can put an informative error message - # about the inability to find the tool. We'll start doing - # this as we cut over more pre-defined Builder+Tools to use - # the ToolInitializer class. + # If we fall through here, there was no tool module found. + # This is where we can put an informative error message + # about the inability to find the tool. We'll start doing + # this as we cut over more pre-defined Builder+Tools to use + # the ToolInitializer class. + def Initializers(env): ToolInitializer(env, ['install'], ['_InternalInstall', '_InternalInstallAs', '_InternalInstallVersionedLib']) + def Install(self, *args, **kw): return self._InternalInstall(*args, **kw) + def InstallAs(self, *args, **kw): return self._InternalInstallAs(*args, **kw) + def InstallVersionedLib(self, *args, **kw): return self._InternalInstallVersionedLib(*args, **kw) + env.AddMethod(Install) env.AddMethod(InstallAs) env.AddMethod(InstallVersionedLib) + def FindTool(tools, env): for tool in tools: t = Tool(tool) @@ -1092,14 +1175,16 @@ def FindTool(tools, env): return tool return None + def FindAllTools(tools, env): def ToolExists(tool, env=env): return Tool(tool).exists(env) - return list(filter (ToolExists, tools)) -def tool_list(platform, env): + return list(filter(ToolExists, tools)) - other_plat_tools=[] + +def tool_list(platform, env): + other_plat_tools = [] # XXX this logic about what tool to prefer on which platform # should be moved into either the platform files or # the tool files themselves. @@ -1107,21 +1192,21 @@ def tool_list(platform, env): # change these search orders, update the man page as well. if str(platform) == 'win32': "prefer Microsoft tools on Windows" - linkers = ['mslink', 'gnulink', 'ilink', 'linkloc', 'ilink32' ] - c_compilers = ['msvc', 'mingw', 'gcc', 'intelc', 'icl', 'icc', 'cc', 'bcc32' ] - cxx_compilers = ['msvc', 'intelc', 'icc', 'g++', 'cxx', 'bcc32' ] - assemblers = ['masm', 'nasm', 'gas', '386asm' ] + linkers = ['mslink', 'gnulink', 'ilink', 'linkloc', 'ilink32'] + c_compilers = ['msvc', 'mingw', 'gcc', 'intelc', 'icl', 'icc', 'cc', 'bcc32'] + cxx_compilers = ['msvc', 'intelc', 'icc', 'g++', 'cxx', 'bcc32'] + assemblers = ['masm', 'nasm', 'gas', '386asm'] fortran_compilers = ['gfortran', 'g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran'] ars = ['mslib', 'ar', 'tlib'] other_plat_tools = ['msvs', 'midl'] elif str(platform) == 'os2': "prefer IBM tools on OS/2" - linkers = ['ilink', 'gnulink', ]#'mslink'] - c_compilers = ['icc', 'gcc',]# 'msvc', 'cc'] - cxx_compilers = ['icc', 'g++',]# 'msvc', 'cxx'] - assemblers = ['nasm',]# 'masm', 'gas'] + linkers = ['ilink', 'gnulink', ] # 'mslink'] + c_compilers = ['icc', 'gcc', ] # 'msvc', 'cc'] + cxx_compilers = ['icc', 'g++', ] # 'msvc', 'cxx'] + assemblers = ['nasm', ] # 'masm', 'gas'] fortran_compilers = ['ifl', 'g77'] - ars = ['ar',]# 'mslib'] + ars = ['ar', ] # 'mslib'] elif str(platform) == 'irix': "prefer MIPSPro on IRIX" linkers = ['sgilink', 'gnulink'] @@ -1174,11 +1259,11 @@ def tool_list(platform, env): else: "prefer GNU tools on all other platforms" linkers = ['gnulink', 'ilink'] - c_compilers = ['gcc', 'intelc', 'icc', 'cc'] + c_compilers = ['gcc', 'intelc', 'icc', 'cc'] cxx_compilers = ['g++', 'intelc', 'icc', 'cxx'] assemblers = ['gas', 'nasm', 'masm'] fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77'] - ars = ['ar',] + ars = ['ar', ] if not str(platform) == 'win32': other_plat_tools += ['m4', 'rpm'] @@ -1210,22 +1295,24 @@ def tool_list(platform, env): d_compiler = FindTool(d_compilers, env) or d_compilers[0] other_tools = FindAllTools(other_plat_tools + [ - #TODO: merge 'install' into 'filesystem' and - # make 'filesystem' the default - 'filesystem', - 'wix', #'midl', 'msvs', - # Parser generators - 'lex', 'yacc', - # Foreign function interface - 'rpcgen', 'swig', - # Java - 'jar', 'javac', 'javah', 'rmic', - # TeX - 'dvipdf', 'dvips', 'gs', - 'tex', 'latex', 'pdflatex', 'pdftex', - # Archivers - 'tar', 'zip', - ], env) + # TODO: merge 'install' into 'filesystem' and + # make 'filesystem' the default + 'filesystem', + 'wix', # 'midl', 'msvs', + # Parser generators + 'lex', 'yacc', + # Foreign function interface + 'rpcgen', 'swig', + # Java + 'jar', 'javac', 'javah', 'rmic', + # TeX + 'dvipdf', 'dvips', 'gs', + 'tex', 'latex', 'pdflatex', 'pdftex', + # Archivers + 'tar', 'zip', + # File builders (text) + 'textfile', + ], env) tools = ([linker, c_compiler, cxx_compiler, fortran_compiler, assembler, ar, d_compiler] @@ -1233,6 +1320,38 @@ def tool_list(platform, env): return [x for x in tools if x] + +def find_program_path(env, key_program, default_paths=None): + """ + Find the location of a tool using various means. + + Mainly for windows where tools aren't all installed in /usr/bin, etc. + + :param env: Current Construction Environment. + :param key_program: Tool to locate. + :param default_paths: List of additional paths this tool might be found in. + """ + # First search in the SCons path + path = env.WhereIs(key_program) + if path: + return path + + # Then in the OS path + path = SCons.Util.WhereIs(key_program) + if path: + return path + + # Finally, add the defaults and check again. Do not change + # ['ENV']['PATH'] permananetly, the caller can do that if needed. + if default_paths is None: + return path + save_path = env['ENV']['PATH'] + for p in default_paths: + env.AppendENVPath('PATH', p) + path = env.WhereIs(key_program) + env['ENV']['PATH'] = save_path + return path + # Local Variables: # tab-width:4 # indent-tabs-mode:nil |