diff options
Diffstat (limited to 'SCons/Tool')
32 files changed, 767 insertions, 663 deletions
diff --git a/SCons/Tool/JavaCommon.py b/SCons/Tool/JavaCommon.py index bb05977..d869b38 100644 --- a/SCons/Tool/JavaCommon.py +++ b/SCons/Tool/JavaCommon.py @@ -87,9 +87,10 @@ if java_parsing: # any alphanumeric token surrounded by angle brackets (generics); # the multi-line comment begin and end tokens /* and */; # array declarations "[]". + # Lambda function symbols: -> _reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"{\};.()]|' + r'\d*\.\d*|[A-Za-z_][\w$.]*|<[A-Za-z_]\w+>|' + - r'/\*|\*/|\[\])') + r'/\*|\*/|\[\]|->)') class OuterState: diff --git a/SCons/Tool/JavaCommonTests.py b/SCons/Tool/JavaCommonTests.py index b0a788e..f35cb9e 100644 --- a/SCons/Tool/JavaCommonTests.py +++ b/SCons/Tool/JavaCommonTests.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os.path -import sys import unittest import fnmatch @@ -97,7 +96,7 @@ public class Foo """Test class names with $ in them""" input = """\ -public class BadDep { +public class BadDep { public void new$rand () {} } """ @@ -484,6 +483,43 @@ public class NestedExample expect = [ 'NestedExample$1', 'NestedExample$1$1', 'NestedExample' ] assert expect == classes, (expect, classes) + def test_lambda_after_new(self): + """Test lamdas after new""" + + input = """\ +// import java.util.*; + +public class LamdaExample +{ + + public void testFunc (int arg1, String arg2, Runnable lambda){ + } + public LamdaExample() + { + testFunc( + 5, + new String("test"), + // Lambda symbol is after new, and used curly braces so + // we should not parse this as a new class. + () -> {} + ); + } + + + public static void main(String argv[]) + { + LamdaExample e = new LamdaExample(); + } +} +""" + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.4') + expect = [ 'LamdaExample' ] + assert expect == classes, (expect, classes) + + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.8') + expect = [ 'LamdaExample' ] + assert expect == classes, (expect, classes) + def test_private_inner_class_instantiation(self): """Test anonymous inner class generated by private instantiation""" @@ -532,7 +568,7 @@ class Broken * Detected. */ class InnerOK { InnerOK () { } } - + { System.out.println("a number: " + 1000.0 + ""); } diff --git a/SCons/Tool/MSCommon/__init__.py b/SCons/Tool/MSCommon/__init__.py index be7720a..ee8f2bd 100644 --- a/SCons/Tool/MSCommon/__init__.py +++ b/SCons/Tool/MSCommon/__init__.py @@ -27,10 +27,6 @@ __doc__ = """ Common functions for Microsoft Visual Studio and Visual C/C++. """ -import copy -import os -import re -import subprocess import SCons.Errors import SCons.Platform.win32 diff --git a/SCons/Tool/MSCommon/arch.py b/SCons/Tool/MSCommon/arch.py index ba57a2c..0032422 100644 --- a/SCons/Tool/MSCommon/arch.py +++ b/SCons/Tool/MSCommon/arch.py @@ -26,7 +26,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" __doc__ = """Module to define supported Windows chip architectures. """ -import os class ArchDefinition: """ diff --git a/SCons/Tool/MSCommon/common.py b/SCons/Tool/MSCommon/common.py index e1a82f2..81004df 100644 --- a/SCons/Tool/MSCommon/common.py +++ b/SCons/Tool/MSCommon/common.py @@ -42,19 +42,46 @@ if LOGFILE == '-': print(message) elif LOGFILE: import logging + modulelist = ( + # root module and parent/root module + 'MSCommon', 'Tool', + # python library and below: correct iff scons does not have a lib folder + 'lib', + # scons modules + 'SCons', 'test', 'scons' + ) + def get_relative_filename(filename, module_list): + if not filename: + return filename + for module in module_list: + try: + ind = filename.rindex(module) + return filename[ind:] + except ValueError: + pass + return filename + class _Debug_Filter(logging.Filter): + # custom filter for module relative filename + def filter(self, record): + relfilename = get_relative_filename(record.pathname, modulelist) + relfilename = relfilename.replace('\\', '/') + record.relfilename = relfilename + return True logging.basicConfig( # This looks like: # 00109ms:MSCommon/vc.py:find_vc_pdir#447: format=( '%(relativeCreated)05dms' - ':MSCommon/%(filename)s' + ':%(relfilename)s' ':%(funcName)s' '#%(lineno)s' ':%(message)s: ' ), filename=LOGFILE, level=logging.DEBUG) - debug = logging.getLogger(name=__name__).debug + logger = logging.getLogger(name=__name__) + logger.addFilter(_Debug_Filter()) + debug = logger.debug else: def debug(x): return None diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py index c6417e9..9a43ae1 100644 --- a/SCons/Tool/MSCommon/vc.py +++ b/SCons/Tool/MSCommon/vc.py @@ -43,7 +43,6 @@ import SCons.Util import subprocess import os import platform -import sys from string import digits as string_digits from subprocess import PIPE @@ -657,16 +656,12 @@ def _check_cl_exists_in_vc_dir(env, vc_dir, msvc_version): return False -def cached_get_installed_vcs(env=None): +def get_installed_vcs(env=None): global __INSTALLED_VCS_RUN - if __INSTALLED_VCS_RUN is None: - ret = get_installed_vcs(env) - __INSTALLED_VCS_RUN = ret - - return __INSTALLED_VCS_RUN + if __INSTALLED_VCS_RUN is not None: + return __INSTALLED_VCS_RUN -def get_installed_vcs(env=None): installed_versions = [] for ver in _VCVER: @@ -687,7 +682,9 @@ def get_installed_vcs(env=None): raise except VisualCException as e: debug('did not find VC %s: caught exception %s' % (ver, str(e))) - return installed_versions + + __INSTALLED_VCS_RUN = installed_versions + return __INSTALLED_VCS_RUN def reset_installed_vcs(): """Make it try again to find VC. This is just for the tests.""" @@ -758,7 +755,7 @@ def get_default_version(env): return msvs_version if not msvc_version: - installed_vcs = cached_get_installed_vcs(env) + installed_vcs = get_installed_vcs(env) debug('installed_vcs:%s' % installed_vcs) if not installed_vcs: #msg = 'No installed VCs' @@ -853,7 +850,7 @@ def msvc_find_valid_batch_script(env, version): warn_msg = "VC version %s not installed. " + \ "C/C++ compilers are most likely not set correctly.\n" + \ " Installed versions are: %s" - warn_msg = warn_msg % (version, cached_get_installed_vcs(env)) + warn_msg = warn_msg % (version, get_installed_vcs(env)) SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg) continue @@ -948,7 +945,7 @@ def msvc_setup_env(env): SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg) def msvc_exists(env=None, version=None): - vcs = cached_get_installed_vcs(env) + vcs = get_installed_vcs(env) if version is None: return len(vcs) > 0 return version in vcs diff --git a/SCons/Tool/ToolTests.py b/SCons/Tool/ToolTests.py index 75a9454..9a6d9b5 100644 --- a/SCons/Tool/ToolTests.py +++ b/SCons/Tool/ToolTests.py @@ -24,7 +24,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os -import sys import unittest import TestUnit @@ -84,19 +83,21 @@ class ToolTestCase(unittest.TestCase): assert env['INCPREFIX'] == '-I', env['INCPREFIX'] assert env['TOOLS'] == ['g++'], env['TOOLS'] + exc_caught = None try: SCons.Tool.Tool() except TypeError: - pass - else: # TODO pylint E0704: bare raise not inside except - raise + exc_caught = 1 + assert exc_caught, "did not catch expected UserError" + exc_caught = None try: p = SCons.Tool.Tool('_does_not_exist_') - except SCons.Errors.SConsEnvironmentError: - pass - else: # TODO pylint E0704: bare raise not inside except - raise + except SCons.Errors.UserError as e: + exc_caught = 1 + # Old msg was Python-style "No tool named", check for new msg: + assert "No tool module" in str(e), e + assert exc_caught, "did not catch expected UserError" def test_pathfind(self): diff --git a/SCons/Tool/__init__.py b/SCons/Tool/__init__.py index 32017cb..0c7afb8 100644 --- a/SCons/Tool/__init__.py +++ b/SCons/Tool/__init__.py @@ -39,7 +39,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import sys import os -from collections.abc import Callable import importlib.util import SCons.Builder @@ -51,6 +50,8 @@ import SCons.Scanner.D import SCons.Scanner.LaTeX import SCons.Scanner.Prog import SCons.Scanner.SWIG +from SCons.Tool.linkCommon import ShLibPrefixGenerator, LdModPrefixGenerator, ShLibSuffixGenerator, \ + LdModSuffixGenerator, LibSymlinksActionFunction, LibSymlinksStrFun DefaultToolpath = [] @@ -183,13 +184,16 @@ class Tool: 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.SConsEnvironmentError(error_string) + sconstools = os.path.normpath(sys.modules['SCons.Tool'].__path__[0]) + if self.toolpath: + sconstools = ", ".join(self.toolpath) + ", " + sconstools + error_string = "No tool module '%s' found in %s" % (self.name, sconstools) + raise SCons.Errors.UserError(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 + error_string = "Tool module '%s' failed import" % self.name raise SCons.Errors.SConsEnvironmentError(error_string) # Don't reload a tool we already loaded. @@ -272,6 +276,9 @@ class Tool: return self.name +LibSymlinksAction = SCons.Action.Action(LibSymlinksActionFunction, LibSymlinksStrFun) + + ########################################################################## # Create common executable program / library / object builders @@ -325,485 +332,6 @@ def createStaticLibBuilder(env): return static_lib -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 - the *result* argument. This function is mainly used for generating library - info such as versioned suffixes, symlink maps, sonames etc. by delegating - the core job to callbacks configured by current linker tool""" - - Verbose = False - - if Verbose: - print('_call_linker_cb: args=%r' % args) - print('_call_linker_cb: callback=%r' % callback) - - try: - cbfun = env['LINKCALLBACKS'][callback] - except (KeyError, TypeError): - if Verbose: - print('_call_linker_cb: env["LINKCALLBACKS"][%r] not found or can not be used' % callback) - pass - else: - if Verbose: - print('_call_linker_cb: env["LINKCALLBACKS"][%r] found' % callback) - print('_call_linker_cb: env["LINKCALLBACKS"][%r]=%r' % (callback, cbfun)) - 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 - return env.subst(string, *args, **kw2) - - -class _ShLibInfoSupport: - @property - def libtype(self): - return 'ShLib' - - def get_lib_prefix(self, env, *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) - - def get_lib_version(self, env, *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) - - -class _LdModInfoSupport: - @property - def libtype(self): - return 'LdMod' - - def get_lib_prefix(self, env, *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) - - def get_lib_version(self, env, *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) - - -class _ImpLibInfoSupport: - @property - def libtype(self): - return 'ImpLib' - - def get_lib_prefix(self, env, *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) - - def get_lib_version(self, env, *args, **kw): - version = _call_env_subst(env, '$IMPLIBVERSION', *args, **kw) - if not version: - try: - lt = kw['implib_libtype'] - except KeyError: - pass - else: - if lt == 'ShLib': - version = _call_env_subst(env, '$SHLIBVERSION', *args, **kw) - elif lt == 'LdMod': - version = _call_env_subst(env, '$LDMODULEVERSION', *args, **kw) - return version - - def get_lib_noversionsymlinks(self, env, *args, **kw): - disable = None - try: - env['IMPLIBNOVERSIONSYMLINKS'] - except KeyError: - try: - lt = kw['implib_libtype'] - except KeyError: - pass - else: - if lt == 'ShLib': - disable = _call_env_subst(env, '$SHLIBNOVERSIONSYMLINKS', *args, **kw) - elif lt == 'LdMod': - disable = _call_env_subst(env, '$LDMODULENOVERSIONSYMLINKS', *args, **kw) - else: - disable = _call_env_subst(env, '$IMPLIBNOVERSIONSYMLINKS', *args, **kw) - return disable - - -class _LibInfoGeneratorBase: - """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} - - def __init__(self, libtype, infoname): - self.libtype = libtype - self.infoname = infoname - - @property - def libtype(self): - return self._support.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_lib_prefix(self, 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) - - def get_lib_version(self, 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) - - def get_versioned_lib_info_generator(self, **kw): - """ - Returns name of generator linker callback that will 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'. - """ - 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): - 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): - Verbose = False - - if sources and 'source' not in kw: - kw2 = kw.copy() - kw2['source'] = sources - else: - kw2 = kw - - prefix = self.get_lib_prefix(env, **kw2) - if Verbose: - print("_LibPrefixGenerator: input prefix=%r" % prefix) - - version = self.get_lib_version(env, **kw2) - if Verbose: - print("_LibPrefixGenerator: version=%r" % version) - - if version: - prefix = self.generate_versioned_lib_info(env, [prefix, version], prefix, **kw2) - - if Verbose: - print("_LibPrefixGenerator: return prefix=%r" % prefix) - return prefix - - -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): - Verbose = False - - if sources and 'source' not in kw: - kw2 = kw.copy() - kw2['source'] = sources - else: - kw2 = kw - - suffix = self.get_lib_suffix(env, **kw2) - if Verbose: - print("_LibSuffixGenerator: input suffix=%r" % suffix) - - version = self.get_lib_version(env, **kw2) - if Verbose: - print("_LibSuffixGenerator: version=%r" % version) - - if version: - suffix = self.generate_versioned_lib_info(env, [suffix, version], suffix, **kw2) - - if Verbose: - print("_LibSuffixGenerator: return suffix=%r" % suffix) - return suffix - - -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') - - def __call__(self, env, libnode, **kw): - Verbose = False - - if libnode and 'target' not in kw: - kw2 = kw.copy() - kw2['target'] = libnode - else: - kw2 = kw - - if Verbose: - print("_LibSymLinkGenerator: libnode=%r" % libnode.get_path()) - - symlinks = None - - version = self.get_lib_version(env, **kw2) - disable = self.get_lib_noversionsymlinks(env, **kw2) - if Verbose: - print('_LibSymlinkGenerator: version=%r' % version) - print('_LibSymlinkGenerator: disable=%r' % disable) - - if version and not disable: - 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') -ImpLibSymlinkGenerator = _LibSymlinkGenerator('ImpLib') - - -class _LibNameGenerator(_LibInfoGeneratorBase): - """Generates "unmangled" library name from a library file node. - - Generally, it's thought to revert modifications done by prefix/suffix - generators (_LibPrefixGenerator/_LibSuffixGenerator) used by a library - builder. For example, on gnulink the suffix generator used by SharedLibrary - builder appends $SHLIBVERSION to $SHLIBSUFFIX producing node name which - ends with "$SHLIBSUFFIX.$SHLIBVERSION". Correspondingly, the implementation - of _LibNameGenerator replaces "$SHLIBSUFFIX.$SHLIBVERSION" with - "$SHLIBSUFFIX" in the node's basename. So that, if $SHLIBSUFFIX is ".so", - $SHLIBVERSION is "0.1.2" and the node path is "/foo/bar/libfoo.so.0.1.2", - 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') - - def __call__(self, env, libnode, **kw): - """Returns "demangled" library name""" - Verbose = False - - if libnode and 'target' not in kw: - kw2 = kw.copy() - kw2['target'] = libnode - else: - kw2 = kw - - if Verbose: - print("_LibNameGenerator: libnode=%r" % libnode.get_path()) - - version = self.get_lib_version(env, **kw2) - if Verbose: - print('_LibNameGenerator: version=%r' % version) - - name = None - if version: - 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: - name = os.path.basename(libnode.get_path()) - - if Verbose: - print('_LibNameGenerator: return name=%r' % name) - - return name - - -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') - - def __call__(self, env, libnode, **kw): - """Returns a SONAME based on a shared library's node path""" - Verbose = False - - if libnode and 'target' not in kw: - kw2 = kw.copy() - kw2['target'] = libnode - else: - kw2 = kw - - if Verbose: - print("_LibSonameGenerator: libnode=%r" % libnode.get_path()) - - soname = _call_env_subst(env, '$SONAME', **kw2) - if not soname: - 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) - 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.libtype)(env, libnode) - if Verbose: - print("_LibSonameGenerator: FALLBACK: soname=%r" % soname) - - if Verbose: - print("_LibSonameGenerator: return soname=%r" % soname) - - return soname - - -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] - 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])) - - clean_targets = kw.get('clean_targets', []) - if not SCons.Util.is_List(clean_targets): - clean_targets = [clean_targets] - - for link, linktgt in symlinks: - env.SideEffect(link, linktgt) - 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: - 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 - nodes. - """ - - Verbose = False - for link, linktgt in symlinks: - linktgt = link.get_dir().rel_path(linktgt) - link = link.get_path() - 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: - 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: - 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) - 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) - 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)]) - except (KeyError, ValueError): - pass - else: - cmd += ": %s" % linkstr - return cmd - - -LibSymlinksAction = SCons.Action.Action(LibSymlinksActionFunction, LibSymlinksStrFun) - - def createSharedLibBuilder(env): """This is a utility function that creates the SharedLibrary Builder in an Environment if it is not there already. diff --git a/SCons/Tool/applelink.py b/SCons/Tool/applelink.py index 8c081a2..aec8b93 100644 --- a/SCons/Tool/applelink.py +++ b/SCons/Tool/applelink.py @@ -39,11 +39,13 @@ import SCons.Util # the -rpath option, so we use the "link" tool instead of "gnulink". from . import link -from SCons.Tool import ShLibSonameGenerator +from .linkCommon import ShLibSonameGenerator + class AppleLinkInvalidCurrentVersionException(Exception): pass + class AppleLinkInvalidCompatibilityVersionException(Exception): pass @@ -70,7 +72,7 @@ def _applelib_versioned_lib_soname(env, libnode, version, prefix, suffix, name_f if Verbose: print("_applelib_versioned_lib_soname: name={!r}".format(name)) major = version.split('.')[0] - (libname,_suffix) = name.split('.') + (libname, _suffix) = name.split('.') # if a desired SONAME was supplied, use that, otherwise create # a default from the major version if env.get('SONAME'): @@ -81,12 +83,15 @@ def _applelib_versioned_lib_soname(env, libnode, version, prefix, suffix, name_f print("_applelib_versioned_lib_soname: soname={!r}".format(soname)) return soname + def _applelib_versioned_shlib_soname(env, libnode, version, prefix, suffix): return _applelib_versioned_lib_soname(env, libnode, version, prefix, suffix, link._versioned_shlib_name) # User programmatically describes how SHLIBVERSION maps to values for compat/current. _applelib_max_version_values = (65535, 255, 255) + + def _applelib_check_valid_version(version_string): """ Check that the version # is valid. @@ -99,17 +104,18 @@ def _applelib_check_valid_version(version_string): """ parts = version_string.split('.') if len(parts) > 3: - return False, "Version string has too many periods [%s]"%version_string + return False, "Version string has too many periods [%s]" % version_string if len(parts) <= 0: - return False, "Version string unspecified [%s]"%version_string + return False, "Version string unspecified [%s]" % version_string for (i, p) in enumerate(parts): try: p_i = int(p) except ValueError: - return False, "Version component %s (from %s) is not a number"%(p, version_string) + return False, "Version component %s (from %s) is not a number" % (p, version_string) if p_i < 0 or p_i > _applelib_max_version_values[i]: - return False, "Version component %s (from %s) is not valid value should be between 0 and %d"%(p, version_string, _applelib_max_version_values[i]) + return False, "Version component %s (from %s) is not valid value should be between 0 and %d" % ( + p, version_string, _applelib_max_version_values[i]) return True, "" @@ -190,9 +196,8 @@ def generate(env): env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -dynamiclib') env['SHLINKCOM'] = env['SHLINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS' - # see: http://docstore.mik.ua/orelly/unix3/mac/ch05_04.htm for proper naming - link._setup_versioned_lib_variables(env, tool = 'applelink')#, use_soname = use_soname) + link._setup_versioned_lib_variables(env, tool='applelink') #, use_soname=True) env['LINKCALLBACKS'] = link._versioned_lib_callbacks() env['LINKCALLBACKS']['VersionedShLibSuffix'] = _applelib_versioned_lib_suffix env['LINKCALLBACKS']['VersionedShLibSoname'] = _applelib_versioned_shlib_soname @@ -205,15 +210,14 @@ def generate(env): # override the default for loadable modules, which are different # on OS X than dynamic shared libs. echoing what XCode does for # pre/suffixes: - env['LDMODULEPREFIX'] = '' - env['LDMODULESUFFIX'] = '' + env['LDMODULEPREFIX'] = '' + env['LDMODULESUFFIX'] = '' env['LDMODULEFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -bundle') env['LDMODULECOM'] = '$LDMODULE -o ${TARGET} $LDMODULEFLAGS $SOURCES $_LIBDIRFLAGS $_LIBFLAGS $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS' env['__SHLIBVERSIONFLAGS'] = '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}' - def exists(env): return env['PLATFORM'] == 'darwin' diff --git a/SCons/Tool/clang.py b/SCons/Tool/clang.py index 162daad..e39c742 100644 --- a/SCons/Tool/clang.py +++ b/SCons/Tool/clang.py @@ -84,8 +84,7 @@ def generate(env): # clang -dumpversion is of no use with pipe.stdout: line = pipe.stdout.readline() - if sys.version_info[0] > 2: - line = line.decode() + line = line.decode() match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line) if match: env['CCVERSION'] = match.group(1) diff --git a/SCons/Tool/clangxx.py b/SCons/Tool/clangxx.py index b1dc6f3..736d455 100644 --- a/SCons/Tool/clangxx.py +++ b/SCons/Tool/clangxx.py @@ -92,8 +92,7 @@ def generate(env): # clang -dumpversion is of no use with pipe.stdout: line = pipe.stdout.readline() - if sys.version_info[0] > 2: - line = line.decode() + line = line.decode() match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line) if match: env['CXXVERSION'] = match.group(1) diff --git a/SCons/Tool/cyglink.py b/SCons/Tool/cyglink.py index fbb6d24..08b8a98 100644 --- a/SCons/Tool/cyglink.py +++ b/SCons/Tool/cyglink.py @@ -12,19 +12,25 @@ import re import os import SCons.Action +from SCons.Tool.linkCommon import ImpLibSymlinkGenerator, StringizeLibSymlinks, EmitLibSymlinks, ImpLibPrefixGenerator, \ + ImpLibSuffixGenerator, ImpLibNameGenerator import SCons.Util import SCons.Tool -#MAYBE: from . import gnulink from . import gnulink from . import link + def _lib_generator(target, source, env, for_signature, **kw): - try: cmd = kw['cmd'] - except KeyError: cmd = SCons.Util.CLVar(['$SHLINK']) + try: + cmd = kw['cmd'] + except KeyError: + cmd = SCons.Util.CLVar(['$SHLINK']) - try: vp = kw['varprefix'] - except KeyError: vp = 'SHLIB' + try: + vp = kw['varprefix'] + except KeyError: + vp = 'SHLIB' dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp) if dll: cmd.extend(['-o', dll]) @@ -34,12 +40,12 @@ def _lib_generator(target, source, env, for_signature, **kw): implib = env.FindIxes(target, 'IMPLIBPREFIX', 'IMPLIBSUFFIX') if implib: cmd.extend([ - '-Wl,--out-implib='+implib.get_string(for_signature), + '-Wl,--out-implib=' + implib.get_string(for_signature), '-Wl,--export-all-symbols', '-Wl,--enable-auto-import', '-Wl,--whole-archive', '$SOURCES', '-Wl,--no-whole-archive', '$_LIBDIRFLAGS', '$_LIBFLAGS' - ]) + ]) else: cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS']) @@ -49,12 +55,14 @@ def _lib_generator(target, source, env, for_signature, **kw): def shlib_generator(target, source, env, for_signature): return _lib_generator(target, source, env, for_signature, varprefix='SHLIB', - cmd = SCons.Util.CLVar(['$SHLINK'])) + cmd=SCons.Util.CLVar(['$SHLINK'])) + def ldmod_generator(target, source, env, for_signature): return _lib_generator(target, source, env, for_signature, varprefix='LDMODULE', - cmd = SCons.Util.CLVar(['$LDMODULE'])) + cmd=SCons.Util.CLVar(['$LDMODULE'])) + def _lib_emitter(target, source, env, **kw): Verbose = False @@ -62,11 +70,15 @@ def _lib_emitter(target, source, env, **kw): if Verbose: print("_lib_emitter: target[0]=%r" % target[0].get_path()) - try: vp = kw['varprefix'] - except KeyError: vp = 'SHLIB' + try: + vp = kw['varprefix'] + except KeyError: + vp = 'SHLIB' - try: libtype = kw['libtype'] - except KeyError: libtype = 'ShLib' + try: + libtype = kw['libtype'] + except KeyError: + libtype = 'ShLib' dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp) no_import_lib = env.get('no_import_lib', 0) @@ -75,12 +87,13 @@ def _lib_emitter(target, source, env, **kw): print("_lib_emitter: dll=%r" % dll.get_path()) if not dll or len(target) > 1: - raise SCons.Errors.UserError("A shared library should have exactly one target with the suffix: %s" % env.subst("$%sSUFFIX" % vp)) + raise SCons.Errors.UserError( + "A shared library should have exactly one target with the suffix: %s" % env.subst("$%sSUFFIX" % vp)) # Remove any "lib" after the prefix pre = env.subst('$%sPREFIX' % vp) - if dll.name[len(pre):len(pre)+3] == 'lib': - dll.name = pre + dll.name[len(pre)+3:] + if dll.name[len(pre):len(pre) + 3] == 'lib': + dll.name = pre + dll.name[len(pre) + 3:] if Verbose: print("_lib_emitter: dll.name=%r" % dll.name) @@ -107,23 +120,26 @@ def _lib_emitter(target, source, env, **kw): implib_target.attributes.shared = 1 target.append(implib_target) - symlinks = SCons.Tool.ImpLibSymlinkGenerator(env, implib_target, - implib_libtype=libtype, - generator_libtype=libtype+'ImpLib') + symlinks = ImpLibSymlinkGenerator(env, implib_target, + implib_libtype=libtype, + generator_libtype=libtype + 'ImpLib') if Verbose: - print("_lib_emitter: implib symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks)) + print("_lib_emitter: implib symlinks=%r" % StringizeLibSymlinks(symlinks)) if symlinks: - SCons.Tool.EmitLibSymlinks(env, symlinks, implib_target, clean_targets = target[0]) + EmitLibSymlinks(env, symlinks, implib_target, clean_targets=target[0]) implib_target.attributes.shliblinks = symlinks return (target, source) + def shlib_emitter(target, source, env): return _lib_emitter(target, source, env, varprefix='SHLIB', libtype='ShLib') + def ldmod_emitter(target, source, env): return _lib_emitter(target, source, env, varprefix='LDMODULE', libtype='LdMod') + def _versioned_lib_suffix(env, suffix, version): """Generate versioned shared library suffix from a unversioned one. If suffix='.dll', and version='0.1.2', then it returns '-0-1-2.dll'""" @@ -138,12 +154,14 @@ def _versioned_lib_suffix(env, suffix, version): print("_versioned_lib_suffix: return suffix= ", suffix) return suffix + def _versioned_implib_name(env, libnode, version, prefix, suffix, **kw): return link._versioned_lib_name(env, libnode, version, prefix, suffix, - SCons.Tool.ImpLibPrefixGenerator, - SCons.Tool.ImpLibSuffixGenerator, + ImpLibPrefixGenerator, + ImpLibSuffixGenerator, implib_libtype=kw['libtype']) + def _versioned_implib_symlinks(env, libnode, version, prefix, suffix, **kw): """Generate link names that should be created for a versioned shared library. Returns a list in the form [ (link, linktarget), ... ] @@ -154,17 +172,18 @@ def _versioned_implib_symlinks(env, libnode, version, prefix, suffix, **kw): print("_versioned_implib_symlinks: libnode=%r" % libnode.get_path()) print("_versioned_implib_symlinks: version=%r" % version) - try: libtype = kw['libtype'] - except KeyError: libtype = 'ShLib' - + try: + libtype = kw['libtype'] + except KeyError: + libtype = 'ShLib' linkdir = os.path.dirname(libnode.get_path()) if Verbose: print("_versioned_implib_symlinks: linkdir=%r" % linkdir) - name = SCons.Tool.ImpLibNameGenerator(env, libnode, - implib_libtype=libtype, - generator_libtype=libtype+'ImpLib') + name = ImpLibNameGenerator(env, libnode, + implib_libtype=libtype, + generator_libtype=libtype + 'ImpLib') if Verbose: print("_versioned_implib_symlinks: name=%r" % name) @@ -174,59 +193,65 @@ def _versioned_implib_symlinks(env, libnode, version, prefix, suffix, **kw): symlinks = [(link0, libnode)] if Verbose: - print("_versioned_implib_symlinks: return symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks)) + print("_versioned_implib_symlinks: return symlinks=%r" % StringizeLibSymlinks(symlinks)) return symlinks + shlib_action = SCons.Action.Action(shlib_generator, generator=1) ldmod_action = SCons.Action.Action(ldmod_generator, generator=1) + def generate(env): """Add Builders and construction variables for cyglink to an Environment.""" gnulink.generate(env) - env['LINKFLAGS'] = SCons.Util.CLVar('-Wl,-no-undefined') + env['LINKFLAGS'] = SCons.Util.CLVar('-Wl,-no-undefined') env['SHLINKCOM'] = shlib_action env['LDMODULECOM'] = ldmod_action - env.Append(SHLIBEMITTER = [shlib_emitter]) - env.Append(LDMODULEEMITTER = [ldmod_emitter]) + env.Append(SHLIBEMITTER=[shlib_emitter]) + env.Append(LDMODULEEMITTER=[ldmod_emitter]) - env['SHLIBPREFIX'] = 'cyg' - env['SHLIBSUFFIX'] = '.dll' + env['SHLIBPREFIX'] = 'cyg' + env['SHLIBSUFFIX'] = '.dll' - env['IMPLIBPREFIX'] = 'lib' - env['IMPLIBSUFFIX'] = '.dll.a' + env['IMPLIBPREFIX'] = 'lib' + env['IMPLIBSUFFIX'] = '.dll.a' # Variables used by versioned shared libraries - env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS' - env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS' + env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS' + env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS' # SHLIBVERSIONFLAGS and LDMODULEVERSIONFLAGS are same as in gnulink... # LINKCALLBACKS are NOT inherited from gnulink env['LINKCALLBACKS'] = { - 'VersionedShLibSuffix' : _versioned_lib_suffix, - 'VersionedLdModSuffix' : _versioned_lib_suffix, - 'VersionedImpLibSuffix' : _versioned_lib_suffix, - 'VersionedShLibName' : link._versioned_shlib_name, - 'VersionedLdModName' : link._versioned_ldmod_name, - 'VersionedShLibImpLibName' : lambda *args: _versioned_implib_name(*args, libtype='ShLib'), - 'VersionedLdModImpLibName' : lambda *args: _versioned_implib_name(*args, libtype='LdMod'), - 'VersionedShLibImpLibSymlinks' : lambda *args: _versioned_implib_symlinks(*args, libtype='ShLib'), - 'VersionedLdModImpLibSymlinks' : lambda *args: _versioned_implib_symlinks(*args, libtype='LdMod'), + 'VersionedShLibSuffix': _versioned_lib_suffix, + 'VersionedLdModSuffix': _versioned_lib_suffix, + 'VersionedImpLibSuffix': _versioned_lib_suffix, + 'VersionedShLibName': link._versioned_shlib_name, + 'VersionedLdModName': link._versioned_ldmod_name, + 'VersionedShLibImpLibName': lambda *args: _versioned_implib_name(*args, libtype='ShLib'), + 'VersionedLdModImpLibName': lambda *args: _versioned_implib_name(*args, libtype='LdMod'), + 'VersionedShLibImpLibSymlinks': lambda *args: _versioned_implib_symlinks(*args, libtype='ShLib'), + 'VersionedLdModImpLibSymlinks': lambda *args: _versioned_implib_symlinks(*args, libtype='LdMod'), } # these variables were set by gnulink but are not used in cyglink - try: del env['_SHLIBSONAME'] - except KeyError: pass - try: del env['_LDMODULESONAME'] - except KeyError: pass + try: + del env['_SHLIBSONAME'] + except KeyError: + pass + try: + del env['_LDMODULESONAME'] + except KeyError: + pass + def exists(env): return gnulink.exists(env) - # Local Variables: # tab-width:4 # indent-tabs-mode:nil diff --git a/SCons/Tool/dmd.py b/SCons/Tool/dmd.py index ba12131..5970246 100644 --- a/SCons/Tool/dmd.py +++ b/SCons/Tool/dmd.py @@ -50,8 +50,6 @@ LIBS """ # -# __COPYRIGHT__ -# # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including @@ -72,11 +70,6 @@ LIBS # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - -import os -import subprocess - import SCons.Action import SCons.Builder import SCons.Defaults @@ -84,6 +77,7 @@ import SCons.Scanner.D import SCons.Tool import SCons.Tool.DCommon as DCommon +from SCons.Tool.linkCommon import ShLibSonameGenerator def generate(env): @@ -128,7 +122,8 @@ def generate(env): env['SHDLINK'] = '$DC' env['SHDLINKFLAGS'] = SCons.Util.CLVar('$DLINKFLAGS -shared -defaultlib=libphobos2.so') - env['SHDLINKCOM'] = '$DLINK -of$TARGET $SHDLINKFLAGS $__SHDLIBVERSIONFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS' + env[ + 'SHDLINKCOM'] = '$DLINK -of$TARGET $SHDLINKFLAGS $__SHDLIBVERSIONFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS' env['DLIBLINKPREFIX'] = '' if env['PLATFORM'] == 'win32' else '-L-l' env['DLIBLINKSUFFIX'] = '.lib' if env['PLATFORM'] == 'win32' else '' @@ -139,7 +134,8 @@ def generate(env): env['_DLIBDIRFLAGS'] = '${_concat(DLIBDIRPREFIX, LIBPATH, DLIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)}' env['DLIB'] = 'lib' if env['PLATFORM'] == 'win32' else 'ar cr' - env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {0}$TARGET $SOURCES $_DLIBFLAGS'.format('-c ' if env['PLATFORM'] == 'win32' else '') + env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {0}$TARGET $SOURCES $_DLIBFLAGS'.format( + '-c ' if env['PLATFORM'] == 'win32' else '') # env['_DLIBFLAGS'] = '${_concat(DLIBFLAGPREFIX, DLIBFLAGS, DLIBFLAGSUFFIX, __env__)}' @@ -157,7 +153,7 @@ def generate(env): env['_SHDLIBSONAME'] = '${DShLibSonameGenerator(__env__,TARGET)}' # NOTE: this is a quick hack, the soname will only work if there is # c/c++ linker loaded which provides callback for the ShLibSonameGenerator - env['DShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator + env['DShLibSonameGenerator'] = ShLibSonameGenerator # NOTE: this is only for further reference, currently $SHDLIBVERSION does # not work, the user must use $SHLIBVERSION env['SHDLIBVERSION'] = '$SHLIBVERSION' @@ -172,7 +168,6 @@ def generate(env): def exists(env): return env.Detect(['dmd', 'ldmd2', 'gdmd']) - # Local Variables: # tab-width:4 # indent-tabs-mode:nil diff --git a/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/docbook.py b/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/docbook.py index 3d53bf7..d79ece3 100644 --- a/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/docbook.py +++ b/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/docbook.py @@ -1,7 +1,5 @@ # docbook.py: extension module # $Id: docbook.py 8353 2009-03-17 16:57:50Z mzjn $ -import sys -import string import libxml2 import libxslt import re diff --git a/SCons/Tool/fortran.py b/SCons/Tool/fortran.py index aeb9130..0a68df6 100644 --- a/SCons/Tool/fortran.py +++ b/SCons/Tool/fortran.py @@ -33,7 +33,6 @@ selection method. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import re import SCons.Action import SCons.Defaults diff --git a/SCons/Tool/gcc.py b/SCons/Tool/gcc.py index d56f6a0..37626ef 100644 --- a/SCons/Tool/gcc.py +++ b/SCons/Tool/gcc.py @@ -34,7 +34,6 @@ selection method. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" from . import cc -import os import re import subprocess diff --git a/SCons/Tool/gdc.py b/SCons/Tool/gdc.py index ecf4f3a..12c327e 100644 --- a/SCons/Tool/gdc.py +++ b/SCons/Tool/gdc.py @@ -53,6 +53,7 @@ import SCons.Defaults import SCons.Tool import SCons.Tool.DCommon as DCommon +import SCons.Tool.linkCommon def generate(env): @@ -120,7 +121,7 @@ def generate(env): env['_SHDLIBSONAME'] = '${DShLibSonameGenerator(__env__,TARGET)}' # NOTE: this is a quick hack, the soname will only work if there is # c/c++ linker loaded which provides callback for the ShLibSonameGenerator - env['DShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator + env['DShLibSonameGenerator'] = SCons.Tool.linkCommon.ShLibSonameGenerator # NOTE: this is only for further reference, currently $SHDLIBVERSION does # not work, the user must use $SHLIBVERSION env['SHDLIBVERSION'] = '$SHLIBVERSION' diff --git a/SCons/Tool/gxx.py b/SCons/Tool/gxx.py index 4b86327..88186cb 100644 --- a/SCons/Tool/gxx.py +++ b/SCons/Tool/gxx.py @@ -33,9 +33,6 @@ selection method. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path -import re -import subprocess import SCons.Tool import SCons.Util diff --git a/SCons/Tool/install.py b/SCons/Tool/install.py index 67c9ec8..e79203e 100644 --- a/SCons/Tool/install.py +++ b/SCons/Tool/install.py @@ -29,13 +29,13 @@ selection method. # 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os from shutil import copy2, copymode, copystat import SCons.Action import SCons.Tool +from SCons.Tool.linkCommon import StringizeLibSymlinks, CreateLibSymlinks, EmitLibSymlinks import SCons.Util # @@ -213,9 +213,9 @@ def installShlibLinks(dest, source, env): Verbose = False symlinks = listShlibLinksToInstall(dest, source, env) if Verbose: - print('installShlibLinks: symlinks={!r}'.format(SCons.Tool.StringizeLibSymlinks(symlinks))) + print('installShlibLinks: symlinks={!r}'.format(StringizeLibSymlinks(symlinks))) if symlinks: - SCons.Tool.CreateLibSymlinks(env, symlinks) + CreateLibSymlinks(env, symlinks) return def installFunc(target, source, env): @@ -292,7 +292,7 @@ def add_versioned_targets_to_INSTALLED_FILES(target, source, env): print("add_versioned_targets_to_INSTALLED_FILES: target={!r}".format(list(map(str, target)))) symlinks = listShlibLinksToInstall(target[0], source, env) if symlinks: - SCons.Tool.EmitLibSymlinks(env, symlinks, target[0]) + EmitLibSymlinks(env, symlinks, target[0]) _UNIQUE_INSTALLED_FILES = None return (target, source) diff --git a/SCons/Tool/intelc.py b/SCons/Tool/intelc.py index 38bdc32..5025719 100644 --- a/SCons/Tool/intelc.py +++ b/SCons/Tool/intelc.py @@ -32,7 +32,11 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import math, sys, os.path, glob, string, re +import glob +import math +import os.path +import re +import sys is_windows = sys.platform == 'win32' is_win64 = is_windows and (os.environ['PROCESSOR_ARCHITECTURE'] == 'AMD64' or diff --git a/SCons/Tool/ldc.py b/SCons/Tool/ldc.py index f915569..d893841 100644 --- a/SCons/Tool/ldc.py +++ b/SCons/Tool/ldc.py @@ -24,8 +24,6 @@ Lib tool variables: """ # -# __COPYRIGHT__ -# # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including @@ -46,11 +44,6 @@ Lib tool variables: # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - -import os -import subprocess - import SCons.Action import SCons.Builder import SCons.Defaults @@ -58,6 +51,7 @@ import SCons.Scanner.D import SCons.Tool import SCons.Tool.DCommon as DCommon +from SCons.Tool.linkCommon import ShLibSonameGenerator def generate(env): @@ -133,7 +127,7 @@ def generate(env): env['_SHDLIBSONAME'] = '${DShLibSonameGenerator(__env__,TARGET)}' # NOTE: this is a quick hack, the soname will only work if there is # c/c++ linker loaded which provides callback for the ShLibSonameGenerator - env['DShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator + env['DShLibSonameGenerator'] = ShLibSonameGenerator # NOTE: this is only for further reference, currently $SHDLIBVERSION does # not work, the user must use $SHLIBVERSION env['SHDLIBVERSION'] = '$SHLIBVERSION' diff --git a/SCons/Tool/link.py b/SCons/Tool/link.py index a3567aa..de377ac 100644 --- a/SCons/Tool/link.py +++ b/SCons/Tool/link.py @@ -9,8 +9,6 @@ selection method. """ # -# __COPYRIGHT__ -# # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including @@ -30,7 +28,6 @@ selection method. # 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import sys import re @@ -46,7 +43,9 @@ from SCons.Tool.DCommon import isD from SCons.Tool.cxx import iscplusplus -from SCons.Tool import ShLibSonameGenerator +from SCons.Tool.linkCommon import StringizeLibSymlinks, ShLibSonameGenerator, EmitLibSymlinks, ShLibSymlinkGenerator, \ + LdModSymlinkGenerator, ShLibPrefixGenerator, ShLibSuffixGenerator, LdModPrefixGenerator, LdModSuffixGenerator, \ + LdModSonameGenerator issued_mixed_link_warning = False @@ -97,17 +96,17 @@ def _lib_emitter(target, source, env, **kw): print("_lib_emitter: symlinks={!r}".format(symlinks)) if symlinks: - SCons.Tool.EmitLibSymlinks(env, symlinks, target[0]) + EmitLibSymlinks(env, symlinks, target[0]) target[0].attributes.shliblinks = symlinks return (target, source) def shlib_emitter(target, source, env): - return _lib_emitter(target, source, env, symlink_generator=SCons.Tool.ShLibSymlinkGenerator) + return _lib_emitter(target, source, env, symlink_generator=ShLibSymlinkGenerator) def ldmod_emitter(target, source, env): - return _lib_emitter(target, source, env, symlink_generator=SCons.Tool.LdModSymlinkGenerator) + return _lib_emitter(target, source, env, symlink_generator=LdModSymlinkGenerator) # This is generic enough to be included here... @@ -142,14 +141,14 @@ def _versioned_lib_name(env, libnode, version, prefix, suffix, prefix_generator, def _versioned_shlib_name(env, libnode, version, prefix, suffix, **kw): - prefix_generator = SCons.Tool.ShLibPrefixGenerator - suffix_generator = SCons.Tool.ShLibSuffixGenerator + prefix_generator = ShLibPrefixGenerator + suffix_generator = ShLibSuffixGenerator return _versioned_lib_name(env, libnode, version, prefix, suffix, prefix_generator, suffix_generator, **kw) def _versioned_ldmod_name(env, libnode, version, prefix, suffix, **kw): - prefix_generator = SCons.Tool.LdModPrefixGenerator - suffix_generator = SCons.Tool.LdModSuffixGenerator + prefix_generator = LdModPrefixGenerator + suffix_generator = LdModSuffixGenerator return _versioned_lib_name(env, libnode, version, prefix, suffix, prefix_generator, suffix_generator, **kw) @@ -236,7 +235,8 @@ def _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, so symlinks = [(link0, libnode), (link1, libnode)] if Verbose: - print("_versioned_lib_symlinks: return symlinks={!r}".format(SCons.Tool.StringizeLibSymlinks(symlinks))) + print("_versioned_lib_symlinks: return symlinks={!r}".format( + StringizeLibSymlinks(symlinks))) return symlinks @@ -301,8 +301,8 @@ def _setup_versioned_lib_variables(env, **kw): env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS -Wl,-soname=$_LDMODULESONAME' env['_SHLIBSONAME'] = '${ShLibSonameGenerator(__env__,TARGET)}' env['_LDMODULESONAME'] = '${LdModSonameGenerator(__env__,TARGET)}' - env['ShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator - env['LdModSonameGenerator'] = SCons.Tool.LdModSonameGenerator + env['ShLibSonameGenerator'] = ShLibSonameGenerator + env['LdModSonameGenerator'] = LdModSonameGenerator else: env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS' env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS' diff --git a/SCons/Tool/linkCommon/__init__.py b/SCons/Tool/linkCommon/__init__.py new file mode 100644 index 0000000..f66ad6d --- /dev/null +++ b/SCons/Tool/linkCommon/__init__.py @@ -0,0 +1,502 @@ +"""SCons.Tool.linkCommon + +Common link/shared library logic +""" + +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +import os +from typing import Callable +from SCons.Util import is_List + + +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 + the *result* argument. This function is mainly used for generating library + info such as versioned suffixes, symlink maps, sonames etc. by delegating + the core job to callbacks configured by current linker tool""" + + Verbose = False + + if Verbose: + print('_call_linker_cb: args=%r' % args) + print('_call_linker_cb: callback=%r' % callback) + + try: + cbfun = env['LINKCALLBACKS'][callback] + except (KeyError, TypeError): + if Verbose: + print('_call_linker_cb: env["LINKCALLBACKS"][%r] not found or can not be used' % callback) + else: + if Verbose: + print('_call_linker_cb: env["LINKCALLBACKS"][%r] found' % callback) + print('_call_linker_cb: env["LINKCALLBACKS"][%r]=%r' % (callback, cbfun)) + if isinstance(cbfun, Callable): + if Verbose: + print('_call_linker_cb: env["LINKCALLBACKS"][%r] is callable' % callback) + result = cbfun(env, *args) + return result + + +class _ShLibInfoSupport: + @property + def libtype(self): + return 'ShLib' + + def get_lib_prefix(self, env, *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) + + def get_lib_version(self, env, *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) + + +class _LdModInfoSupport: + @property + def libtype(self): + return 'LdMod' + + def get_lib_prefix(self, env, *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) + + def get_lib_version(self, env, *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) + + +class _ImpLibInfoSupport: + @property + def libtype(self): + return 'ImpLib' + + def get_lib_prefix(self, env, *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) + + def get_lib_version(self, env, *args, **kw): + version = _call_env_subst(env, '$IMPLIBVERSION', *args, **kw) + if not version: + try: + lt = kw['implib_libtype'] + except KeyError: + pass + else: + if lt == 'ShLib': + version = _call_env_subst(env, '$SHLIBVERSION', *args, **kw) + elif lt == 'LdMod': + version = _call_env_subst(env, '$LDMODULEVERSION', *args, **kw) + return version + + def get_lib_noversionsymlinks(self, env, *args, **kw): + disable = None + try: + env['IMPLIBNOVERSIONSYMLINKS'] + except KeyError: + try: + lt = kw['implib_libtype'] + except KeyError: + pass + else: + if lt == 'ShLib': + disable = _call_env_subst(env, '$SHLIBNOVERSIONSYMLINKS', *args, **kw) + elif lt == 'LdMod': + disable = _call_env_subst(env, '$LDMODULENOVERSIONSYMLINKS', *args, **kw) + else: + disable = _call_env_subst(env, '$IMPLIBNOVERSIONSYMLINKS', *args, **kw) + return disable + + +class _LibInfoGeneratorBase: + """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} + + def __init__(self, libtype, infoname): + self.libtype = libtype + self.infoname = infoname + + @property + def libtype(self): + return self._support.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_lib_prefix(self, 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) + + def get_lib_version(self, 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) + + def get_versioned_lib_info_generator(self, **kw): + """ + Returns name of generator linker callback that will 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'. + """ + 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): + 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): + Verbose = False + + if sources and 'source' not in kw: + kw2 = kw.copy() + kw2['source'] = sources + else: + kw2 = kw + + prefix = self.get_lib_prefix(env, **kw2) + if Verbose: + print("_LibPrefixGenerator: input prefix=%r" % prefix) + + version = self.get_lib_version(env, **kw2) + if Verbose: + print("_LibPrefixGenerator: version=%r" % version) + + if version: + prefix = self.generate_versioned_lib_info(env, [prefix, version], prefix, **kw2) + + if Verbose: + print("_LibPrefixGenerator: return prefix=%r" % prefix) + return prefix + + +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): + Verbose = False + + if sources and 'source' not in kw: + kw2 = kw.copy() + kw2['source'] = sources + else: + kw2 = kw + + suffix = self.get_lib_suffix(env, **kw2) + if Verbose: + print("_LibSuffixGenerator: input suffix=%r" % suffix) + + version = self.get_lib_version(env, **kw2) + if Verbose: + print("_LibSuffixGenerator: version=%r" % version) + + if version: + suffix = self.generate_versioned_lib_info(env, [suffix, version], suffix, **kw2) + + if Verbose: + print("_LibSuffixGenerator: return suffix=%r" % suffix) + return suffix + + +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') + + def __call__(self, env, libnode, **kw): + Verbose = False + + if libnode and 'target' not in kw: + kw2 = kw.copy() + kw2['target'] = libnode + else: + kw2 = kw + + if Verbose: + print("_LibSymLinkGenerator: libnode=%r" % libnode.get_path()) + + symlinks = None + + version = self.get_lib_version(env, **kw2) + disable = self.get_lib_noversionsymlinks(env, **kw2) + if Verbose: + print('_LibSymlinkGenerator: version=%r' % version) + print('_LibSymlinkGenerator: disable=%r' % disable) + + if version and not disable: + 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') +ImpLibSymlinkGenerator = _LibSymlinkGenerator('ImpLib') + + +class _LibNameGenerator(_LibInfoGeneratorBase): + """Generates "unmangled" library name from a library file node. + + Generally, it's thought to revert modifications done by prefix/suffix + generators (_LibPrefixGenerator/_LibSuffixGenerator) used by a library + builder. For example, on gnulink the suffix generator used by SharedLibrary + builder appends $SHLIBVERSION to $SHLIBSUFFIX producing node name which + ends with "$SHLIBSUFFIX.$SHLIBVERSION". Correspondingly, the implementation + of _LibNameGenerator replaces "$SHLIBSUFFIX.$SHLIBVERSION" with + "$SHLIBSUFFIX" in the node's basename. So that, if $SHLIBSUFFIX is ".so", + $SHLIBVERSION is "0.1.2" and the node path is "/foo/bar/libfoo.so.0.1.2", + 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') + + def __call__(self, env, libnode, **kw): + """Returns "demangled" library name""" + Verbose = False + + if libnode and 'target' not in kw: + kw2 = kw.copy() + kw2['target'] = libnode + else: + kw2 = kw + + if Verbose: + print("_LibNameGenerator: libnode=%r" % libnode.get_path()) + + version = self.get_lib_version(env, **kw2) + if Verbose: + print('_LibNameGenerator: version=%r' % version) + + name = None + if version: + 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: + name = os.path.basename(libnode.get_path()) + + if Verbose: + print('_LibNameGenerator: return name=%r' % name) + + return name + + +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') + + def __call__(self, env, libnode, **kw): + """Returns a SONAME based on a shared library's node path""" + Verbose = False + + if libnode and 'target' not in kw: + kw2 = kw.copy() + kw2['target'] = libnode + else: + kw2 = kw + + if Verbose: + print("_LibSonameGenerator: libnode=%r" % libnode.get_path()) + + soname = _call_env_subst(env, '$SONAME', **kw2) + if not soname: + 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) + 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.libtype)(env, libnode) + if Verbose: + print("_LibSonameGenerator: FALLBACK: soname=%r" % soname) + + if Verbose: + print("_LibSonameGenerator: return soname=%r" % soname) + + return soname + + +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 is_List(symlinks): + try: + 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])) + + clean_targets = kw.get('clean_targets', []) + if not is_List(clean_targets): + clean_targets = [clean_targets] + + for link, linktgt in symlinks: + env.SideEffect(link, linktgt) + 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: + 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 + nodes. + """ + + Verbose = False + for link, linktgt in symlinks: + linktgt = link.get_dir().rel_path(linktgt) + link = link.get_path() + 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: + 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: + 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) + 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) + 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)]) + except (KeyError, ValueError): + pass + else: + cmd += ": %s" % linkstr + return cmd + + +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 + return env.subst(string, *args, **kw2)
\ No newline at end of file diff --git a/SCons/Tool/linkloc.py b/SCons/Tool/linkloc.py index 0ca37b3..6ee5d61 100644 --- a/SCons/Tool/linkloc.py +++ b/SCons/Tool/linkloc.py @@ -34,7 +34,6 @@ selection method. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os.path import re import SCons.Action diff --git a/SCons/Tool/msginit.py b/SCons/Tool/msginit.py index a94cb85..4b72c30 100644 --- a/SCons/Tool/msginit.py +++ b/SCons/Tool/msginit.py @@ -28,7 +28,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.Warnings import SCons.Builder -import re ############################################################################# def _optional_no_translator_flag(env): diff --git a/SCons/Tool/msvc.py b/SCons/Tool/msvc.py index b9eb60a..a06a434 100644 --- a/SCons/Tool/msvc.py +++ b/SCons/Tool/msvc.py @@ -35,8 +35,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os.path import os -import re -import sys import SCons.Action import SCons.Builder diff --git a/SCons/Tool/packaging/rpm.py b/SCons/Tool/packaging/rpm.py index a026e45..cdeabcf 100644 --- a/SCons/Tool/packaging/rpm.py +++ b/SCons/Tool/packaging/rpm.py @@ -27,7 +27,6 @@ The rpm packager. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import os import SCons.Builder import SCons.Tool.rpmutils diff --git a/SCons/Tool/qt.py b/SCons/Tool/qt.py index fab1625..d8a51b2 100644 --- a/SCons/Tool/qt.py +++ b/SCons/Tool/qt.py @@ -35,7 +35,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os.path import re -import glob import SCons.Action import SCons.Builder diff --git a/SCons/Tool/textfile.py b/SCons/Tool/textfile.py index bb8a0f9..c1b597f 100644 --- a/SCons/Tool/textfile.py +++ b/SCons/Tool/textfile.py @@ -48,8 +48,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons -import os -import re from SCons.Node import Node from SCons.Node.Python import Value @@ -76,8 +74,8 @@ def _do_subst(node, subs): if 'b' in TEXTFILE_FILE_WRITE_MODE: try: contents = bytearray(contents, 'utf-8') - except UnicodeDecodeError: - # contents is already utf-8 encoded python 2 str i.e. a byte array + except TypeError: + # TODO: this should not happen, get_text_contents returns text contents = bytearray(contents) return contents diff --git a/SCons/Tool/wixTests.py b/SCons/Tool/wixTests.py index 6039115..5b255d9 100644 --- a/SCons/Tool/wixTests.py +++ b/SCons/Tool/wixTests.py @@ -26,7 +26,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import unittest import os.path import os -import sys import SCons.Errors from SCons.Tool.wix import * diff --git a/SCons/Tool/yacc.py b/SCons/Tool/yacc.py index 0b62305..ab019b2 100644 --- a/SCons/Tool/yacc.py +++ b/SCons/Tool/yacc.py @@ -50,14 +50,14 @@ if sys.platform == 'win32': else: BINS = ["bison", "yacc"] + def _yaccEmitter(target, source, env, ysuf, hsuf): yaccflags = env.subst("$YACCFLAGS", target=target, source=source) flags = SCons.Util.CLVar(yaccflags) targetBase, targetExt = os.path.splitext(SCons.Util.to_String(target[0])) - if '.ym' in ysuf: # If using Objective-C - target = [targetBase + ".m"] # the extension is ".m". - + if '.ym' in ysuf: # If using Objective-C + target = [targetBase + ".m"] # the extension is ".m". # If -d is specified on the command line, yacc will emit a .h # or .hpp file with the same name as the .c or .cpp output file. @@ -75,10 +75,8 @@ def _yaccEmitter(target, source, env, ysuf, hsuf): # be noted and also be cleaned # Bug #2558 if "-v" in flags: - env.SideEffect(targetBase+'.output',target[0]) - env.Clean(target[0],targetBase+'.output') - - + env.SideEffect(targetBase + '.output', target[0]) + env.Clean(target[0], targetBase + '.output') # With --defines and --graph, the name of the file is totally defined # in the options. @@ -94,15 +92,19 @@ def _yaccEmitter(target, source, env, ysuf, hsuf): return (target, source) + def yEmitter(target, source, env): return _yaccEmitter(target, source, env, ['.y', '.yacc'], '$YACCHFILESUFFIX') + def ymEmitter(target, source, env): return _yaccEmitter(target, source, env, ['.ym'], '$YACCHFILESUFFIX') + def yyEmitter(target, source, env): return _yaccEmitter(target, source, env, ['.yy'], '$YACCHXXFILESUFFIX') + def get_yacc_path(env, append_paths=False): """ Find the path to the yacc tool, searching several possible names @@ -118,7 +120,7 @@ def get_yacc_path(env, append_paths=False): bin_path = SCons.Tool.find_program_path( env, prog, - default_paths=CHOCO_DEFAULT_PATH + MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS ) + default_paths=CHOCO_DEFAULT_PATH + MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS) if bin_path: if append_paths: env.AppendENVPath('PATH', os.path.dirname(bin_path)) @@ -149,14 +151,20 @@ def generate(env): # ignore the return, all we need is for the path to be added _ = get_yacc_path(env, append_paths=True) - env["YACC"] = env.Detect(BINS) + if 'YACC' not in env: + env["YACC"] = env.Detect(BINS) + env['YACCFLAGS'] = SCons.Util.CLVar('') - env['YACCCOM'] = '$YACC $YACCFLAGS -o $TARGET $SOURCES' + env['YACCCOM'] = '$YACC $YACCFLAGS -o $TARGET $SOURCES' env['YACCHFILESUFFIX'] = '.h' env['YACCHXXFILESUFFIX'] = '.hpp' env['YACCVCGFILESUFFIX'] = '.vcg' + def exists(env): + if 'YACC' in env: + return env.Detect(env['YACC']) + if sys.platform == 'win32': return get_yacc_path(env) else: diff --git a/SCons/Tool/zip.py b/SCons/Tool/zip.py index 23d540f..cbf2c16 100644 --- a/SCons/Tool/zip.py +++ b/SCons/Tool/zip.py @@ -42,7 +42,9 @@ import SCons.Util import zipfile -zipcompression = zipfile.ZIP_DEFLATED +zip_compression = zipfile.ZIP_DEFLATED + + def zip(target, source, env): compression = env.get('ZIPCOMPRESSION', 0) zf = zipfile.ZipFile(str(target[0]), 'w', compression) @@ -52,19 +54,20 @@ def zip(target, source, env): for fname in filenames: path = os.path.join(dirpath, fname) if os.path.isfile(path): - zf.write(path, os.path.relpath(path, str(env.get('ZIPROOT', '')))) else: zf.write(str(s), os.path.relpath(str(s), str(env.get('ZIPROOT', '')))) zf.close() -zipAction = SCons.Action.Action(zip, varlist=['ZIPCOMPRESSION']) +# Fix PR #3569 - If you don't specify ZIPCOM and ZIPCOMSTR when creating +# env, then it will ignore ZIPCOMSTR set afterwards. +zipAction = SCons.Action.Action(zip, "$ZIPCOMSTR", varlist=['ZIPCOMPRESSION']) -ZipBuilder = SCons.Builder.Builder(action = SCons.Action.Action('$ZIPCOM', '$ZIPCOMSTR'), - source_factory = SCons.Node.FS.Entry, - source_scanner = SCons.Defaults.DirScanner, - suffix = '$ZIPSUFFIX', - multi = 1) +ZipBuilder = SCons.Builder.Builder(action=SCons.Action.Action('$ZIPCOM', '$ZIPCOMSTR'), + source_factory=SCons.Node.FS.Entry, + source_scanner=SCons.Defaults.DirScanner, + suffix='$ZIPSUFFIX', + multi=1) def generate(env): @@ -75,12 +78,13 @@ def generate(env): bld = ZipBuilder env['BUILDERS']['Zip'] = bld - env['ZIP'] = 'zip' - env['ZIPFLAGS'] = SCons.Util.CLVar('') - env['ZIPCOM'] = zipAction - env['ZIPCOMPRESSION'] = zipcompression - env['ZIPSUFFIX'] = '.zip' - env['ZIPROOT'] = SCons.Util.CLVar('') + env['ZIP'] = 'zip' + env['ZIPFLAGS'] = SCons.Util.CLVar('') + env['ZIPCOM'] = zipAction + env['ZIPCOMPRESSION'] = zip_compression + env['ZIPSUFFIX'] = '.zip' + env['ZIPROOT'] = SCons.Util.CLVar('') + def exists(env): return True |