Skip to content

Instantly share code, notes, and snippets.

@bdbaddog
Created June 14, 2021 19:16
Show Gist options
  • Save bdbaddog/e35f91166bfe1a74ccb7b44ef4e0d345 to your computer and use it in GitHub Desktop.
Save bdbaddog/e35f91166bfe1a74ccb7b44ef4e0d345 to your computer and use it in GitHub Desktop.
diff --git a/SCons/Defaults.py b/SCons/Defaults.py
index c59fbcffa..2bacc1073 100644
--- a/SCons/Defaults.py
+++ b/SCons/Defaults.py
@@ -31,12 +31,12 @@ The code that reads the registry to find MSVC components was borrowed
from distutils.msvccompiler.
"""
-import os
import errno
+import os
import shutil
import stat
-import time
import sys
+import time
import SCons.Action
import SCons.Builder
@@ -52,6 +52,7 @@ import SCons.Tool
# interface.
_default_env = None
+
# Lazily instantiate the default environment so the overhead of creating
# it doesn't apply when it's not needed.
def _fetch_DefaultEnvironment(*args, **kw):
@@ -59,6 +60,7 @@ def _fetch_DefaultEnvironment(*args, **kw):
global _default_env
return _default_env
+
def DefaultEnvironment(*args, **kw):
"""
Initial public entry point for creating the default construction
@@ -88,6 +90,7 @@ def DefaultEnvironment(*args, **kw):
_default_env._CacheDir_path = None
return _default_env
+
# Emitters for setting the shared attribute on object files,
# and an action for checking that all of the source files
# going into a shared library are, in fact, shared.
@@ -96,11 +99,13 @@ def StaticObjectEmitter(target, source, env):
tgt.attributes.shared = None
return (target, source)
+
def SharedObjectEmitter(target, source, env):
for tgt in target:
tgt.attributes.shared = 1
return (target, source)
+
def SharedFlagChecker(source, target, env):
same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
if same == '0' or same == '' or same == 'False':
@@ -110,7 +115,9 @@ def SharedFlagChecker(source, target, env):
except AttributeError:
shared = None
if not shared:
- raise SCons.Errors.UserError("Source file: %s is static and is not compatible with shared target: %s" % (src, target[0]))
+ raise SCons.Errors.UserError(
+ "Source file: %s is static and is not compatible with shared target: %s" % (src, target[0]))
+
SharedCheck = SCons.Action.Action(SharedFlagChecker, None)
@@ -128,6 +135,7 @@ ProgScan = SCons.Tool.ProgramScanner
# the rest of those in Tool/__init__.py, but I'm not sure where else
# they should go. Leave them here for now.
import SCons.Scanner.Dir
+
DirScanner = SCons.Scanner.Dir.DirScanner()
DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner()
@@ -152,6 +160,7 @@ LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
# ways by creating ActionFactory instances.
ActionFactory = SCons.Action.ActionFactory
+
def get_paths_str(dest):
# If dest is a list, we need to manually call str() on each element
if SCons.Util.is_List(dest):
@@ -162,24 +171,26 @@ def get_paths_str(dest):
else:
return '"' + str(dest) + '"'
+
permission_dic = {
- 'u':{
- 'r':stat.S_IRUSR,
- 'w':stat.S_IWUSR,
- 'x':stat.S_IXUSR
+ 'u': {
+ 'r': stat.S_IRUSR,
+ 'w': stat.S_IWUSR,
+ 'x': stat.S_IXUSR
},
- 'g':{
- 'r':stat.S_IRGRP,
- 'w':stat.S_IWGRP,
- 'x':stat.S_IXGRP
+ 'g': {
+ 'r': stat.S_IRGRP,
+ 'w': stat.S_IWGRP,
+ 'x': stat.S_IXGRP
},
- 'o':{
- 'r':stat.S_IROTH,
- 'w':stat.S_IWOTH,
- 'x':stat.S_IXOTH
+ 'o': {
+ 'r': stat.S_IROTH,
+ 'w': stat.S_IWOTH,
+ 'x': stat.S_IXOTH
}
}
+
def chmod_func(dest, mode):
import SCons.Util
from string import digits
@@ -223,6 +234,7 @@ def chmod_func(dest, mode):
elif operator == "-":
os.chmod(str(element), curr_perm & ~new_perm)
+
def chmod_strfunc(dest, mode):
import SCons.Util
if not SCons.Util.is_String(mode):
@@ -230,8 +242,10 @@ def chmod_strfunc(dest, mode):
else:
return 'Chmod(%s, "%s")' % (get_paths_str(dest), str(mode))
+
Chmod = ActionFactory(chmod_func, chmod_strfunc)
+
def copy_func(dest, src, symlinks=True):
"""
If symlinks (is true), then a symbolic link will be
@@ -262,11 +276,13 @@ def copy_func(dest, src, symlinks=True):
# A error is raised in both cases, so we can just return 0 for success
return 0
+
Copy = ActionFactory(
copy_func,
lambda dest, src, symlinks=True: 'Copy("%s", "%s")' % (dest, src)
)
+
def delete_func(dest, must_exist=0):
SCons.Node.FS.invalidate_node_memos(dest)
if not SCons.Util.is_List(dest):
@@ -283,11 +299,14 @@ def delete_func(dest, must_exist=0):
continue
os.unlink(entry)
+
def delete_strfunc(dest, must_exist=0):
return 'Delete(%s)' % get_paths_str(dest)
+
Delete = ActionFactory(delete_func, delete_strfunc)
+
def mkdir_func(dest):
SCons.Node.FS.invalidate_node_memos(dest)
if not SCons.Util.is_List(dest):
@@ -298,24 +317,28 @@ def mkdir_func(dest):
except os.error as e:
p = str(entry)
if (e.args[0] == errno.EEXIST or
- (sys.platform=='win32' and e.args[0]==183)) \
+ (sys.platform == 'win32' and e.args[0] == 183)) \
and os.path.isdir(str(entry)):
- pass # not an error if already exists
+ pass # not an error if already exists
else:
raise
+
Mkdir = ActionFactory(mkdir_func,
lambda dir: 'Mkdir(%s)' % get_paths_str(dir))
+
def move_func(dest, src):
SCons.Node.FS.invalidate_node_memos(dest)
SCons.Node.FS.invalidate_node_memos(src)
shutil.move(src, dest)
+
Move = ActionFactory(move_func,
lambda dest, src: 'Move("%s", "%s")' % (dest, src),
convert=str)
+
def touch_func(dest):
SCons.Node.FS.invalidate_node_memos(dest)
if not SCons.Util.is_List(dest):
@@ -330,9 +353,11 @@ def touch_func(dest):
atime = mtime
os.utime(file, (atime, mtime))
+
Touch = ActionFactory(touch_func,
lambda file: 'Touch(%s)' % get_paths_str(file))
+
# Internal utility functions
@@ -386,7 +411,7 @@ def _concat_ixes(prefix, list, suffix, env):
if suffix[0] == ' ':
result.append(suffix[1:])
elif x[-len(suffix):] != suffix:
- result[-1] = result[-1]+suffix
+ result[-1] = result[-1] + suffix
return result
@@ -443,6 +468,7 @@ def _stripixes(prefix, itms, suffix, stripprefixes, stripsuffixes, env, c=None):
return c(prefix, stripped, suffix, env)
+
def processDefines(defs):
"""process defines, resolving strings, lists, dictionaries, into a list of
strings
@@ -458,7 +484,7 @@ def processDefines(defs):
else:
l.append(str(d[0]))
elif SCons.Util.is_Dict(d):
- for macro,value in d.items():
+ for macro, value in d.items():
if value is not None:
l.append(str(macro) + '=' + str(value))
else:
@@ -466,7 +492,7 @@ def processDefines(defs):
elif SCons.Util.is_String(d):
l.append(str(d))
else:
- raise SCons.Errors.UserError("DEFINE %s is not a list, dict, string or None."%repr(d))
+ raise SCons.Errors.UserError("DEFINE %s is not a list, dict, string or None." % repr(d))
elif SCons.Util.is_Dict(defs):
# The items in a dictionary are stored in random order, but
# if the order of the command-line options changes from
@@ -475,7 +501,7 @@ def processDefines(defs):
# Consequently, we have to sort the keys to ensure a
# consistent order...
l = []
- for k,v in sorted(defs.items()):
+ for k, v in sorted(defs.items()):
if v is None:
l.append(str(k))
else:
@@ -524,11 +550,14 @@ class Variable_Method_Caller:
the way of Memoizing construction environments, because we had to
create new environment objects to hold the variables.)
"""
+
def __init__(self, variable, method):
self.variable = variable
self.method = method
+
def __call__(self, *args, **kw):
- try: 1//0
+ try:
+ 1 // 0
except ZeroDivisionError:
# Don't start iterating with the current stack-frame to
# prevent creating reference cycles (f_back is safe).
@@ -543,6 +572,7 @@ class Variable_Method_Caller:
frame = frame.f_back
return None
+
def __libversionflags(env, version_var, flags_var):
"""
if $version_var is not empty, returns env[flags_var], otherwise returns None
@@ -552,42 +582,59 @@ def __libversionflags(env, version_var, flags_var):
:return:
"""
try:
- if env.subst('$'+version_var):
+ if env.subst('$' + version_var):
return env[flags_var]
except KeyError:
pass
return None
+def __lib_either_version_flag(env, version_var1, version_var2, flags_var):
+ """
+ if $version_var1 or $version_var2 is not empty, returns env[flags_var], otherwise returns None
+ :param env:
+ :param version_var1:
+ :param version_var2:
+ :param flags_var:
+ :return:
+ """
+ try:
+ if env.subst('$' + version_var1) or env.subst('$' + version_var2):
+ return env[flags_var]
+ except KeyError:
+ pass
+ return None
+
ConstructionEnvironment = {
- 'BUILDERS' : {},
- 'SCANNERS' : [ SCons.Tool.SourceFileScanner ],
- 'CONFIGUREDIR' : '#/.sconf_temp',
- 'CONFIGURELOG' : '#/config.log',
- 'CPPSUFFIXES' : SCons.Tool.CSuffixes,
- 'DSUFFIXES' : SCons.Tool.DSuffixes,
- 'ENV' : {},
- 'IDLSUFFIXES' : SCons.Tool.IDLSuffixes,
- '_concat' : _concat,
- '_defines' : _defines,
- '_stripixes' : _stripixes,
- '_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
- '_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
- '_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
- '_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
-
- '__libversionflags' : __libversionflags,
- '__SHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}',
- '__LDMODULEVERSIONFLAGS' : '${__libversionflags(__env__,"LDMODULEVERSION","_LDMODULEVERSIONFLAGS")}',
- '__DSHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}',
-
- 'TEMPFILE' : NullCmdGenerator,
+ 'BUILDERS': {},
+ 'SCANNERS': [SCons.Tool.SourceFileScanner],
+ 'CONFIGUREDIR': '#/.sconf_temp',
+ 'CONFIGURELOG': '#/config.log',
+ 'CPPSUFFIXES': SCons.Tool.CSuffixes,
+ 'DSUFFIXES': SCons.Tool.DSuffixes,
+ 'ENV': {},
+ 'IDLSUFFIXES': SCons.Tool.IDLSuffixes,
+ '_concat': _concat,
+ '_defines': _defines,
+ '_stripixes': _stripixes,
+ '_LIBFLAGS': '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
+ '_LIBDIRFLAGS': '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
+ '_CPPINCFLAGS': '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
+ '_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
+
+ '__libversionflags': __libversionflags,
+ '__SHLIBVERSIONFLAGS': '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}',
+ '__LDMODULEVERSIONFLAGS': '${__libversionflags(__env__,"LDMODULEVERSION","_LDMODULEVERSIONFLAGS")}',
+ '__DSHLIBVERSIONFLAGS': '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}',
+ '__lib_either_version_flag': __lib_either_version_flag,
+
+ 'TEMPFILE': NullCmdGenerator,
'TEMPFILEARGJOIN': ' ',
- 'Dir' : Variable_Method_Caller('TARGET', 'Dir'),
- 'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'),
- 'File' : Variable_Method_Caller('TARGET', 'File'),
- 'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'),
+ 'Dir': Variable_Method_Caller('TARGET', 'Dir'),
+ 'Dirs': Variable_Method_Caller('TARGET', 'Dirs'),
+ 'File': Variable_Method_Caller('TARGET', 'File'),
+ 'RDirs': Variable_Method_Caller('TARGET', 'RDirs'),
}
# Local Variables:
diff --git a/SCons/Tool/__init__.py b/SCons/Tool/__init__.py
index 87139f178..7c78dbab8 100644
--- a/SCons/Tool/__init__.py
+++ b/SCons/Tool/__init__.py
@@ -50,8 +50,7 @@ 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
+from SCons.Tool.linkCommon import LibSymlinksActionFunction, LibSymlinksStrFun
DefaultToolpath = []
@@ -348,8 +347,8 @@ def createSharedLibBuilder(env):
LibSymlinksAction]
shared_lib = SCons.Builder.Builder(action=action_list,
emitter="$SHLIBEMITTER",
- prefix=ShLibPrefixGenerator,
- suffix=ShLibSuffixGenerator,
+ prefix="$SHLIBPREFIX",
+ suffix="$_SHLIBSUFFIX",
target_scanner=ProgramScanner,
src_suffix='$SHOBJSUFFIX',
src_builder='SharedObject')
@@ -374,8 +373,8 @@ def createLoadableModuleBuilder(env):
LibSymlinksAction]
ld_module = SCons.Builder.Builder(action=action_list,
emitter="$LDMODULEEMITTER",
- prefix=LdModPrefixGenerator,
- suffix=LdModSuffixGenerator,
+ prefix="$LDMODULEPREFIX",
+ suffix="$_LDMODULESUFFIX",
target_scanner=ProgramScanner,
src_suffix='$SHOBJSUFFIX',
src_builder='SharedObject')
diff --git a/SCons/Tool/applelink.py b/SCons/Tool/applelink.py
index f51a6af52..6a4a37cc2 100644
--- a/SCons/Tool/applelink.py
+++ b/SCons/Tool/applelink.py
@@ -8,6 +8,10 @@ selection method.
"""
+#
+# MIT License
+#
+# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -29,14 +33,14 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-import SCons.Tool.linkCommon
-import SCons.Util
-
# Even though the Mac is based on the GNU toolchain, it doesn't understand
# the -rpath option, so we use the "link" tool instead of "gnulink".
+from SCons.Util import CLVar
+
from . import link
-from .linkCommon import ShLibSonameGenerator
+# User programmatically describes how SHLIBVERSION maps to values for compat/current.
+_APPLELIB_MAX_VERSION_VALUES = (65535, 255, 255)
class AppleLinkInvalidCurrentVersionException(Exception):
@@ -47,49 +51,6 @@ class AppleLinkInvalidCompatibilityVersionException(Exception):
pass
-def _applelib_versioned_lib_suffix(env, suffix, version):
- """For suffix='.dylib' and version='0.1.2' it returns '.0.1.2.dylib'"""
- Verbose = False
- if Verbose:
- print("_applelib_versioned_lib_suffix: suffix={!r}".format(suffix))
- print("_applelib_versioned_lib_suffix: version={!r}".format(version))
- if version not in suffix:
- suffix = "." + version + suffix
- if Verbose:
- print("_applelib_versioned_lib_suffix: return suffix={!r}".format(suffix))
- return suffix
-
-
-def _applelib_versioned_lib_soname(env, libnode, version, prefix, suffix, name_func):
- """For libnode='/optional/dir/libfoo.X.Y.Z.dylib' it returns 'libfoo.X.dylib'"""
- Verbose = False
- if Verbose:
- print("_applelib_versioned_lib_soname: version={!r}".format(version))
- name = name_func(env, libnode, version, prefix, suffix)
- if Verbose:
- print("_applelib_versioned_lib_soname: name={!r}".format(name))
- major = version.split('.')[0]
- (libname, _suffix) = name.split('.')
- # if a desired SONAME was supplied, use that, otherwise create
- # a default from the major version
- if env.get('SONAME'):
- soname = ShLibSonameGenerator(env, libnode)
- else:
- soname = '.'.join([libname, major, _suffix])
- if Verbose:
- 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,
- SCons.Tool.linkCommon._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.
@@ -111,9 +72,9 @@ def _applelib_check_valid_version(version_string):
p_i = int(p)
except ValueError:
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]:
+ 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])
+ p, version_string, _APPLELIB_MAX_VERSION_VALUES[i])
return True, ""
@@ -191,15 +152,9 @@ def generate(env):
env['_FRAMEWORKS'] = '${_concat("-framework ", FRAMEWORKS, "", __env__)}'
env['LINKCOM'] = env['LINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
- env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -dynamiclib')
+ env['SHLINKFLAGS'] = CLVar('$LINKFLAGS -dynamiclib')
env['SHLINKCOM'] = env['SHLINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
- # see: http://docstore.mik.ua/orelly/unix3/mac/ch05_04.htm for proper naming
- SCons.Tool.linkCommon._setup_versioned_lib_variables(env, tool='applelink', use_soname=True)
- env['LINKCALLBACKS'] = SCons.Tool.linkCommon._versioned_lib_callbacks()
- env['LINKCALLBACKS']['VersionedShLibSuffix'] = _applelib_versioned_lib_suffix
- env['LINKCALLBACKS']['VersionedShLibSoname'] = _applelib_versioned_shlib_soname
-
env['_APPLELINK_CURRENT_VERSION'] = _applelib_currentVersionFromSoVersion
env['_APPLELINK_COMPATIBILITY_VERSION'] = _applelib_compatVersionFromSoVersion
env['_SHLIBVERSIONFLAGS'] = '$_APPLELINK_CURRENT_VERSION $_APPLELINK_COMPATIBILITY_VERSION '
@@ -210,10 +165,21 @@ def generate(env):
# pre/suffixes:
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")}'
+ env['LDMODULEFLAGS'] = CLVar('$LINKFLAGS -bundle')
+ env[
+ 'LDMODULECOM'] = '$LDMODULE -o ${TARGET} $LDMODULEFLAGS' \
+ ' $SOURCES $_LIBDIRFLAGS $_LIBFLAGS $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
+
+ # New stuff
+ #
+ env['_SHLIBSUFFIX'] = '${_SHLIBVERSION}${SHLIBSUFFIX}'
+
+ env[
+ '__SHLIBVERSIONFLAGS'] = '${__lib_either_version_flag(__env__,' \
+ '"SHLIBVERSION","_APPLELINK_CURRENT_VERSION", "_SHLIBVERSIONFLAGS")}'
+ env[
+ '__LDMODULEVERSIONFLAGS'] = '${__lib_either_version_flag(__env__,' \
+ '"LDMODULEVERSION","_APPLELINK_CURRENT_VERSION", "_LDMODULEVERSIONFLAGS")}'
def exists(env):
diff --git a/SCons/Tool/cyglink.py b/SCons/Tool/cyglink.py
index 595cc2e5d..1995ac326 100644
--- a/SCons/Tool/cyglink.py
+++ b/SCons/Tool/cyglink.py
@@ -8,211 +8,153 @@ selection method.
"""
-import re
-import os
-
-import SCons.Action
-import SCons.Tool.linkCommon as linkCommon
-from SCons.Tool.linkCommon import ImpLibSymlinkGenerator, StringizeLibSymlinks, EmitLibSymlinks, ImpLibPrefixGenerator, \
- ImpLibSuffixGenerator, ImpLibNameGenerator
-import SCons.Util
-import SCons.Tool
-
+from SCons.Tool.linkCommon import StringizeLibSymlinks, EmitLibSymlinks
+from SCons.Util import CLVar
from . import gnulink
-def _lib_generator(target, source, env, for_signature, **kw):
- try:
- cmd = kw['cmd']
- except KeyError:
- cmd = SCons.Util.CLVar(['$SHLINK'])
-
- try:
- vp = kw['varprefix']
- except KeyError:
- vp = 'SHLIB'
-
- dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp)
- if dll: cmd.extend(['-o', dll])
+def cyglink_lib_emitter(target, source, env, **kw):
+ verbose = True
- cmd.extend(['$SHLINKFLAGS', '$__%sVERSIONFLAGS' % vp, '$__RPATH'])
-
- implib = env.FindIxes(target, 'IMPLIBPREFIX', 'IMPLIBSUFFIX')
- if implib:
- cmd.extend([
- '-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'
- ])
+ if 'variable_prefix' in kw:
+ var_prefix = kw['variable_prefix']
else:
- cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS'])
-
- return [cmd]
-
+ var_prefix = 'SHLIB'
-def shlib_generator(target, source, env, for_signature):
- return _lib_generator(target, source, env, for_signature,
- varprefix='SHLIB',
- cmd=SCons.Util.CLVar(['$SHLINK']))
+ no_import_lib = env.get('no_import_lib', False)
+ if verbose:
+ print("cyglink_lib_emitter: target[0]={!r}".format(target[0].get_path()))
-def ldmod_generator(target, source, env, for_signature):
- return _lib_generator(target, source, env, for_signature,
- varprefix='LDMODULE',
- cmd=SCons.Util.CLVar(['$LDMODULE']))
-
-
-def _lib_emitter(target, source, env, **kw):
- Verbose = False
-
- if Verbose:
- print("_lib_emitter: target[0]=%r" % target[0].get_path())
+ if not no_import_lib:
+ # Specify import lib and add to targets
- try:
- vp = kw['varprefix']
- except KeyError:
- vp = 'SHLIB'
+ import_lib = env.subst('$%s_IMPLIBNAME' % var_prefix, target=target, source=source)
+ import_lib_target = env.fs.File(import_lib)
+ import_lib_target.attributes.shared = 1
+ target.append(import_lib_target)
- try:
- libtype = kw['libtype']
- except KeyError:
- libtype = 'ShLib'
+ if verbose:
+ print("cyglink_lib_emitter: import_lib={}".format(import_lib))
+ print("cyglink_lib_emitter: target=%s" % target)
- dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp)
- no_import_lib = env.get('no_import_lib', 0)
+ for tgt in target:
+ if is_String(tgt):
+ tgt = env.File(tgt)
+ tgt.attributes.shared = 1
- if Verbose:
- print("_lib_emitter: dll=%r" % dll.get_path())
+ return target, source
- 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))
- # 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:]
+def cyglink_ldmodule_emitter(target, source, env, **kw):
+ return cyglink_lib_emitter(target, source, env, variable_prefix='LDMODULE')
- if Verbose:
- print("_lib_emitter: dll.name=%r" % dll.name)
- orig_target = target
- target = [env.fs.File(dll)]
- target[0].attributes.shared = 1
+def cyglink_shlib_symlink_emitter(target, source, env, **kw):
+ """
+ On cygwin, we only create a symlink from the non-versioned implib to the versioned implib.
+ We don't version the shared library itself.
+ :param target:
+ :param source:
+ :param env:
+ :param kw:
+ :return:
+ """
+ verbose = True
- if Verbose:
- print("_lib_emitter: after target=[env.fs.File(dll)]: target[0]=%r" % target[0].get_path())
+ if 'variable_prefix' in kw:
+ var_prefix = kw['variable_prefix']
+ else:
+ var_prefix = 'SHLIB'
- # Append an import lib target
- if not no_import_lib:
- # Create list of target libraries as strings
- target_strings = env.ReplaceIxes(orig_target[0],
- '%sPREFIX' % vp, '%sSUFFIX' % vp,
- 'IMPLIBPREFIX', 'IMPLIBSUFFIX')
- if Verbose:
- print("_lib_emitter: target_strings=%r" % target_strings)
-
- implib_target = env.fs.File(target_strings)
- if Verbose:
- print("_lib_emitter: implib_target=%r" % implib_target.get_path())
- implib_target.attributes.shared = 1
- target.append(implib_target)
-
- # Only create the symlinks if there is actually an import library
- symlinks = ImpLibSymlinkGenerator(env, implib_target,
- implib_libtype=libtype,
- generator_libtype=libtype + 'ImpLib')
- if Verbose:
- print("_lib_emitter: implib symlinks=%r" % StringizeLibSymlinks(symlinks))
- if symlinks:
- EmitLibSymlinks(env, symlinks, implib_target, clean_targets=target[0])
- implib_target.attributes.shliblinks = symlinks
+ no_import_lib = env.get('no_import_lib', False)
+ if no_import_lib in ['1', 'True', 'true', True]:
+ if verbose:
+ print("cyglink_shlib_symlink_emitter: no_import_lib=%s" % no_import_lib)
+ return target, source
- return (target, source)
+ no_symlinks = env.subst('$%sNOVERSIONSYMLINKS' % var_prefix)
+ if no_symlinks in ['1', 'True', 'true', True]:
+ return target, source
+ shlibversion = env.subst('$%sVERSION' % var_prefix)
+ if shlibversion:
+ if verbose:
+ print("cyglink_shlib_symlink_emitter: %sVERSION=%s" % (var_prefix, shlibversion))
-def shlib_emitter(target, source, env):
- return _lib_emitter(target, source, env, varprefix='SHLIB', libtype='ShLib')
+ # The implib (added by the cyglink_lib_emitter)
+ imp_lib_node = target[1]
+ shlib_noversion_symlink = env.subst('$%s_NOVERSION_SYMLINK' % var_prefix, target=target[0], source=source)
+ if verbose:
+ print("cyglink_shlib_symlink_emitter: shlib_noversion_symlink :%s" % shlib_noversion_symlink)
+ print("cyglink_shlib_symlink_emitter: imp_lib_node :%s" % imp_lib_node)
-def ldmod_emitter(target, source, env):
- return _lib_emitter(target, source, env, varprefix='LDMODULE', libtype='LdMod')
+ symlinks = [(env.File(shlib_noversion_symlink), imp_lib_node)]
+ if verbose:
+ print("cyglink_shlib_symlink_emitter: symlinks={!r}".format(
+ ', '.join(["%r->%r" % (k, v) for k, v in StringizeLibSymlinks(symlinks)])
+ ))
-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'"""
- Verbose = False
- if Verbose:
- print("_versioned_lib_suffix: suffix= ", suffix)
- print("_versioned_lib_suffix: version= ", version)
- cygversion = re.sub(r'\.', '-', version)
- if not suffix.startswith('-' + cygversion):
- suffix = '-' + cygversion + suffix
- if Verbose:
- print("_versioned_lib_suffix: return suffix= ", suffix)
- return suffix
+ if symlinks:
+ # This does the actual symlinking
+ EmitLibSymlinks(env, symlinks, target[0])
+ # This saves the information so if the versioned shared library is installed
+ # it can faithfully reproduce the correct symlinks
+ target[0].attributes.shliblinks = symlinks
-def _versioned_implib_name(env, libnode, version, prefix, suffix, **kw):
- return linkCommon._versioned_lib_name(env, libnode, version, prefix, suffix,
- ImpLibPrefixGenerator,
- ImpLibSuffixGenerator,
- implib_libtype=kw['libtype'])
+ return target, source
-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), ... ]
- """
- Verbose = False
+def cyglink_ldmod_symlink_emitter(target, source, env, **kw):
+ return cyglink_shlib_symlink_emitter(target, source, env, variable_prefix='LDMODULE')
- if Verbose:
- print("_versioned_implib_symlinks: libnode=%r" % libnode.get_path())
- print("_versioned_implib_symlinks: version=%r" % version)
- try:
- libtype = kw['libtype']
- except KeyError:
- libtype = 'ShLib'
+def cyglink_shlibversion(target, source, env, for_signature):
+ var_prefix = 'SHLIB'
+ var = '%sVERSION' % var_prefix
+ if var not in env:
+ return ''
- linkdir = os.path.dirname(libnode.get_path())
- if Verbose:
- print("_versioned_implib_symlinks: linkdir=%r" % linkdir)
+ version = env.subst("$%s" % var, target=target, source=source)
+ version = version.replace('.', '-')
+ return "." + version
- name = ImpLibNameGenerator(env, libnode,
- implib_libtype=libtype,
- generator_libtype=libtype + 'ImpLib')
- if Verbose:
- print("_versioned_implib_symlinks: name=%r" % name)
- major = version.split('.')[0]
+def cyglink_ldmodule_version(target, source, env, for_signature):
+ var_prefix = 'LDMODULE'
+ var = '%sVERSION' % var_prefix
+ if var not in env:
+ return ''
- link0 = env.fs.File(os.path.join(linkdir, name))
- symlinks = [(link0, libnode)]
+ version = env.subst("$%s" % var, target=target, source=source)
+ version = version.replace('.', '-')
+ return "." + version
- if Verbose:
- print("_versioned_implib_symlinks: return symlinks=%r" % StringizeLibSymlinks(symlinks))
- return symlinks
+def _implib_pre_flags(target, source, env, for_signature):
+ no_import_lib = env.get('no_import_lib', False)
+ if no_import_lib in ['1', 'True', 'true', True]:
+ return ''
+ else:
+ return '-Wl,--out-implib=${TARGETS[1]} -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive'
-shlib_action = SCons.Action.Action(shlib_generator, generator=1)
-ldmod_action = SCons.Action.Action(ldmod_generator, generator=1)
+def _implib_post_flags(target, source, env, for_signature):
+ no_import_lib = env.get('no_import_lib', False)
+ if no_import_lib in ['1', 'True', 'true', True]:
+ return ''
+ else:
+ return '-Wl,--no-whole-archive'
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['SHLINKCOM'] = shlib_action
- env['LDMODULECOM'] = ldmod_action
- env.Append(SHLIBEMITTER=[shlib_emitter])
- env.Append(LDMODULEEMITTER=[ldmod_emitter])
+ env['LINKFLAGS'] = CLVar('-Wl,-no-undefined')
env['SHLIBPREFIX'] = 'cyg'
env['SHLIBSUFFIX'] = '.dll'
@@ -221,33 +163,43 @@ def generate(env):
env['IMPLIBSUFFIX'] = '.dll.a'
# Variables used by versioned shared libraries
+ # SHLIBVERSIONFLAGS and LDMODULEVERSIONFLAGS are same as in gnulink...
env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS'
env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS'
- # SHLIBVERSIONFLAGS and LDMODULEVERSIONFLAGS are same as in gnulink...
+ env['_IMPLIB_PRE_SOURCES'] = _implib_pre_flags
+ env['_IMPLIB_POST_SOURCES'] = _implib_post_flags
+ env['SHLINKCOM'] = '$SHLINK -o $TARGET $SHLINKFLAGS $__SHLIBVERSIONFLAGS $__RPATH ' \
+ '$_IMPLIB_PRE_SOURCES $SOURCES $_IMPLIB_POST_SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
+ env['LDMODULECOM'] = '$LDMODULE -o $TARGET $SHLINKFLAGS $__LDMODULEVERSIONFLAGS $__RPATH ' \
+ '$_IMPLIB_PRE_SOURCES $SOURCES $_IMPLIB_POST_SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
+
+ # Overwrite emitters. Cyglink does things differently when creating symlinks
+ env['SHLIBEMITTER'] = [cyglink_lib_emitter, cyglink_shlib_symlink_emitter]
+ env['LDMODULEEMITTER'] = [cyglink_ldmodule_emitter, cyglink_ldmod_symlink_emitter]
+
+ # This is the non versioned shlib filename
+ # If SHLIBVERSION is defined then this will symlink to $SHLIBNAME
+ env['SHLIB_NOVERSION_SYMLINK'] = '${IMPLIBPREFIX}$_get_shlib_stem${IMPLIBSUFFIX}'
+ env['LDMODULE_NOVERSION_SYMLINK'] = '${IMPLIBPREFIX}$_get_ldmodule_stem${IMPLIBSUFFIX}'
+
+ env['SHLIB_IMPLIBNAME'] = '${IMPLIBPREFIX}$_get_shlib_stem${_SHLIB_IMPLIBSUFFIX}'
+ env['LDMODULE_IMPLIBNAME'] = '${IMPLIBPREFIX}$_get_ldmodule_stem${_LDMODULE_IMPLIBSUFFIX}'
+
+ env['_cyglink_shlibversion'] = cyglink_shlibversion
+ env['_SHLIB_IMPLIBSUFFIX'] = '${_cyglink_shlibversion}${IMPLIBSUFFIX}'
+ env['_SHLIBSUFFIX'] = '${_cyglink_shlibversion}${SHLIBSUFFIX}'
+
+ env['_cyglink_ldmodule_version'] = cyglink_ldmodule_version
- # LINKCALLBACKS are NOT inherited from gnulink
- env['LINKCALLBACKS'] = {
- 'VersionedShLibSuffix': _versioned_lib_suffix,
- 'VersionedLdModSuffix': _versioned_lib_suffix,
- 'VersionedImpLibSuffix': _versioned_lib_suffix,
- 'VersionedShLibName': linkCommon._versioned_shlib_name,
- 'VersionedLdModName': linkCommon._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'),
- }
+ env['_LDMODULESUFFIX'] = '${_cyglink_ldmodule_version}${LDMODULESUFFIX}'
+ env['_LDMODULE_IMPLIBSUFFIX'] = '${_cyglink_ldmodule_version}${IMPLIBSUFFIX}'
+ # Remove variables set by default initialization which aren't needed/used by cyglink
# 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
+ for rv in ['_SHLIBSONAME', '_LDMODULESONAME']:
+ if rv in env:
+ del env[rv]
def exists(env):
diff --git a/SCons/Tool/dmd.py b/SCons/Tool/dmd.py
index 5970246f5..05c54ec6c 100644
--- a/SCons/Tool/dmd.py
+++ b/SCons/Tool/dmd.py
@@ -77,7 +77,6 @@ import SCons.Scanner.D
import SCons.Tool
import SCons.Tool.DCommon as DCommon
-from SCons.Tool.linkCommon import ShLibSonameGenerator
def generate(env):
@@ -150,10 +149,13 @@ def generate(env):
# Support for versioned libraries
env['_SHDLIBVERSIONFLAGS'] = '$SHDLIBVERSIONFLAGS -L-soname=$_SHDLIBSONAME'
- 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'] = ShLibSonameGenerator
+
+ # TODO: Fix this with new logic
+ # 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'] = 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/gnulink.py b/SCons/Tool/gnulink.py
index 2b095493b..fb5acd09f 100644
--- a/SCons/Tool/gnulink.py
+++ b/SCons/Tool/gnulink.py
@@ -8,6 +8,10 @@ selection method.
"""
+#
+# MIT License
+#
+# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -33,10 +37,8 @@ selection method.
import SCons.Tool.linkCommon
import SCons.Util
import SCons.Tool
-import sys
from . import link
-import SCons.Tool.linkCommon as linkCommon
def generate(env):
@@ -52,11 +54,6 @@ def generate(env):
env['RPATHSUFFIX'] = ''
env['_RPATH'] = '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}'
- # OpenBSD doesn't usually use SONAME for libraries
- use_soname = not sys.platform.startswith('openbsd')
- linkCommon._setup_versioned_lib_variables(env, tool='gnulink', use_soname=use_soname)
- env['LINKCALLBACKS'] = linkCommon._versioned_lib_callbacks()
-
def exists(env):
# TODO: sync with link.smart_link() to choose a linker
diff --git a/SCons/Tool/ldc.py b/SCons/Tool/ldc.py
index d893841fc..342f3f032 100644
--- a/SCons/Tool/ldc.py
+++ b/SCons/Tool/ldc.py
@@ -51,7 +51,6 @@ import SCons.Scanner.D
import SCons.Tool
import SCons.Tool.DCommon as DCommon
-from SCons.Tool.linkCommon import ShLibSonameGenerator
def generate(env):
@@ -124,10 +123,14 @@ def generate(env):
# Support for versioned libraries
env['_SHDLIBVERSIONFLAGS'] = '$SHDLIBVERSIONFLAGS -L-soname=$_SHDLIBSONAME'
- 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'] = ShLibSonameGenerator
+
+ # TODO: Fix to work with new logic
+ # 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'] = 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 c552273bc..efc84f116 100644
--- a/SCons/Tool/link.py
+++ b/SCons/Tool/link.py
@@ -31,26 +31,21 @@ selection method.
"""
-
import SCons.Tool
import SCons.Util
import SCons.Warnings
-
-from SCons.Tool.linkCommon import smart_link, shlib_emitter, ldmod_emitter
+from SCons.Tool import createProgBuilder
+from SCons.Tool.linkCommon import smart_link
+from SCons.Tool.linkCommon.LoadableModule import setup_loadable_module_logic
+from SCons.Tool.linkCommon.SharedLibrary import setup_shared_lib_logic
def generate(env):
"""Add Builders and construction variables for gnulink to an Environment."""
- SCons.Tool.createSharedLibBuilder(env)
- SCons.Tool.createProgBuilder(env)
+ createProgBuilder(env)
- env['SHLINK'] = '$LINK'
- env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared')
- env['SHLINKCOM'] = '$SHLINK -o $TARGET $SHLINKFLAGS $__SHLIBVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
-
- # don't set up the emitter, because AppendUnique will generate a list
- # starting with None :-(
- env.Append(SHLIBEMITTER=[shlib_emitter])
+ setup_shared_lib_logic(env)
+ setup_loadable_module_logic(env)
env['SMARTLINK'] = smart_link
env['LINK'] = "$SMARTLINK"
@@ -64,20 +59,6 @@ def generate(env):
env['LIBLINKPREFIX'] = '-l'
env['LIBLINKSUFFIX'] = ''
- # For most platforms, a loadable module is the same as a shared
- # library. Platforms which are different can override these, but
- # setting them the same means that LoadableModule works everywhere.
- SCons.Tool.createLoadableModuleBuilder(env)
- env['LDMODULE'] = '$SHLINK'
- env.Append(LDMODULEEMITTER=[ldmod_emitter])
- env['LDMODULEPREFIX'] = '$SHLIBPREFIX'
- env['LDMODULESUFFIX'] = '$SHLIBSUFFIX'
- env['LDMODULEFLAGS'] = '$SHLINKFLAGS'
- env[
- 'LDMODULECOM'] = '$LDMODULE -o $TARGET $LDMODULEFLAGS $__LDMODULEVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
- env['LDMODULEVERSION'] = '$SHLIBVERSION'
- env['LDMODULENOVERSIONSYMLINKS'] = '$SHLIBNOVERSIONSYMLINKS'
-
def exists(env):
# This module isn't really a Tool on its own, it's common logic for
diff --git a/SCons/Tool/linkCommon/LoadableModule.py b/SCons/Tool/linkCommon/LoadableModule.py
new file mode 100644
index 000000000..36921f6f5
--- /dev/null
+++ b/SCons/Tool/linkCommon/LoadableModule.py
@@ -0,0 +1,97 @@
+from SCons.Tool import createLoadableModuleBuilder
+from .SharedLibrary import shlib_symlink_emitter
+from . import lib_emitter
+
+
+def ldmod_symlink_emitter(target, source, env, **kw):
+ return shlib_symlink_emitter(target, source, env, variable_prefix='LDMODULE')
+
+
+def _get_ldmodule_stem(target, source, env, for_signature):
+ """
+ Get the basename for a library (so for libxyz.so, return xyz)
+ :param target:
+ :param source:
+ :param env:
+ :param for_signature:
+ :return:
+ """
+ target_name = str(target)
+ ldmodule_prefix = env.subst('$LDMODULEPREFIX')
+ ldmodule_suffix = env.subst("$_LDMODULESUFFIX")
+
+ if target_name.startswith(ldmodule_prefix):
+ target_name = target_name[len(ldmodule_prefix):]
+
+ if target_name.endswith(ldmodule_suffix):
+ target_name = target_name[:-len(ldmodule_suffix)]
+
+ return target_name
+
+
+def _ldmodule_soversion(target, source, env, for_signature):
+ """Function to determine what to use for SOVERSION"""
+
+ if 'SOVERSION' in env:
+ return '.$SOVERSION'
+ elif 'LDMODULEVERSION' in env:
+ ldmod_version = env.subst('$LDMODULEVERSION')
+ # We use only the most significant digit of LDMODULEVERSION
+ return '.' + ldmod_version.split('.')[0]
+ else:
+ return ''
+
+
+def _ldmodule_soname(target, source, env, for_signature):
+ if 'SONAME' in env:
+ return '$SONAME'
+ else:
+ return "$LDMODULEPREFIX$_get_ldmodule_stem$_LDMODULESOVERSION${LDMODULESUFFIX}"
+
+
+def setup_loadable_module_logic(env):
+ """
+ Just the logic for loadable modules
+
+ For most platforms, a loadable module is the same as a shared
+ library. Platforms which are different can override these, but
+ setting them the same means that LoadableModule works everywhere.
+
+ :param env:
+ :return:
+ """
+
+ createLoadableModuleBuilder(env)
+
+ env['_get_ldmodule_stem'] = _get_ldmodule_stem
+ env['_LDMODULESOVERSION'] = _ldmodule_soversion
+ env['_LDMODULESONAME'] = _ldmodule_soname
+
+ env['LDMODULENAME'] = '${LDMODULEPREFIX}$_get_ldmodule_stem${_LDMODULESUFFIX}'
+
+ # This is the non versioned LDMODULE filename
+ # If LDMODULEVERSION is defined then this will symlink to $LDMODULENAME
+ env['LDMODULE_NOVERSION_SYMLINK'] = '${LDMODULEPREFIX}$_get_ldmodule_stem${LDMODULESUFFIX}'
+
+ # This is the sonamed file name
+ # If LDMODULEVERSION is defined then this will symlink to $LDMODULENAME
+ env['LDMODULE_SONAME_SYMLINK'] = '$_LDMODULESONAME'
+
+ env['_LDMODULEVERSION'] = "${LDMODULEVERSION and '.'+LDMODULEVERSION or ''}"
+ env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS -Wl,-soname=$_LDMODULESONAME'
+
+ env['LDMODULEEMITTER'] = [lib_emitter, ldmod_symlink_emitter]
+
+ env['LDMODULEPREFIX'] = '$SHLIBPREFIX'
+ env['_LDMODULESUFFIX'] = '${_LDMODULEVERSION}${LDMODULESUFFIX}'
+ env['LDMODULESUFFIX'] = '$SHLIBSUFFIX'
+
+ env['LDMODULE'] = '$SHLINK'
+
+ env['LDMODULEFLAGS'] = '$SHLINKFLAGS'
+
+ env['LDMODULECOM'] = '$LDMODULE -o $TARGET $LDMODULEFLAGS $__LDMODULEVERSIONFLAGS $__RPATH $SOURCES ' \
+ '$_LIBDIRFLAGS $_LIBFLAGS '
+
+ env['LDMODULEVERSION'] = '$SHLIBVERSION'
+ env['LDMODULENOVERSIONSYMLINKS'] = '$SHLIBNOVERSIONSYMLINKS'
\ No newline at end of file
diff --git a/SCons/Tool/linkCommon/SharedLibrary.py b/SCons/Tool/linkCommon/SharedLibrary.py
new file mode 100644
index 000000000..d8f780dc1
--- /dev/null
+++ b/SCons/Tool/linkCommon/SharedLibrary.py
@@ -0,0 +1,153 @@
+from SCons.Tool import createSharedLibBuilder
+from SCons.Util import CLVar
+from . import lib_emitter, EmitLibSymlinks, StringizeLibSymlinks
+
+
+def shlib_symlink_emitter(target, source, env, **kw):
+ verbose = False
+
+ if 'variable_prefix' in kw:
+ var_prefix = kw['variable_prefix']
+ else:
+ var_prefix = 'SHLIB'
+
+ do_symlinks = env.subst('$%sNOVERSIONSYMLINKS' % var_prefix)
+ if do_symlinks in ['1', 'True', 'true', True]:
+ return target, source
+
+ shlibversion = env.subst('$%sVERSION' % var_prefix)
+ if shlibversion:
+ if verbose:
+ print("shlib_symlink_emitter: %sVERSION=%s" % (var_prefix, shlibversion))
+
+ libnode = target[0]
+ linkdir = libnode.get_dir()
+ shlib_soname_symlink = env.subst('$%s_SONAME_SYMLINK' % var_prefix, target=target, source=source)
+ shlib_noversion_symlink = env.subst('$%s_NOVERSION_SYMLINK' % var_prefix, target=target, source=source)
+
+ if verbose:
+ print("shlib_soname_symlink :%s" % shlib_soname_symlink)
+ print("shlib_noversion_symlink :%s" % shlib_noversion_symlink)
+ print("libnode :%s" % libnode)
+
+ symlinks = [(env.File(shlib_soname_symlink), libnode),
+ (env.File(shlib_noversion_symlink), libnode)]
+
+ if verbose:
+ print("_lib_emitter: symlinks={!r}".format(
+ ', '.join(["%r->%r" % (k, v) for k, v in StringizeLibSymlinks(symlinks)])
+ ))
+
+ if symlinks:
+ # This does the actual symlinking
+ EmitLibSymlinks(env, symlinks, target[0])
+
+ # This saves the information so if the versioned shared library is installed
+ # it can faithfully reproduce the correct symlinks
+ target[0].attributes.shliblinks = symlinks
+
+ return target, source
+
+
+def _soversion(target, source, env, for_signature):
+ """Function to determine what to use for SOVERSION"""
+
+ if 'SOVERSION' in env:
+ return '.$SOVERSION'
+ elif 'SHLIBVERSION' in env:
+ shlibversion = env.subst('$SHLIBVERSION')
+ # We use only the most significant digit of SHLIBVERSION
+ return '.' + shlibversion.split('.')[0]
+ else:
+ return ''
+
+
+def _soname(target, source, env, for_signature):
+
+ if 'SONAME' in env:
+ # Now verify that SOVERSION is not also set as that is not allowed
+ if 'SOVERSION' in env:
+ raise SCons.Errors.UserError('Ambiguous library .so naming, both SONAME: %s and SOVERSION: %s are defined. '
+ 'Only one can be defined for a target library.' % (env['SONAME'], env['SOVERSION']))
+ return '$SONAME'
+ else:
+ return "$_get_shlib_dir$SHLIBPREFIX$_get_shlib_stem$_SHLIBSOVERSION${SHLIBSUFFIX}"
+
+
+def _get_shlib_stem(target, source, env, for_signature):
+ """
+ Get the basename for a library (so for libxyz.so, return xyz)
+ :param target:
+ :param source:
+ :param env:
+ :param for_signature:
+ :return:
+ """
+ verbose = False
+
+ target_name = str(target.name)
+ shlibprefix = env.subst('$SHLIBPREFIX')
+ shlibsuffix = env.subst("$_SHLIBSUFFIX")
+
+ if verbose and not for_signature:
+ print("_get_shlib_stem: target_name:%s shlibprefix:%s shlibsuffix:%s"%(target_name, shlibprefix, shlibsuffix))
+
+ if target_name.startswith(shlibprefix):
+ target_name = target_name[len(shlibprefix):]
+
+ if target_name.endswith(shlibsuffix):
+ target_name = target_name[:-len(shlibsuffix)]
+
+ if verbose and not for_signature:
+ print("_get_shlib_stem: target_name:%s AFTER"%(target_name,))
+
+ return target_name
+
+
+def _get_shlib_dir(target, source, env, for_signature):
+ """
+ Get the directory the shlib is in.
+ """
+ if target.dir:
+ return "%s/"%str(target.dir)
+ else:
+ return ""
+
+def setup_shared_lib_logic(env):
+ """
+ Just the logic for shared libraries
+ :param env:
+ :return:
+ """
+ createSharedLibBuilder(env)
+
+ env['_get_shlib_stem'] = _get_shlib_stem
+ env['_get_shlib_dir'] = _get_shlib_dir
+ env['_SHLIBSOVERSION'] = _soversion
+ env['_SHLIBSONAME'] = _soname
+
+ env['SHLIBNAME'] = '${_get_shlib_dir}${SHLIBPREFIX}$_get_shlib_stem${_SHLIBSUFFIX}'
+
+ # This is the non versioned shlib filename
+ # If SHLIBVERSION is defined then this will symlink to $SHLIBNAME
+ env['SHLIB_NOVERSION_SYMLINK'] = '${_get_shlib_dir}${SHLIBPREFIX}$_get_shlib_stem${SHLIBSUFFIX}'
+
+ # This is the sonamed file name
+ # If SHLIBVERSION is defined then this will symlink to $SHLIBNAME
+ env['SHLIB_SONAME_SYMLINK'] = '$_SHLIBSONAME'
+
+ # Note this is gnu style
+ env['SHLIBSONAMEFLAGS'] = '-Wl,-soname=$_SHLIBSONAME'
+ env['_SHLIBVERSION'] = "${SHLIBVERSION and '.'+SHLIBVERSION or ''}"
+ env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS -Wl,-soname=$_SHLIBSONAME'
+
+ env['SHLIBEMITTER'] = [lib_emitter, shlib_symlink_emitter]
+
+ env['SHLIBPREFIX'] = 'lib'
+ env['_SHLIBSUFFIX'] = '${SHLIBSUFFIX}${_SHLIBVERSION}'
+
+ env['SHLINKFLAGS'] = CLVar('$LINKFLAGS -shared')
+
+ env['SHLINKCOM'] = '$SHLINK -o $TARGET $SHLINKFLAGS $__SHLIBVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
+ env['SHLINKCOMSTR'] = '$SHLINKCOM'
+ env['SHLINK'] = '$LINK'
diff --git a/SCons/Tool/linkCommon/__init__.py b/SCons/Tool/linkCommon/__init__.py
index c49bc23d9..7aaffab92 100644
--- a/SCons/Tool/linkCommon/__init__.py
+++ b/SCons/Tool/linkCommon/__init__.py
@@ -25,396 +25,12 @@
Common link/shared library logic
"""
-import os
-import re
-import sys
-from typing import Callable
-
import SCons.Util
import SCons.Warnings
from SCons.Tool.DCommon import isD
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')
+issued_mixed_link_warning = False
def StringizeLibSymlinks(symlinks):
@@ -455,8 +71,8 @@ def CreateLibSymlinks(env, symlinks):
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()
@@ -491,13 +107,13 @@ def LibSymlinksStrFun(target, source, env, *args):
if symlinks:
if cmd is None: cmd = ""
if cmd: cmd += "\n"
- cmd += "Create symlinks for: %r" % tgt.get_path()
+ cmd += "Create symlinks for: %r\n " % tgt.get_path()
try:
- linkstr = ', '.join(["%r->%r" % (k, v) for k, v in StringizeLibSymlinks(symlinks)])
+ linkstr = '\n '.join(["%r->%r" % (k, v) for k, v in StringizeLibSymlinks(symlinks)])
except (KeyError, ValueError):
pass
else:
- cmd += ": %s" % linkstr
+ cmd += "%s" % linkstr
return cmd
@@ -539,235 +155,13 @@ def smart_link(source, target, env, for_signature):
return '$CC'
-def _lib_emitter(target, source, env, **kw):
- Verbose = False
- if Verbose:
+def lib_emitter(target, source, env, **kw):
+ verbose = False
+ if verbose:
print("_lib_emitter: target[0]={!r}".format(target[0].get_path()))
for tgt in target:
if SCons.Util.is_String(tgt):
tgt = env.File(tgt)
tgt.attributes.shared = 1
- try:
- symlink_generator = kw['symlink_generator']
- except KeyError:
- pass
- else:
- if Verbose:
- print("_lib_emitter: symlink_generator={!r}".format(symlink_generator))
- symlinks = symlink_generator(env, target[0])
- if Verbose:
- print("_lib_emitter: symlinks={!r}".format(symlinks))
-
- if symlinks:
- 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=ShLibSymlinkGenerator)
-
-
-def ldmod_emitter(target, source, env):
- return _lib_emitter(target, source, env, symlink_generator=LdModSymlinkGenerator)
-
-
-def _versioned_lib_name(env, libnode, version, prefix, suffix, prefix_generator, suffix_generator, **kw):
- """For libnode='/optional/dir/libfoo.so.X.Y.Z' it returns 'libfoo.so'"""
- Verbose = False
-
- if Verbose:
- print("_versioned_lib_name: libnode={!r}".format(libnode.get_path()))
- print("_versioned_lib_name: version={!r}".format(version))
- print("_versioned_lib_name: prefix={!r}".format(prefix))
- print("_versioned_lib_name: suffix={!r}".format(suffix))
- print("_versioned_lib_name: suffix_generator={!r}".format(suffix_generator))
-
- versioned_name = os.path.basename(libnode.get_path())
- if Verbose:
- print("_versioned_lib_name: versioned_name={!r}".format(versioned_name))
-
- versioned_prefix = prefix_generator(env, **kw)
- versioned_suffix = suffix_generator(env, **kw)
- if Verbose:
- print("_versioned_lib_name: versioned_prefix={!r}".format(versioned_prefix))
- print("_versioned_lib_name: versioned_suffix={!r}".format(versioned_suffix))
-
- versioned_prefix_re = '^' + re.escape(versioned_prefix)
- versioned_suffix_re = re.escape(versioned_suffix) + '$'
- name = re.sub(versioned_prefix_re, prefix, versioned_name)
- name = re.sub(versioned_suffix_re, suffix, name)
- if Verbose:
- print("_versioned_lib_name: name={!r}".format(name))
- return name
-
-
-def _versioned_shlib_name(env, libnode, version, prefix, suffix, **kw):
- 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 = LdModPrefixGenerator
- suffix_generator = LdModSuffixGenerator
- return _versioned_lib_name(env, libnode, version, prefix, suffix, prefix_generator, suffix_generator, **kw)
-
-
-def _versioned_lib_suffix(env, suffix, version):
- """For suffix='.so' and version='0.1.2' it returns '.so.0.1.2'"""
- Verbose = False
- if Verbose:
- print("_versioned_lib_suffix: suffix={!r}".format(suffix))
- print("_versioned_lib_suffix: version={!r}".format(version))
- if not suffix.endswith(version):
- suffix = suffix + '.' + version
- if Verbose:
- print("_versioned_lib_suffix: return suffix={!r}".format(suffix))
- return suffix
-
-
-def _versioned_lib_soname(env, libnode, version, prefix, suffix, name_func):
- """For libnode='/optional/dir/libfoo.so.X.Y.Z' it returns 'libfoo.so.X'"""
- Verbose = False
- if Verbose:
- print("_versioned_lib_soname: version={!r}".format(version))
- name = name_func(env, libnode, version, prefix, suffix)
- if Verbose:
- print("_versioned_lib_soname: name={!r}".format(name))
- major = version.split('.')[0]
-
- # if a desired SONAME was supplied, use that, otherwise create
- # a default from the major version
- if env.get('SONAME'):
- soname = ShLibSonameGenerator(env, libnode)
- else:
- soname = name + '.' + major
- if Verbose:
- print("_versioned_lib_soname: soname={!r}".format(soname))
- return soname
-
-
-def _versioned_shlib_soname(env, libnode, version, prefix, suffix):
- return _versioned_lib_soname(env, libnode, version, prefix, suffix, _versioned_shlib_name)
-
-
-def _versioned_ldmod_soname(env, libnode, version, prefix, suffix):
- return _versioned_lib_soname(env, libnode, version, prefix, suffix, _versioned_ldmod_name)
-
-
-def _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, soname_func):
- """Generate link names that should be created for a versioned shared library.
- Returns a dictionary in the form { linkname : linktarget }
- """
- Verbose = False
-
- if Verbose:
- print("_versioned_lib_symlinks: libnode={!r}".format(libnode.get_path()))
- print("_versioned_lib_symlinks: version={!r}".format(version))
-
- if sys.platform.startswith('openbsd'):
- # OpenBSD uses x.y shared library versioning numbering convention
- # and doesn't use symlinks to backwards-compatible libraries
- if Verbose:
- print("_versioned_lib_symlinks: return symlinks={!r}".format(None))
- return None
-
- linkdir = libnode.get_dir()
- if Verbose:
- print("_versioned_lib_symlinks: linkdir={!r}".format(linkdir.get_path()))
-
- name = name_func(env, libnode, version, prefix, suffix)
- if Verbose:
- print("_versioned_lib_symlinks: name={!r}".format(name))
-
- soname = soname_func(env, libnode, version, prefix, suffix)
- if Verbose:
- print("_versioned_lib_symlinks: soname={!r}".format(soname))
-
- link0 = env.fs.File(soname, linkdir)
- link1 = env.fs.File(name, linkdir)
-
- # We create direct symlinks, not daisy-chained.
- if link0 == libnode:
- # This enables SHLIBVERSION without periods (e.g. SHLIBVERSION=1)
- symlinks = [(link1, libnode)]
- else:
- # This handles usual SHLIBVERSION, i.e. '1.2', '1.2.3', etc.
- symlinks = [(link0, libnode), (link1, libnode)]
-
- if Verbose:
- print("_versioned_lib_symlinks: return symlinks={!r}".format(
- StringizeLibSymlinks(symlinks)))
-
- return symlinks
-
-
-def _versioned_shlib_symlinks(env, libnode, version, prefix, suffix):
- name_func = env['LINKCALLBACKS']['VersionedShLibName']
- soname_func = env['LINKCALLBACKS']['VersionedShLibSoname']
-
- return _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, soname_func)
-
-
-def _versioned_ldmod_symlinks(env, libnode, version, prefix, suffix):
- name_func = _versioned_ldmod_name
- soname_func = _versioned_ldmod_soname
-
- name_func = env['LINKCALLBACKS']['VersionedLdModName']
- soname_func = env['LINKCALLBACKS']['VersionedLdModSoname']
-
- return _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, soname_func)
-
-
-def _versioned_lib_callbacks():
- return {
- 'VersionedShLibSuffix': _versioned_lib_suffix,
- 'VersionedLdModSuffix': _versioned_lib_suffix,
- 'VersionedShLibSymlinks': _versioned_shlib_symlinks,
- 'VersionedLdModSymlinks': _versioned_ldmod_symlinks,
- 'VersionedShLibName': _versioned_shlib_name,
- 'VersionedLdModName': _versioned_ldmod_name,
- 'VersionedShLibSoname': _versioned_shlib_soname,
- 'VersionedLdModSoname': _versioned_ldmod_soname,
- }.copy()
-
-
-issued_mixed_link_warning = False
-
-
-def _setup_versioned_lib_variables(env, **kw):
- """
- Setup all variables required by the versioning machinery
- """
-
- tool = None
- try:
- tool = kw['tool']
- except KeyError:
- pass
-
- use_soname = False
- try:
- use_soname = kw['use_soname']
- except KeyError:
- pass
-
- # The $_SHLIBVERSIONFLAGS define extra commandline flags used when
- # building VERSIONED shared libraries. It's always set, but used only
- # when VERSIONED library is built (see __SHLIBVERSIONFLAGS in SCons/Defaults.py).
- if use_soname:
- # If the linker uses SONAME, then we need this little automata
- env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS -Wl,-soname=$_SHLIBSONAME'
- env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS -Wl,-soname=$_LDMODULESONAME'
- env['_SHLIBSONAME'] = '${ShLibSonameGenerator(__env__,TARGET)}'
- env['_LDMODULESONAME'] = '${LdModSonameGenerator(__env__,TARGET)}'
- env['ShLibSonameGenerator'] = ShLibSonameGenerator
- env['LdModSonameGenerator'] = LdModSonameGenerator
- else:
- env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS'
- env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS'
-
- # LDOMDULVERSIONFLAGS should always default to $SHLIBVERSIONFLAGS
- env['LDMODULEVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS'
\ No newline at end of file
diff --git a/SCons/Tool/sunlink.py b/SCons/Tool/sunlink.py
index f66890326..b0c9816e6 100644
--- a/SCons/Tool/sunlink.py
+++ b/SCons/Tool/sunlink.py
@@ -7,6 +7,10 @@ It will usually be imported through the generic SCons.Tool.Tool()
selection method.
"""
+#
+# MIT License
+#
+# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -30,9 +34,7 @@ selection method.
import os.path
-import SCons.Tool.linkCommon as linkCommon
import SCons.Util
-
from . import link
ccLinker = None
@@ -52,23 +54,20 @@ for d in dirs:
ccLinker = linker
break
+
def generate(env):
"""Add Builders and construction variables for Forte to an Environment."""
link.generate(env)
-
+
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -G')
env['RPATHPREFIX'] = '-R'
env['RPATHSUFFIX'] = ''
env['_RPATH'] = '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}'
- # Support for versioned libraries
- linkCommon._setup_versioned_lib_variables(env, tool='sunlink', use_soname=True)
-
env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS -h $_SHLIBSONAME'
env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS -h $_LDMODULESONAME'
- env['LINKCALLBACKS'] = linkCommon._versioned_lib_callbacks()
def exists(env):
return ccLinker
diff --git a/SCons/__init__.py b/SCons/__init__.py
index fcd665ed0..c9ca70f90 100644
--- a/SCons/__init__.py
+++ b/SCons/__init__.py
@@ -1,9 +1,9 @@
__version__="4.0.1.9998"
__copyright__="Copyright (c) 2001 - 2020 The SCons Foundation"
__developer__="bdbaddog"
-__date__="2020-10-09 19:00:35"
+__date__="2020-12-21 01:23:32"
__buildsys__="ProDog2020"
-__revision__="93525bed88d19a00f5de400086c0046011d3b833"
-__build__="93525bed88d19a00f5de400086c0046011d3b833"
+__revision__="78292be9cbb471101e6ed4ec5f6da0161730c656"
+__build__="78292be9cbb471101e6ed4ec5f6da0161730c656"
# make sure compatibility is always in place
import SCons.compat # noqa
\ No newline at end of file
diff --git a/test/LINK/SHLIBVERSIONFLAGS.py b/test/LINK/SHLIBVERSIONFLAGS.py
index 7bcabf0b3..783286260 100644
--- a/test/LINK/SHLIBVERSIONFLAGS.py
+++ b/test/LINK/SHLIBVERSIONFLAGS.py
@@ -25,10 +25,10 @@
#
-
import TestSCons
-import SCons.Platform
+
import SCons.Defaults
+import SCons.Platform
foo_c_src = "void foo() {}\n"
@@ -39,34 +39,33 @@ tool_list = SCons.Platform.DefaultToolList(platform, env)
test = TestSCons.TestSCons()
if 'gnulink' in tool_list:
versionflags = r".+ -Wl,-soname=libfoo.so.1( .+)+"
- soname='libfoo.so.4'
- sonameVersionFlags=r".+ -Wl,-soname=%s( .+)+" % soname
+ soname = 'libfoo.so.4'
+ sonameVersionFlags = r".+ -Wl,-soname=%s( .+)+" % soname
elif 'sunlink' in tool_list:
versionflags = r".+ -h libfoo.so.1( .+)+"
- soname='libfoo.so.4'
- sonameVersionFlags=r".+ -h %s( .+)+" % soname
+ soname = 'libfoo.so.4'
+ sonameVersionFlags = r".+ -h %s( .+)+" % soname
elif 'applelink' in tool_list:
- versionflags = r".+ 'libfoo.1.dylib'->'libfoo.1.2.3.dylib'(.+)+"
- soname='libfoo.4.dylib'
- sonameVersionFlags=r".+ '%s'->'libfoo.1.2.3.dylib'(.+)+" % soname
+ versionflags = r" 'libfoo.1.dylib'->'libfoo.1.2.3.dylib'"
+ soname = 'libfoo.4.dylib'
+ sonameVersionFlags = r" '%s'->'libfoo.1.2.3.dylib'(.+)+" % soname
else:
test.skip_test('No testable linkers found, skipping the test\n')
-
# stdout must not contain SHLIBVERSIONFLAGS if there is no SHLIBVERSION provided
test.write('foo.c', foo_c_src)
test.write('SConstruct', "SharedLibrary('foo','foo.c')\n")
test.run()
test.fail_test(test.match_re_dotall(test.stdout(), versionflags))
-test.run(arguments = ['-c'])
+test.run(arguments=['-c'])
# stdout must contain SHLIBVERSIONFLAGS if there is SHLIBVERSION provided
test = TestSCons.TestSCons()
test.write('foo.c', foo_c_src)
test.write('SConstruct', "SharedLibrary('foo','foo.c',SHLIBVERSION='1.2.3')\n")
-test.run(stdout = versionflags, match = TestSCons.match_re_dotall)
-test.run(arguments = ['-c'])
+test.run(stdout=versionflags, match=TestSCons.match_re_dotall)
+test.run(arguments=['-c'])
# stdout must contain SONAME if there is SONAME provided
test = TestSCons.TestSCons()
@@ -74,9 +73,9 @@ test.write('foo.c', foo_c_src)
test.write('SConstruct', """
SharedLibrary('foo','foo.c',SHLIBVERSION='1.2.3',SONAME='%s')
""" % soname)
-test.run(stdout = sonameVersionFlags, match = TestSCons.match_re_dotall)
+test.run(stdout=sonameVersionFlags, match=TestSCons.match_re_dotall)
test.must_exist(test.workpath(soname))
-test.run(arguments = ['-c'])
+test.run(arguments=['-c'])
# stdout must contain SOVERSION if there is SOVERSION provided
test = TestSCons.TestSCons()
@@ -84,9 +83,9 @@ test.write('foo.c', foo_c_src)
test.write('SConstruct', """
SharedLibrary('foo','foo.c',SHLIBVERSION='1.2.3',SOVERSION='4')
""")
-test.run(stdout = sonameVersionFlags, match = TestSCons.match_re_dotall)
+test.run(stdout=sonameVersionFlags, match=TestSCons.match_re_dotall)
test.must_exist(test.workpath(soname))
-test.run(arguments = ['-c'])
+test.run(arguments=['-c'])
# test if both SONAME and SOVERSION are used
test = TestSCons.TestSCons()
@@ -94,7 +93,7 @@ test.write('foo.c', foo_c_src)
test.write('SConstruct', """
SharedLibrary('foo','foo.c',SHLIBVERSION='1.2.3',SONAME='%s',SOVERSION='4')
""" % soname)
-test.run(status=2,stderr=None)
+test.run(status=2, stderr=None)
test.must_contain_all_lines(test.stderr(), ['Ambiguous library .so naming'])
test.pass_test()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment