summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Deegan <bill@baddogconsulting.com>2018-12-04 22:33:28 (GMT)
committerWilliam Deegan <bill@baddogconsulting.com>2018-12-04 22:33:28 (GMT)
commit2b978d126393723def974e48fec0f7fffcd5743e (patch)
treeaa1f53e9b0e45491e0523e6c266902b9ed7b7e54
parent666368d25da2c4339f5e7143eb0678b41ce95f87 (diff)
downloadSCons-2b978d126393723def974e48fec0f7fffcd5743e.zip
SCons-2b978d126393723def974e48fec0f7fffcd5743e.tar.gz
SCons-2b978d126393723def974e48fec0f7fffcd5743e.tar.bz2
Initial checkin of functional versioned shared libraries for applelink. Not loadable modules don't get versions embedded in the generated file
-rw-r--r--src/engine/SCons/Tool/applelink.py82
-rw-r--r--src/engine/SCons/Tool/link.py35
-rw-r--r--test/LINK/LDMODULEVERSIONFLAGS.py1
-rw-r--r--test/LINK/SHLIBVERSIONFLAGS.py2
-rw-r--r--test/LINK/VersionedLib-VariantDir.py6
-rw-r--r--test/LINK/VersionedLib-j2.py5
-rw-r--r--test/LINK/VersionedLib-subdir.py5
-rw-r--r--test/LINK/VersionedLib.py6
8 files changed, 100 insertions, 42 deletions
diff --git a/src/engine/SCons/Tool/applelink.py b/src/engine/SCons/Tool/applelink.py
index 5a06f9c..4a87a07 100644
--- a/src/engine/SCons/Tool/applelink.py
+++ b/src/engine/SCons/Tool/applelink.py
@@ -1,6 +1,6 @@
"""SCons.Tool.applelink
-Tool-specific initialization for the Apple gnu-like linker.
+Tool-specific initialization for the Apple's gnu-like linker.
There normally shouldn't be any need to import this module directly.
It will usually be imported through the generic SCons.Tool.Tool()
@@ -40,6 +40,73 @@ import SCons.Util
from . import link
+
+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 not version 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('.')
+ 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, link._versioned_shlib_name)
+
+
+# User programmatically describes how SHLIBVERSION maps to values for compat/current.
+
+def _applelib_currentVersionFromSoVersion(source, target, env, for_signature):
+ """
+ -Wl,current_version=2.3
+ """
+
+ if env.get('APPLELINK_CURRENT_VERSION', False):
+ version_string = env['SHLIBVERSION']
+ elif env.get('SHLIBVERSION', False):
+ version_string = env['SHLIBVERSION']
+ else:
+ return ""
+
+ version_string = ".".join(version_string.split('.')[:3])
+
+ return "-Wl,-current_version,%s" % version_string
+
+
+def _applelib_compatVersionFromSoVersion(source, target, env, for_signature):
+ """
+ -Wl,compat_version=2.0
+ """
+
+ if env.get('APPLELINK_COMPAT_VERSION', False):
+ version_string = env['SHLIBVERSION']
+ elif env.get('SHLIBVERSION', False):
+ version_string = ".".join(env['SHLIBVERSION'].split('.')[:2] + ['0'])
+ else:
+ return ""
+
+ return "-Wl,-compatibility_version,%s" % version_string
+
+
def generate(env):
"""Add Builders and construction variables for applelink to an
Environment."""
@@ -57,9 +124,18 @@ def generate(env):
# TODO: Work needed to generate versioned shared libraries
# Leaving this commented out, and also going to disable versioned library checking for now
# 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)
- #env['LINKCALLBACKS'] = link._versioned_lib_callbacks()
+ link._setup_versioned_lib_variables(env, tool = 'applelink')#, use_soname = use_soname)
+ env['LINKCALLBACKS'] = link._versioned_lib_callbacks()
+
+ # 'VersionedShLibSuffix': _versioned_lib_suffix,
+ 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 '
+ env['_LDMODULEVERSIONFLAGS'] = '$APPLELINK_CURRENT_VERSION $APPLELINK_COMPATIBILITY_VERSION '
# override the default for loadable modules, which are different
# on OS X than dynamic shared libs. echoing what XCode does for
diff --git a/src/engine/SCons/Tool/link.py b/src/engine/SCons/Tool/link.py
index a55688c..5adc6ca 100644
--- a/src/engine/SCons/Tool/link.py
+++ b/src/engine/SCons/Tool/link.py
@@ -46,15 +46,13 @@ from SCons.Tool.FortranCommon import isfortran
from SCons.Tool.DCommon import isD
-import SCons.Tool.cxx
-
-cplusplus = SCons.Tool.cxx
+from SCons.Tool.cxx import iscplusplus
issued_mixed_link_warning = False
def smart_link(source, target, env, for_signature):
- has_cplusplus = cplusplus.iscplusplus(source)
+ has_cplusplus = iscplusplus(source)
has_fortran = isfortran(env, source)
has_d = isD(env, source)
if has_cplusplus and has_fortran and not has_d:
@@ -113,7 +111,7 @@ def ldmod_emitter(target, source, env):
# This is generic enough to be included here...
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 = True
+ Verbose = False
if Verbose:
print("_versioned_lib_name: libnode={!r}".format(libnode.get_path()))
@@ -142,15 +140,15 @@ def _versioned_lib_name(env, libnode, version, prefix, suffix, prefix_generator,
def _versioned_shlib_name(env, libnode, version, prefix, suffix, **kw):
- pg = SCons.Tool.ShLibPrefixGenerator
- sg = SCons.Tool.ShLibSuffixGenerator
- return _versioned_lib_name(env, libnode, version, prefix, suffix, pg, sg, **kw)
+ prefix_generator = SCons.Tool.ShLibPrefixGenerator
+ suffix_generator = SCons.Tool.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):
- pg = SCons.Tool.LdModPrefixGenerator
- sg = SCons.Tool.LdModSuffixGenerator
- return _versioned_lib_name(env, libnode, version, prefix, suffix, pg, sg, **kw)
+ prefix_generator = SCons.Tool.LdModPrefixGenerator
+ suffix_generator = SCons.Tool.LdModSuffixGenerator
+ return _versioned_lib_name(env, libnode, version, prefix, suffix, prefix_generator, suffix_generator, **kw)
def _versioned_lib_suffix(env, suffix, version):
@@ -193,7 +191,7 @@ def _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, so
"""Generate link names that should be created for a versioned shared library.
Returns a dictionary in the form { linkname : linktarget }
"""
- Verbose = True
+ Verbose = False
if Verbose:
print("_versioned_lib_symlinks: libnode={!r}".format(libnode.get_path()))
@@ -215,6 +213,8 @@ def _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, so
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)
@@ -234,11 +234,8 @@ def _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, so
def _versioned_shlib_symlinks(env, libnode, version, prefix, suffix):
- name_func = _versioned_shlib_name
- soname_func = _versioned_shlib_soname
-
- # nf = env['LINKCALLBACKS']['VersionedShLibName']
- # sf = env['LINKCALLBACKS']['VersionedShLibSoname']
+ name_func = env['LINKCALLBACKS']['VersionedShLibName']
+ soname_func = env['LINKCALLBACKS']['VersionedShLibSoname']
return _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, soname_func)
@@ -246,6 +243,10 @@ def _versioned_shlib_symlinks(env, libnode, version, prefix, suffix):
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)
diff --git a/test/LINK/LDMODULEVERSIONFLAGS.py b/test/LINK/LDMODULEVERSIONFLAGS.py
index 0683b72..6e3085c 100644
--- a/test/LINK/LDMODULEVERSIONFLAGS.py
+++ b/test/LINK/LDMODULEVERSIONFLAGS.py
@@ -57,6 +57,7 @@ test.run(arguments = ['-c'])
for versionvar in ['SHLIBVERSION', 'LDMODULEVERSION']:
test = TestSCons.TestSCons()
+ test.verbose_set(1)
test.write('foo.c', foo_c_src)
test.write('SConstruct', "LoadableModule('foo','foo.c',%s='1.2.3')\n" % versionvar)
test.run(stdout = versionflags, match = TestSCons.match_re_dotall)
diff --git a/test/LINK/SHLIBVERSIONFLAGS.py b/test/LINK/SHLIBVERSIONFLAGS.py
index aae8843..9d91868 100644
--- a/test/LINK/SHLIBVERSIONFLAGS.py
+++ b/test/LINK/SHLIBVERSIONFLAGS.py
@@ -42,6 +42,8 @@ if 'gnulink' in tool_list:
versionflags = r".+ -Wl,-Bsymbolic -Wl,-soname=libfoo.so.1( .+)+"
elif 'sunlink' in tool_list:
versionflags = r".+ -h libfoo.so.1( .+)+"
+elif 'applelink' in tool_list:
+ versionflags = r".+ -dynamiclib -Wl,-current_version,1.2.3 -Wl,-compatibility_version,1.2.0( .+)+"
else:
test.skip_test('No testable linkers found, skipping the test\n')
diff --git a/test/LINK/VersionedLib-VariantDir.py b/test/LINK/VersionedLib-VariantDir.py
index 340fee0..4a5ac40 100644
--- a/test/LINK/VersionedLib-VariantDir.py
+++ b/test/LINK/VersionedLib-VariantDir.py
@@ -37,12 +37,6 @@ import SCons.Defaults
test = TestSCons.TestSCons()
-import sys
-if sys.platform == 'darwin':
- # Skipping until logic is fixed for macosx
- test.skip_test("Not working on darwin yet\n")
-
-
env = SCons.Defaults.DefaultEnvironment()
platform = SCons.Platform.platform_default()
tool_list = SCons.Platform.DefaultToolList(platform, env)
diff --git a/test/LINK/VersionedLib-j2.py b/test/LINK/VersionedLib-j2.py
index ed3b7ff..0cde91c 100644
--- a/test/LINK/VersionedLib-j2.py
+++ b/test/LINK/VersionedLib-j2.py
@@ -39,11 +39,6 @@ import SCons.Defaults
test = TestSCons.TestSCons()
-if sys.platform == 'darwin':
- # Skipping until logic is fixed for macosx
- test.skip_test("Not working on darwin yet\n")
-
-
test.write('foo.c', """
#if _WIN32
__declspec(dllexport)
diff --git a/test/LINK/VersionedLib-subdir.py b/test/LINK/VersionedLib-subdir.py
index 2271a54..66fef63 100644
--- a/test/LINK/VersionedLib-subdir.py
+++ b/test/LINK/VersionedLib-subdir.py
@@ -41,11 +41,6 @@ import SCons.Defaults
test = TestSCons.TestSCons()
-if sys.platform == 'darwin':
- # Skipping until logic is fixed for macosx
- test.skip_test("Not working on darwin yet\n")
-
-
test.write('foo.c', """
#if _WIN32
__declspec(dllexport)
diff --git a/test/LINK/VersionedLib.py b/test/LINK/VersionedLib.py
index c05c159..468e3e5 100644
--- a/test/LINK/VersionedLib.py
+++ b/test/LINK/VersionedLib.py
@@ -33,12 +33,6 @@ import TestSCons
import SCons.Platform
import SCons.Defaults
-import sys
-if sys.platform == 'darwin':
- # Skipping until logic is fixed for macosx
- test = TestSCons.TestSCons()
- test.skip_test("Not working on darwin yet\n")
-
env = SCons.Defaults.DefaultEnvironment()
platform = SCons.Platform.platform_default()
tool_list = SCons.Platform.DefaultToolList(platform, env)