summaryrefslogtreecommitdiffstats
path: root/SCons/Tool/applelink.py
diff options
context:
space:
mode:
Diffstat (limited to 'SCons/Tool/applelink.py')
-rw-r--r--SCons/Tool/applelink.py224
1 files changed, 224 insertions, 0 deletions
diff --git a/SCons/Tool/applelink.py b/SCons/Tool/applelink.py
new file mode 100644
index 0000000..8c081a2
--- /dev/null
+++ b/SCons/Tool/applelink.py
@@ -0,0 +1,224 @@
+"""SCons.Tool.applelink
+
+Tool-specific initialization for 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()
+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
+# 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.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+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 . import link
+
+from SCons.Tool import ShLibSonameGenerator
+
+class AppleLinkInvalidCurrentVersionException(Exception):
+ pass
+
+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, 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.
+ X[.Y[.Z]]
+ where X 0-65535
+ where Y either not specified or 0-255
+ where Z either not specified or 0-255
+ :param version_string:
+ :return:
+ """
+ parts = version_string.split('.')
+ if len(parts) > 3:
+ return False, "Version string has too many periods [%s]"%version_string
+ if len(parts) <= 0:
+ 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)
+ 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 True, ""
+
+
+def _applelib_currentVersionFromSoVersion(source, target, env, for_signature):
+ """
+ A generator function to create the -Wl,-current_version flag if needed.
+ If env['APPLELINK_NO_CURRENT_VERSION'] contains a true value no flag will be generated
+ Otherwise if APPLELINK_CURRENT_VERSION is not specified, env['SHLIBVERSION']
+ will be used.
+
+ :param source:
+ :param target:
+ :param env:
+ :param for_signature:
+ :return: A string providing the flag to specify the current_version of the shared library
+ """
+ if env.get('APPLELINK_NO_CURRENT_VERSION', False):
+ return ""
+ elif env.get('APPLELINK_CURRENT_VERSION', False):
+ version_string = env['APPLELINK_CURRENT_VERSION']
+ elif env.get('SHLIBVERSION', False):
+ version_string = env['SHLIBVERSION']
+ else:
+ return ""
+
+ version_string = ".".join(version_string.split('.')[:3])
+
+ valid, reason = _applelib_check_valid_version(version_string)
+ if not valid:
+ raise AppleLinkInvalidCurrentVersionException(reason)
+
+ return "-Wl,-current_version,%s" % version_string
+
+
+def _applelib_compatVersionFromSoVersion(source, target, env, for_signature):
+ """
+ A generator function to create the -Wl,-compatibility_version flag if needed.
+ If env['APPLELINK_NO_COMPATIBILITY_VERSION'] contains a true value no flag will be generated
+ Otherwise if APPLELINK_COMPATIBILITY_VERSION is not specified
+ the first two parts of env['SHLIBVERSION'] will be used with a .0 appended.
+
+ :param source:
+ :param target:
+ :param env:
+ :param for_signature:
+ :return: A string providing the flag to specify the compatibility_version of the shared library
+ """
+ if env.get('APPLELINK_NO_COMPATIBILITY_VERSION', False):
+ return ""
+ elif env.get('APPLELINK_COMPATIBILITY_VERSION', False):
+ version_string = env['APPLELINK_COMPATIBILITY_VERSION']
+ elif env.get('SHLIBVERSION', False):
+ version_string = ".".join(env['SHLIBVERSION'].split('.')[:2] + ['0'])
+ else:
+ return ""
+
+ if version_string is None:
+ return ""
+
+ valid, reason = _applelib_check_valid_version(version_string)
+ if not valid:
+ raise AppleLinkInvalidCompatibilityVersionException(reason)
+
+ return "-Wl,-compatibility_version,%s" % version_string
+
+
+def generate(env):
+ """Add Builders and construction variables for applelink to an
+ Environment."""
+ link.generate(env)
+
+ env['FRAMEWORKPATHPREFIX'] = '-F'
+ env['_FRAMEWORKPATH'] = '${_concat(FRAMEWORKPATHPREFIX, FRAMEWORKPATH, "", __env__, RDirs)}'
+
+ env['_FRAMEWORKS'] = '${_concat("-framework ", FRAMEWORKS, "", __env__)}'
+ env['LINKCOM'] = env['LINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
+ 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)
+ env['LINKCALLBACKS'] = link._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 '
+ 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
+ # 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")}'
+
+
+
+def exists(env):
+ return env['PLATFORM'] == 'darwin'
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4: