summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPawel Tomulik <ptomulik@meil.pw.edu.pl>2015-09-03 01:02:08 +0200
committerPawel Tomulik <ptomulik@meil.pw.edu.pl>2015-09-03 01:02:08 +0200
commitf8d81690ddc55b805d4c4f8d210f58c1f026cd30 (patch)
tree71e59b1562c5d867550c13291491de386ea3a1c7
parenta825718913cbad5c0bb0846c2cee2f5c876b760b (diff)
downloadscons-f8d81690ddc55b805d4c4f8d210f58c1f026cd30.tar.gz
new versioned libraries - gnulink and cyglink for now
-rw-r--r--src/engine/SCons/Defaults.py7
-rw-r--r--src/engine/SCons/Platform/cygwin.py4
-rw-r--r--src/engine/SCons/Tool/__init__.py428
-rw-r--r--src/engine/SCons/Tool/__init__.xml37
-rw-r--r--src/engine/SCons/Tool/cyglink.py148
-rw-r--r--src/engine/SCons/Tool/cyglink.xml49
-rw-r--r--src/engine/SCons/Tool/gnulink.py117
-rw-r--r--src/engine/SCons/Tool/gnulink.xml4
-rw-r--r--src/engine/SCons/Tool/install.py130
-rw-r--r--src/engine/SCons/Tool/install.xml11
-rw-r--r--src/engine/SCons/Tool/link.py148
-rw-r--r--src/engine/SCons/Tool/link.xml154
-rw-r--r--src/engine/SCons/Tool/linkloc.py1
-rw-r--r--src/engine/SCons/Tool/mingw.py1
-rw-r--r--src/engine/SCons/Tool/mslink.py1
-rw-r--r--src/engine/SCons/Tool/mwld.py1
-rw-r--r--src/engine/SCons/Tool/qt.py1
-rw-r--r--test/LINK/VersionedLib-j2.py135
-rw-r--r--test/LINK/VersionedLib-subdir.py149
-rw-r--r--test/LINK/VersionedLib.py22
20 files changed, 1187 insertions, 361 deletions
diff --git a/src/engine/SCons/Defaults.py b/src/engine/SCons/Defaults.py
index 65004438..db489692 100644
--- a/src/engine/SCons/Defaults.py
+++ b/src/engine/SCons/Defaults.py
@@ -482,6 +482,10 @@ class Variable_Method_Caller(object):
frame = frame.f_back
return None
+def __libversionflags_string(versionvar):
+ return '${("%s" in locals() and %s and "_%sFLAGS" in locals()) ' \
+ 'and _%sFLAGS or None}' % (versionvar, versionvar, versionvar, versionvar)
+
ConstructionEnvironment = {
'BUILDERS' : {},
'SCANNERS' : [],
@@ -499,6 +503,9 @@ ConstructionEnvironment = {
'_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
'_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
'_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
+
+ '__SHLIBVERSIONFLAGS' : __libversionflags_string('SHLIBVERSION'),
+ '__LDMODULEVERSIONFLAGS' : __libversionflags_string('LDMODULEVERSION'),
'TEMPFILE' : NullCmdGenerator,
'Dir' : Variable_Method_Caller('TARGET', 'Dir'),
'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'),
diff --git a/src/engine/SCons/Platform/cygwin.py b/src/engine/SCons/Platform/cygwin.py
index a0126826..34c79ff9 100644
--- a/src/engine/SCons/Platform/cygwin.py
+++ b/src/engine/SCons/Platform/cygwin.py
@@ -42,8 +42,8 @@ def generate(env):
env['PROGSUFFIX'] = '.exe'
env['SHLIBPREFIX'] = ''
env['SHLIBSUFFIX'] = '.dll'
- env['LIBPREFIXES'] = [ '$LIBPREFIX', '$SHLIBPREFIX' ]
- env['LIBSUFFIXES'] = [ '$LIBSUFFIX', '$SHLIBSUFFIX' ]
+ env['LIBPREFIXES'] = [ '$LIBPREFIX', '$SHLIBPREFIX', '$IMPLIBPREFIX' ]
+ env['LIBSUFFIXES'] = [ '$LIBSUFFIX', '$SHLIBSUFFIX', '$IMPLIBSUFFIX' ]
env['TEMPFILE'] = TempFileMunge
env['TEMPFILEPREFIX'] = '@'
env['MAXLINELENGTH'] = 2048
diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py
index efd2e339..4a27c0da 100644
--- a/src/engine/SCons/Tool/__init__.py
+++ b/src/engine/SCons/Tool/__init__.py
@@ -236,150 +236,304 @@ def createStaticLibBuilder(env):
return static_lib
-def VersionShLibLinkNames(version, libname, env):
- """Generate names of symlinks to the versioned shared library"""
- Verbose = False
- platform = env.subst('$PLATFORM')
- shlib_suffix = env.subst('$SHLIBSUFFIX')
- shlink_flags = SCons.Util.CLVar(env.subst('$SHLINKFLAGS'))
-
- linknames = []
- if version.count(".") != 2:
- # We need a version string of the form x.y.z to proceed
- # Several changes need to be made to support versions like x.y
- raise ValueError
-
- if platform == 'darwin':
- # For libfoo.x.y.z.dylib, linknames libfoo.so
- suffix_re = re.escape('.' + version + shlib_suffix)
- linkname = re.sub(suffix_re, shlib_suffix, libname)
- if Verbose:
- print "VersionShLibLinkNames: linkname = ",linkname
- linknames.append(linkname)
- elif platform == 'posix' or platform == 'sunos':
- if sys.platform.startswith('openbsd'):
- # OpenBSD uses x.y shared library versioning numbering convention
- # and doesn't use symlinks to backwards-compatible libraries
- return []
- # For libfoo.so.x.y.z, linknames libfoo.so libfoo.so.x.y libfoo.so.x
- suffix_re = re.escape(shlib_suffix + '.' + version)
- # First linkname has no version number
- linkname = re.sub(suffix_re, shlib_suffix, libname)
- if Verbose:
- print "VersionShLibLinkNames: linkname = ",linkname
- linknames.append(linkname)
- versionparts = version.split('.')
- major_name = linkname + "." + versionparts[0]
- minor_name = major_name + "." + versionparts[1]
- #Only add link for major_name
- #for linkname in [major_name, minor_name]:
- for linkname in [major_name, ]:
- if Verbose:
- print "VersionShLibLinkNames: linkname ",linkname, ", target ",libname
- linknames.append(linkname)
- # note: no Windows case here (win32 or cygwin);
- # MSVC doesn't support this type of versioned shared libs.
- # (could probably do something for MinGW though)
- return linknames
-
-def VersionedSharedLibrary(target = None, source= None, env=None):
- """Build a shared library. If the environment has SHLIBVERSION
-defined make a versioned shared library and create the appropriate
-symlinks for the platform we are on"""
+def _call_env_cb(env, callback, args, result = None):
+ """Returns the result of env[callback](*args) call if env[callback] is
+ callable. If env[callback] does not exist or is not callable, 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_env_cb: args=%r' % args
+ print '_call_env_cb: callback=%r' % callback
+
try:
- version = env.subst('$SHLIBVERSION')
+ cbfun = env[callback]
except KeyError:
+ pass
+ else:
+ if Verbose:
+ print '_call_env_cb: env[%r] found' % callback
+ print '_call_env_cb: env[%r]=%r' % (callback, cbfun)
+ if(callable(cbfun)):
+ if Verbose:
+ print '_call_env_cb: env[%r] is callable' % callback
+ result = cbfun(env, *args)
+ return result
+
+class _LibInfoGeneratorBase(object):
+ """Generator base class for library-related info such as suffixes for
+ versioned libraries, symlink maps, sonames etc. It handles commonities
+ of SharedLibrary and LoadableModule
+ """
+ def __init__(self, libtype, infoname):
+ self.set_libtype(libtype)
+ self.set_infoname(infoname)
+
+ def set_libtype(self, libtype):
+ if libtype not in ['ShLib', 'LdMod', 'ImpLib']:
+ raise ValueError('unsupported libtype %r' % libtype)
+ self.libtype = libtype
+
+ def get_libtype(self):
+ return self.libtype
+
+ def set_infoname(self, infoname):
+ self.infoname = infoname
+
+ def get_infoname(self):
+ return self.infoname
+
+ def get_lib_prefix(self, env):
+ prefix = None
+ libtype = self.get_libtype()
+ if libtype == 'ShLib':
+ prefix = env.subst('$SHLIBPREFIX')
+ elif libtype == 'LdMod':
+ prefix = env.subst('$LDMODULEPREFIX')
+ elif libtype == 'ImpLib':
+ prefix = env.subst('$IMPLIBPREFIX')
+ return prefix
+
+ def get_lib_suffix(self, env):
+ suffix = None
+ libtype = self.get_libtype()
+ if libtype == 'ShLib':
+ suffix = env.subst('$SHLIBSUFFIX')
+ elif libtype == 'LdMod':
+ suffix = env.subst('$LDMODULESUFFIX')
+ elif libtype == 'ImpLib':
+ suffix = env.subst('$IMPLIBSUFFIX')
+ return suffix
+
+ def get_lib_version(self, env, **kw):
version = None
+ libtype = self.get_libtype()
+ if libtype == 'ShLib':
+ version = env.subst('$SHLIBVERSION')
+ elif libtype == 'LdMod':
+ version = env.subst('$LDMODULEVERSION')
+ elif libtype == 'ImpLib':
+ version = env.subst('$IMPLIBVERSION')
+ if not version:
+ try: lt = kw['implib_libtype']
+ except KeyError: pass
+ else:
+ if lt == 'ShLib':
+ version = env.subst('$SHLIBVERSION')
+ elif lt == 'LdMod':
+ version = env.subst('$LDMODULEVERSION')
+ return version
+
+ def get_versioned_lib_info_generator(self, **kw):
+ try: libtype = kw['generator_libtype']
+ except KeyError: libtype = self.get_libtype()
+ infoname = self.get_infoname()
+ return 'GenerateVersioned%s%s' % (libtype, infoname)
+
+ def generate_versioned_lib_info(self, env, args, result = None, **kw):
+ callback = self.get_versioned_lib_info_generator(**kw)
+ return _call_env_cb(env, callback, args, result)
+
+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
+
+ suffix = self.get_lib_suffix(env)
+ if Verbose:
+ print "_LibSuffixGenerator: input suffix=%r" % suffix
- # libname includes the version number if one was given
- libname = getattr(target[0].attributes, 'shlibname', target[0].name)
- platform = env.subst('$PLATFORM')
- shlib_suffix = env.subst('$SHLIBSUFFIX')
- shlink_flags = SCons.Util.CLVar(env.subst('$SHLINKFLAGS'))
- if Verbose:
- print "VersionShLib: libname = ",libname
- print "VersionShLib: platform = ",platform
- print "VersionShLib: shlib_suffix = ",shlib_suffix
- print "VersionShLib: target = ",str(target[0])
-
- if version:
- # set the shared library link flags
- if platform == 'posix':
- shlink_flags += [ '-Wl,-Bsymbolic' ]
- # OpenBSD doesn't usually use SONAME for libraries
- if not sys.platform.startswith('openbsd'):
- # continue setup of shlink flags for all other POSIX systems
- suffix_re = re.escape(shlib_suffix + '.' + version)
- (major, age, revision) = version.split(".")
- # soname will have only the major version number in it
- soname = re.sub(suffix_re, shlib_suffix, libname) + '.' + major
- shlink_flags += [ '-Wl,-soname=%s' % soname ]
- if Verbose:
- print " soname ",soname,", shlink_flags ",shlink_flags
- elif platform == 'sunos':
- suffix_re = re.escape(shlib_suffix + '.' + version)
- (major, age, revision) = version.split(".")
- soname = re.sub(suffix_re, shlib_suffix, libname) + '.' + major
- shlink_flags += [ '-h', soname ]
- elif platform == 'cygwin':
- shlink_flags += [ '-Wl,-Bsymbolic',
- '-Wl,--out-implib,${TARGET.base}.a' ]
- elif platform == 'darwin':
- shlink_flags += [ '-current_version', '%s' % version,
- '-compatibility_version', '%s' % version,
- '-undefined', 'dynamic_lookup' ]
+ version = self.get_lib_version(env, **kw)
if Verbose:
- print "VersionShLib: shlink_flags = ",shlink_flags
- envlink = env.Clone()
- envlink['SHLINKFLAGS'] = shlink_flags
- else:
- envlink = env
+ print "_LibSuffixGenerator: version=%r" % version
- result = SCons.Defaults.ShLinkAction(target, source, envlink)
+ if version:
+ suffix = self.generate_versioned_lib_info(env, [suffix, version], suffix, **kw)
- if version:
- # here we need the full pathname so the links end up in the right directory
- libname = getattr(target[0].attributes, 'shlibpath', target[0].get_internal_path())
if Verbose:
- print "VerShLib: target lib is = ", libname
- print "VerShLib: name is = ", target[0].name
- print "VerShLib: dir is = ", target[0].dir.path
- linknames = VersionShLibLinkNames(version, libname, env)
+ 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 dict of symlinks that
+ should be created by SharedLibrary or LoadableModule builders"""
+ def __init__(self, libtype):
+ super(_LibSymlinkGenerator, self).__init__(libtype, 'Symlinks')
+
+ def get_noversionsymlinks(self, env, **kw):
+ disable = None
+ libtype = self.get_libtype()
+ if libtype == 'ShLib':
+ disable = env.subst('$SHLIBNOVERSIONSYMLINKS')
+ elif libtype == 'LdMod':
+ disable = env.subst('$LDMODULENOVERSIONSYMLINKS')
+ elif libtype == 'ImpLib':
+ try: env['IMPLIBNOVERSIONSYMLINKS']
+ except KeyError:
+ try: lt = kw['implib_libtype']
+ except KeyError: pass
+ else:
+ if lt == 'ShLib':
+ disable = env.subst('$SHLIBNOVERSIONSYMLINKS')
+ elif lt == 'LdMod':
+ disable = env.subst('$LDMODULENOVERSIONSYMLINKS')
+ else:
+ disable = env.subst('$IMPLIBNOVERSIONSYMLINKS')
+ return disable
+
+ def __call__(self, env, libnode, **kw):
+ Verbose = False
+
if Verbose:
- print "VerShLib: linknames ",linknames
- # Here we just need the file name w/o path as the target of the link
- lib_ver = getattr(target[0].attributes, 'shlibname', target[0].name)
- # make symlink of adjacent names in linknames
- for count in range(len(linknames)):
- linkname = linknames[count]
- if count > 0:
- try:
- os.remove(lastlinkname)
- except:
- pass
- os.symlink(os.path.basename(linkname),lastlinkname)
- if Verbose:
- print "VerShLib: made sym link of %s -> %s" % (lastlinkname,linkname)
- lastlinkname = linkname
- # finish chain of sym links with link to the actual library
- if len(linknames)>0:
- try:
- os.remove(lastlinkname)
- except:
- pass
- os.symlink(lib_ver,lastlinkname)
+ print "_LibSymLinkGenerator: str(libnode)=%r" % str(libnode)
+
+ symlinks = None
+
+ version = self.get_lib_version(env, **kw)
+ disable = self.get_noversionsymlinks(env, **kw)
+ if Verbose:
+ print '_LibSymlinkGenerator: version=%r' % version
+ print '_LibSymlinkGenerator: disable=%r' % disable
+
+ if version and not disable:
+ suffix = self.get_lib_suffix(env)
+ symlinks = self.generate_versioned_lib_info(env, [libnode, version, suffix], **kw)
+
+ if Verbose:
+ print '_LibSymlinkGenerator: return symlinks=%r' % symlinks
+ return symlinks
+
+ShLibSymlinkGenerator = _LibSymlinkGenerator('ShLib')
+LdModSymlinkGenerator = _LibSymlinkGenerator('LdMod')
+ImpLibSymlinkGenerator = _LibSymlinkGenerator('ImpLib')
+
+class _LibNameGenerator(_LibInfoGeneratorBase):
+ """Library name generator. Returns library name (e.g. libfoo.so) for
+ a given node (e.g. /foo/bar/libfoo.so.0.1.2)"""
+ def __init__(self, libtype):
+ super(_LibNameGenerator, self).__init__(libtype, 'Name')
+
+ def __call__(self, env, libnode, **kw):
+ """Returns library name with version suffixes stripped"""
+ Verbose = False
+
+ if Verbose:
+ print "_LibNameGenerator: str(libnode)=%r" % str(libnode)
+
+ version = self.get_lib_version(env, **kw)
+ if Verbose:
+ print '_LibNameGenerator: version=%r' % version
+
+ name = None
+ if version:
+ suffix = self.get_lib_suffix(env)
+ name = self.generate_versioned_lib_info(env, [libnode, version, suffix], **kw)
+
+ if not name:
+ name = os.path.basename(str(libnode))
+
+ 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 Verbose:
+ print "_LibSonameGenerator: str(libnode)=%r" % str(libnode)
+
+ soname = env.subst('$SONAME')
+ if not soname:
+ version = self.get_lib_version(env,**kw)
if Verbose:
- print "VerShLib: made sym link of %s -> %s" % (linkname, lib_ver)
- return result
+ print "_LibSonameGenerator: version=%r" % version
+ if version:
+ suffix = self.get_lib_suffix(env)
+ soname = self.generate_versioned_lib_info(env, [libnode, version, suffix], **kw)
+
+ if not soname:
+ # fallback to library name (as returned by appropriate _LibNameGenerator)
+ soname = _LibNameGenerator(self.get_libtype())(env, libnode)
+ if Verbose:
+ print "_LibSonameGenerator: FALLBACK: soname=%r" % soname
+
+ if Verbose:
+ print "_LibSonameGenerator: return soname=%r" % soname
-# Fix http://scons.tigris.org/issues/show_bug.cgi?id=2903 :
-# Ensure we still depend on SCons.Defaults.ShLinkAction command line which is $SHLINKCOM.
-# This was tricky because we don't want changing LIBPATH to cause a rebuild, but
-# changing other link args should. LIBPATH has $( ... $) around it but until this
-# fix, when the varlist was added to the build sig those ignored parts weren't getting
-# ignored.
-ShLibAction = SCons.Action.Action(VersionedSharedLibrary, None, varlist=['SHLINKCOM'])
+ return soname
+
+ShLibSonameGenerator = _LibSonameGenerator('ShLib')
+LdModSonameGenerator = _LibSonameGenerator('LdMod')
+
+def EmitLibSymlinks(env, symlinks, libnode):
+ """Used by emitters to handle (shared/versioned) library symlinks"""
+ Verbose = False
+ for linkname, linktgt in symlinks.iteritems():
+ env.SideEffect(linkname, linktgt)
+ if(Verbose):
+ print "EmitLibSymlinks: SideEffect(", linkname, ", ", linktgt, ")"
+ clean = list(set(filter(lambda x : x != linktgt, symlinks.keys() + [str(libnode)])))
+ env.Clean(linktgt, clean)
+ if(Verbose):
+ print "EmitLibSymlinks: Clean(%r,%r)" % (linktgt, clean)
+
+def CreateLibSymlinks(env, symlinks):
+ """Physically creates symlinks. The symlinks argument must be a dict in
+ form { linkname : linktarget }
+ """
+
+ Verbose = False
+ for linkname, linktgt in symlinks.iteritems():
+ linkname = str(env.arg2nodes(linkname)[0])
+ linkdir = os.path.dirname(linkname)
+ if linkdir:
+ # NOTE: os.path.relpath appears in python 2.6
+ linktgt = os.path.relpath(linktgt, linkdir)
+ else:
+ linktgt = os.path.basename(linktgt)
+ if(Verbose):
+ print "CreateLibSymlinks: preparing to add symlink ", linkname, " -> ", linktgt
+ try:
+ os.remove(linkname)
+ except:
+ pass
+ os.symlink(linktgt, linkname)
+ if(Verbose):
+ print "CreateLibSymlinks: add symlink ", linkname, " -> ", linktgt
+ return 0
+
+def LibSymlinksActionFunction(target, source, env):
+ for tgt in target:
+ symlinks = getattr(getattr(tgt,'attributes', None), 'shliblinks', None)
+ if symlinks:
+ CreateLibSymlinks(env, symlinks)
+ return 0
+
+LibSymlinksAction = SCons.Action.Action(LibSymlinksActionFunction, None)
def createSharedLibBuilder(env):
"""This is a utility function that creates the SharedLibrary
@@ -393,11 +547,12 @@ def createSharedLibBuilder(env):
except KeyError:
import SCons.Defaults
action_list = [ SCons.Defaults.SharedCheck,
- ShLibAction ]
+ SCons.Defaults.ShLinkAction,
+ LibSymlinksAction ]
shared_lib = SCons.Builder.Builder(action = action_list,
emitter = "$SHLIBEMITTER",
prefix = '$SHLIBPREFIX',
- suffix = '$SHLIBSUFFIX',
+ suffix = ShLibSuffixGenerator,
target_scanner = ProgramScanner,
src_suffix = '$SHOBJSUFFIX',
src_builder = 'SharedObject')
@@ -417,11 +572,12 @@ def createLoadableModuleBuilder(env):
except KeyError:
import SCons.Defaults
action_list = [ SCons.Defaults.SharedCheck,
- SCons.Defaults.LdModuleLinkAction ]
+ SCons.Defaults.LdModuleLinkAction,
+ LibSymlinksAction ]
ld_module = SCons.Builder.Builder(action = action_list,
emitter = "$LDMODULEEMITTER",
prefix = '$LDMODULEPREFIX',
- suffix = '$LDMODULESUFFIX',
+ suffix = LdModSuffixGenerator,
target_scanner = ProgramScanner,
src_suffix = '$SHOBJSUFFIX',
src_builder = 'SharedObject')
diff --git a/src/engine/SCons/Tool/__init__.xml b/src/engine/SCons/Tool/__init__.xml
index ee56fc3d..7102fa4d 100644
--- a/src/engine/SCons/Tool/__init__.xml
+++ b/src/engine/SCons/Tool/__init__.xml
@@ -464,6 +464,17 @@ as C++ files.
</summary>
</cvar>
+<cvar name="IMPLIBVERSION">
+<summary>
+<para>
+Used to override &cv-link-SHLIBVERSION;/&cv-link-LDMODULEVERSION; when
+generating versioned import library for a shared library/loadable module. If
+undefined, the &cv-link-SHLIBVERSION;/&cv-link-LDMODULEVERSION; is used do
+determine the version of versioned import library.
+</para>
+</summary>
+</cvar>
+
<cvar name="LIBEMITTER">
<summary>
<para>
@@ -472,6 +483,21 @@ TODO
</summary>
</cvar>
+<cvar name="LDMODULEVERSION">
+<summary>
+<para>
+When this construction variable is defined, a versioned loadable module
+is created by &b-link-LoadableModule; builder. This activates the
+&cv-link-_LDMODULEVERSIONFLAGS; and thus modifies the &cv-link-LDMODULECOM; as
+required, adds the version number to the library name, and creates the symlinks
+that are needed. &cv-link-LDMODULEVERSION; needs to be of the form X.Y.Z, where
+X and Y are numbers, and Z is a number but can also contain letters to
+designate alpha, beta, or release candidate patch levels. By default
+&cv-link-LDMODULEVERSION; is set to $SHLIBVERSION.
+</para>
+</summary>
+</cvar>
+
<cvar name="SHLIBEMITTER">
<summary>
<para>
@@ -492,11 +518,12 @@ TODO
<summary>
<para>
When this construction variable is defined, a versioned shared library
-is created. This modifies the &cv-link-SHLINKFLAGS; as required, adds
-the version number to the library name, and creates the symlinks that
-are needed. &cv-link-SHLIBVERSION; needs to be of the form X.Y.Z,
-where X and Y are numbers, and Z is a number but can also contain
-letters to designate alpha, beta, or release candidate patch levels.
+is created by &b-link-SharedLibrary; builder. This activates the
+&cv-link-_SHLIBVERSIONFLAGS; and thus modifies the &cv-link-SHLINKCOM; as
+required, adds the version number to the library name, and creates the symlinks
+that are needed. &cv-link-SHLIBVERSION; needs to be of the form X.Y.Z, where X
+and Y are numbers, and Z is a number but can also contain letters to designate
+alpha, beta, or release candidate patch levels.
</para>
</summary>
</cvar>
diff --git a/src/engine/SCons/Tool/cyglink.py b/src/engine/SCons/Tool/cyglink.py
index 87716cf9..40339781 100644
--- a/src/engine/SCons/Tool/cyglink.py
+++ b/src/engine/SCons/Tool/cyglink.py
@@ -7,19 +7,26 @@ It will usually be imported through the generic SCons.Tool.Tool()
selection method.
"""
+import re
+import os
import SCons.Action
import SCons.Util
+import SCons.Tool
import gnulink
-def shlib_generator(target, source, env, for_signature):
- cmd = SCons.Util.CLVar(['$SHLINK'])
+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, 'SHLIBPREFIX', 'SHLIBSUFFIX')
+ dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp)
if dll: cmd.extend(['-o', dll])
- cmd.extend(['$SHLINKFLAGS', '$__RPATH'])
+ cmd.extend(['$SHLINKFLAGS', '$__%sVERSIONFLAGS' % vp, '$__RPATH'])
implib = env.FindIxes(target, 'IMPLIBPREFIX', 'IMPLIBSUFFIX')
if implib:
@@ -35,15 +42,34 @@ def shlib_generator(target, source, env, for_signature):
return [cmd]
-def shlib_emitter(target, source, env):
- dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX')
+
+def shlib_generator(target, source, env, for_signature):
+ return _lib_generator(target, source, env, for_signature,
+ varprefix='SHLIB',
+ cmd = SCons.Util.CLVar(['$SHLINK']))
+
+def ldmod_generator(target, source, env, for_signature):
+ return _lib_generator(target, source, env, for_signature,
+ varprefix='LDMODULE',
+ cmd = SCons.Util.CLVar(['$LDMODULE']))
+
+def _lib_emitter(target, source, env, **kw):
+ Verbose = False
+
+ try: vp = kw['varprefix']
+ except KeyError: vp = 'SHLIB'
+
+ try: libtype = kw['libtype']
+ except KeyError: libtype = 'ShLib'
+
+ dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp)
no_import_lib = env.get('no_import_lib', 0)
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("$SHLIBSUFFIX"))
+ 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('$SHLIBPREFIX')
+ pre = env.subst('$%sPREFIX' % vp)
if dll.name[len(pre):len(pre)+3] == 'lib':
dll.name = pre + dll.name[len(pre)+3:]
@@ -55,17 +81,90 @@ def shlib_emitter(target, source, env):
if not no_import_lib:
# Create list of target libraries as strings
target_strings = env.ReplaceIxes(orig_target[0],
- 'SHLIBPREFIX', 'SHLIBSUFFIX',
+ '%sPREFIX' % vp, '%sSUFFIX' % vp,
'IMPLIBPREFIX', 'IMPLIBSUFFIX')
implib_target = env.fs.File(target_strings)
+ if Verbose:
+ print "_lib_emitter: implib_target=%r" % str(implib_target)
implib_target.attributes.shared = 1
target.append(implib_target)
+ symlinks = SCons.Tool.ImpLibSymlinkGenerator(env, implib_target,
+ implib_libtype=libtype,
+ generator_libtype=libtype+'ImpLib')
+ if Verbose:
+ print "_lib_emitter: implib symlinks=%r" % symlinks
+ if symlinks:
+ SCons.Tool.EmitLibSymlinks(env, symlinks, implib_target)
+ implib_target.attributes.shliblinks = symlinks
+
return (target, source)
+
+def shlib_emitter(target, source, env):
+ return _lib_emitter(target, source, env, varprefix='SHLIB', libtype='ShLib')
+
+def ldmod_emitter(target, source, env):
+ return _lib_emitter(target, source, env, varprefix='LDMODULE', libtype='LdMod')
+def _versioned_lib_suffix(env, suffix, version):
+ """Generate versioned shared library suffix from a unversioned one.
+ If suffix='.dll', and version='0.1.2', then it returns '-0-1-2.dll'"""
+ Verbose = False
+ if Verbose:
+ print "_versioned_lib_suffix: suffix= ", suffix
+ print "_versioned_lib_suffix: version= ", version
+ cygversion = re.sub('\.', '-', version)
+ if not suffix.startswith('-' + cygversion):
+ suffix = '-' + cygversion + suffix
+ if Verbose:
+ print "_versioned_lib_suffix: return suffix= ", suffix
+ return suffix
+
+def _versioned_implib_name(env, libnode, version, suffix, **kw):
+ import link
+ generator = SCons.Tool.ImpLibSuffixGenerator
+ libtype = kw['libtype']
+ return link._versioned_lib_name(env, libnode, version, suffix, generator, implib_libtype=libtype)
+
+def _versioned_implib_symlinks(env, libnode, version, suffix, **kw):
+ """Generate link names that should be created for a versioned shared lirbrary.
+ Returns a dictionary in the form { linkname : linktarget }
+ """
+ Verbose = False
+
+ if Verbose:
+ print "_versioned_implib_symlinks: str(libnode)=%r" % str(libnode)
+ print "_versioned_implib_symlinks: version=%r" % version
+
+ try: libtype = kw['libtype']
+ except KeyError: libtype = 'ShLib'
+
+ symlinks = {}
+
+ linkdir = os.path.dirname(str(libnode))
+ if Verbose:
+ print "_versioned_implib_symlinks: linkdir=%r" % linkdir
+
+ name = SCons.Tool.ImpLibNameGenerator(env, libnode,
+ implib_libtype=libtype,
+ generator_libtype=libtype+'ImpLib')
+ if Verbose:
+ print "_versioned_implib_symlinks: name=%r" % name
+
+ major = version.split('.')[0]
+
+ link0 = os.path.join(str(linkdir), name)
+
+ symlinks[link0] = str(libnode)
+
+ if Verbose:
+ print "_versioned_implib_symlinks: return symlinks=%r" % symlinks
+
+ return symlinks
shlib_action = SCons.Action.Action(shlib_generator, generator=1)
+ldmod_action = SCons.Action.Action(ldmod_generator, generator=1)
def generate(env):
"""Add Builders and construction variables for cyglink to an Environment."""
@@ -74,8 +173,9 @@ def generate(env):
env['LINKFLAGS'] = SCons.Util.CLVar('-Wl,-no-undefined')
env['SHLINKCOM'] = shlib_action
- env['LDMODULECOM'] = shlib_action
+ env['LDMODULECOM'] = ldmod_action
env.Append(SHLIBEMITTER = [shlib_emitter])
+ env.Append(LDMODULEEMITTER = [ldmod_emitter])
env['SHLIBPREFIX'] = 'cyg'
env['SHLIBSUFFIX'] = '.dll'
@@ -83,6 +183,34 @@ def generate(env):
env['IMPLIBPREFIX'] = 'lib'
env['IMPLIBSUFFIX'] = '.dll.a'
+ # Variables used by versioned shared libraries
+ env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS'
+ env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS'
+
+ # SHLIBVERSIONFLAGS and LDMODULEVERSIONFLAGS are same as in gnulink...
+
+ env['GenerateVersionedShLibSuffix'] = _versioned_lib_suffix
+ env['GenerateVersionedLdModSuffix'] = _versioned_lib_suffix
+ env['GenerateVersionedImpLibSuffix'] = _versioned_lib_suffix
+ env['GenerateVersionedShLibImpLibName'] = lambda *args: _versioned_implib_name(*args, libtype='ShLib')
+ env['GenerateVersionedLdModImpLibName'] = lambda *args: _versioned_implib_name(*args, libtype='LdMod')
+ env['GenerateVersionedShLibImpLibSymlinks'] = lambda *args: _versioned_implib_symlinks(*args, libtype='ShLib')
+ env['GenerateVersionedLdModImpLibSymlinks'] = lambda *args: _versioned_implib_symlinks(*args, libtype='LdMod')
+
+ def trydel(env, key):
+ try: del env[key]
+ except KeyError: pass
+
+ # these variables were set by gnulink but are not used in cyglink
+ trydel(env,'_SHLINKSONAME')
+ trydel(env,'_LDMODULESONAME')
+ trydel(env,'ShLibSonameGenerator')
+ trydel(env,'LdModSonameGenerator')
+ trydel(env,'GenerateVersionedShLibSymlinks')
+ trydel(env,'GenerateVersionedLdModSymlinks')
+ trydel(env,'GenerateVersionedShLibSoname')
+ trydel(env,'GenerateVersionedLdModSoname')
+
def exists(env):
return gnulink.exists(env)
diff --git a/src/engine/SCons/Tool/cyglink.xml b/src/engine/SCons/Tool/cyglink.xml
new file mode 100644
index 00000000..42208f1a
--- /dev/null
+++ b/src/engine/SCons/Tool/cyglink.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
+
+<!DOCTYPE sconsdoc [
+<!ENTITY % scons SYSTEM '../../../../doc/scons.mod'>
+%scons;
+<!ENTITY % builders-mod SYSTEM '../../../../doc/generated/builders.mod'>
+%builders-mod;
+<!ENTITY % functions-mod SYSTEM '../../../../doc/generated/functions.mod'>
+%functions-mod;
+<!ENTITY % tools-mod SYSTEM '../../../../doc/generated/tools.mod'>
+%tools-mod;
+<!ENTITY % variables-mod SYSTEM '../../../../doc/generated/variables.mod'>
+%variables-mod;
+]>
+
+<sconsdoc xmlns="http://www.scons.org/dbxsd/v1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd">
+
+<tool name="cyglink">
+<summary>
+<para>
+Set construction variables for cygwin linker/loader.
+</para>
+</summary>
+<sets>
+<item>IMPLIBPREFIX</item>
+<item>IMPLIBSUFFIX</item>
+<item>LDMODULEVERSIONFLAGS</item>
+<item>LINKFLAGS</item>
+<item>RPATHPREFIX</item>
+<item>RPATHSUFFIX</item>
+<item>SHLIBPREFIX</item>
+<item>SHLIBSUFFIX</item>
+<item>SHLIBVERSIONFLAGS</item>
+<item>SHLINKCOM</item>
+<item>SHLINKFLAGS</item>
+<item>_LDMODULEVERSIONFLAGS</item>
+<item>_SHLIBVERSIONFLAGS</item>
+</sets>
+</tool>
+
+</sconsdoc>
diff --git a/src/engine/SCons/Tool/gnulink.py b/src/engine/SCons/Tool/gnulink.py
index 3dc8f51b..ea0ca5af 100644
--- a/src/engine/SCons/Tool/gnulink.py
+++ b/src/engine/SCons/Tool/gnulink.py
@@ -34,9 +34,97 @@ selection method.
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import SCons.Util
+import SCons.Tool
+import os
+import sys
+import re
import link
+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" % suffix
+ print "_versioned_lib_suffix: version=%r" % version
+ if not suffix.endswith(version):
+ suffix = suffix + '.' + version
+ if Verbose:
+ print "_versioned_lib_suffix: return suffix=%r" % suffix
+ return suffix
+
+def _versioned_lib_soname(env, libnode, version, suffix, name_generator):
+ """For libnode='/optional/dir/libfoo.so.X.Y.Z' it returns 'libfoo.so.X'"""
+ Verbose = False
+ if Verbose:
+ print "_versioned_lib_soname: version=%r" % version
+ name = name_generator(env, libnode)
+ if Verbose:
+ print "_versioned_lib_soname: name=%r" % name
+ major = version.split('.')[0]
+ soname = name + '.' + major
+ if Verbose:
+ print "_versioned_lib_soname: soname=%r" % soname
+ return soname
+
+def _versioned_shlib_soname(env, libnode, version, suffix):
+ generator = SCons.Tool.ShLibNameGenerator
+ return _versioned_lib_soname(env, libnode, version, suffix, generator)
+
+def _versioned_ldmod_soname(env, libnode, version, suffix):
+ generator = SCons.Tool.LdModNameGenerator
+ return _versioned_lib_soname(env, libnode, version, suffix, generator)
+
+def _versioned_lib_symlinks(env, libnode, version, suffix, name_generator, soname_generator):
+ """Generate link names that should be created for a versioned shared lirbrary.
+ Returns a dictionary in the form { linkname : linktarget }
+ """
+ Verbose = False
+
+ if Verbose:
+ print "_versioned_lib_symlinks: str(libnode)=%r" % str(libnode)
+ print "_versioned_lib_symlinks: version=%r" % version
+
+ symlinks = {}
+
+ 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" % symlinks
+ return symlinks
+
+ linkdir = os.path.dirname(str(libnode))
+ if Verbose:
+ print "_versioned_lib_symlinks: linkdir=%r" % linkdir
+
+ name = name_generator(env, libnode)
+ if Verbose:
+ print "_versioned_lib_symlinks: name=%r" % name
+
+ soname = soname_generator(env, libnode)
+
+ link0 = os.path.join(str(linkdir), soname)
+ link1 = os.path.join(str(linkdir), name)
+
+ symlinks[link0] = str(libnode)
+ symlinks[link1] = link0
+
+ if Verbose:
+ print "_versioned_lib_symlinks: return symlinks=%r" % symlinks
+
+ return symlinks
+
+def _versioned_shlib_symlinks(env, libnode, version, suffix):
+ name_generator = SCons.Tool.ShLibNameGenerator
+ soname_generator = SCons.Tool.ShLibSonameGenerator
+ return _versioned_lib_symlinks(env, libnode, version, suffix, name_generator, soname_generator)
+
+def _versioned_ldmod_symlinks(env, libnode, version, suffix):
+ name_generator = SCons.Tool.LdModNameGenerator
+ soname_generator = SCons.Tool.LdModSonameGenerator
+ return _versioned_lib_symlinks(env, libnode, version, suffix, name_generator, soname_generator)
+
def generate(env):
"""Add Builders and construction variables for gnulink to an Environment."""
link.generate(env)
@@ -49,6 +137,35 @@ def generate(env):
env['RPATHPREFIX'] = '-Wl,-rpath='
env['RPATHSUFFIX'] = ''
env['_RPATH'] = '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}'
+
+ # 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).
+ if sys.platform.startswith('openbsd'):
+ # OpenBSD doesn't usually use SONAME for libraries
+ env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS'
+ env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS'
+ else:
+ env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS -Wl,-soname=$_SHLINKSONAME'
+ env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS -Wl,-soname=$_LDMODULESONAME'
+ env['SHLIBVERSIONFLAGS'] = SCons.Util.CLVar('-Wl,-Bsymbolic')
+ env['LDMODULEVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS'
+
+ # libfoo.so.X.Y.Z -> libfoo.so.X
+ env['_SHLINKSONAME'] = '${ShLibSonameGenerator(__env__,TARGET)}'
+ env['_LDMODULESONAME'] = '${LdModSonameGenerator(__env__,TARGET)}'
+
+ env['ShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator
+ env['LdModSonameGenerator'] = SCons.Tool.LdModSonameGenerator
+
+ env['GenerateVersionedShLibSuffix'] = _versioned_lib_suffix
+ env['GenerateVersionedLdModSuffix'] = _versioned_lib_suffix
+ env['GenerateVersionedShLibSymlinks'] = _versioned_shlib_symlinks
+ env['GenerateVersionedLdModSymlinks'] = _versioned_ldmod_symlinks
+ env['GenerateVersionedShLibName'] = link._versioned_shlib_name
+ env['GenerateVersionedLdModName'] = link._versioned_ldmod_name
+ env['GenerateVersionedShLibSoname'] = _versioned_shlib_soname
+ env['GenerateVersionedLdModSoname'] = _versioned_shlib_soname
def exists(env):
# TODO: sync with link.smart_link() to choose a linker
diff --git a/src/engine/SCons/Tool/gnulink.xml b/src/engine/SCons/Tool/gnulink.xml
index 2a36de2f..63ce0f49 100644
--- a/src/engine/SCons/Tool/gnulink.xml
+++ b/src/engine/SCons/Tool/gnulink.xml
@@ -33,6 +33,10 @@ Set construction variables for GNU linker/loader.
<item>SHLINKFLAGS</item>
<item>RPATHPREFIX</item>
<item>RPATHSUFFIX</item>
+<item>_LDMODULESONAME</item>
+<item>_SHLINKSONAME</item>
+<item>LDMODULEVERSIONFLAGS</item>
+<item>SHLIBVERSIONFLAGS</item>
</sets>
</tool>
diff --git a/src/engine/SCons/Tool/install.py b/src/engine/SCons/Tool/install.py
index 9f2e937b..c5c2adbb 100644
--- a/src/engine/SCons/Tool/install.py
+++ b/src/engine/SCons/Tool/install.py
@@ -38,6 +38,7 @@ import shutil
import stat
import SCons.Action
+import SCons.Tool
from SCons.Util import make_path_relative
#
@@ -141,98 +142,34 @@ def copyFuncVersionedLib(dest, source, env):
shutil.copy2(source, dest)
st = os.stat(source)
os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
- versionedLibLinks(dest, source, env)
+ installShlibLinks(dest, source, env)
return 0
-def versionedLibVersion(dest, source, env):
- """Check if dest is a version shared library name. Return version, libname, & install_dir if it is."""
- Verbose = False
- platform = env.subst('$PLATFORM')
- if not (platform == 'posix' or platform == 'darwin' or platform == 'sunos'):
- return (None, None, None)
-
- if (hasattr(source[0], 'attributes') and
- hasattr(source[0].attributes, 'shlibname')):
- libname = source[0].attributes.shlibname
- else:
- libname = os.path.basename(str(dest))
+def listShlibLinksToInstall(dest, source, env):
+ install_links = {}
install_dir = os.path.dirname(str(dest))
- shlib_suffix = env.subst('$SHLIBSUFFIX')
- # See if the source name is a versioned shared library, get the version number
- result = False
-
- version_re = re.compile("[0-9]+\\.[0-9]+\\.[0-9a-zA-Z]+")
- version_File = None
- if platform == 'posix' or platform == 'sunos':
- # handle unix names
- versioned_re = re.compile(re.escape(shlib_suffix + '.') + "[0-9]+\\.[0-9]+\\.[0-9a-zA-Z]+")
- result = versioned_re.findall(libname)
- if result:
- version_File = version_re.findall(versioned_re.findall(libname)[-1])[-1]
- elif platform == 'darwin':
- # handle OSX names
- versioned_re = re.compile("\\.[0-9]+\\.[0-9]+\\.[0-9a-zA-Z]+" + re.escape(shlib_suffix) )
- result = versioned_re.findall(libname)
- if result:
- version_File = version_re.findall(versioned_re.findall(libname)[-1])[-1]
-
- if Verbose:
- print "install: version_File ", version_File
- # result is False if we did not find a versioned shared library name, so return and empty list
- if not result:
- return (None, libname, install_dir)
-
- version = None
- # get version number from the environment
- try:
- version = env.subst('$SHLIBVERSION')
- except KeyError:
- version = None
-
- if version != version_File:
- #raise SCons.Errors.UserError("SHLIBVERSION '%s' does not match the version # '%s' in the filename" % (version, version_File) )
- print "SHLIBVERSION '%s' does not match the version # '%s' in the filename, proceeding based on file name" % (version, version_File)
- version = version_File
- return (version, libname, install_dir)
-
-def versionedLibLinks(dest, source, env):
+ source = env.arg2nodes(source)
+ for src in source:
+ links = getattr(getattr(src,'attributes',None), 'shliblinks', None)
+ if SCons.Util.is_Dict(links):
+ for linkname, linktgt in links.iteritems():
+ linkname_base = os.path.basename(str(linkname))
+ linktgt_base = os.path.basename(str(linktgt))
+ install_linkname = os.path.join(install_dir, linkname_base)
+ install_linktgt = os.path.join(install_dir, linktgt_base)
+ install_links[install_linkname] = install_linktgt
+ return install_links
+
+def installShlibLinks(dest, source, env):
"""If we are installing a versioned shared library create the required links."""
Verbose = False
- linknames = []
- version, libname, install_dir = versionedLibVersion(dest, source, env)
-
- if version != None:
- # libname includes the version number if one was given
- linknames = SCons.Tool.VersionShLibLinkNames(version,libname,env)
- if Verbose:
- print "versionedLibLinks: linknames ",linknames
- # Here we just need the file name w/o path as the target of the link
- lib_ver = libname
- # make symlink of adjacent names in linknames
- for count in range(len(linknames)):
- linkname = linknames[count]
- fulllinkname = os.path.join(install_dir, linkname)
- if Verbose:
- print "full link name ",fulllinkname
- if count > 0:
- try:
- os.remove(lastlinkname)
- except:
- pass
- os.symlink(os.path.basename(fulllinkname),lastlinkname)
- if Verbose:
- print "versionedLibLinks: made sym link of %s -> %s" % (lastlinkname,os.path.basename(fulllinkname))
- lastlinkname = fulllinkname
- # finish chain of sym links with link to the actual library
- if len(linknames)>0:
- try:
- os.remove(lastlinkname)
- except:
- pass
- os.symlink(lib_ver,lastlinkname)
- if Verbose:
- print "versionedLibLinks: made sym link of %s -> %s" % (lib_ver,lastlinkname)
+
+ symlinks = listShlibLinksToInstall(dest, source, env)
+ if Verbose:
+ print 'installShlibLinks: symlinks=%r' % symlinks
+ if symlinks:
+ SCons.Tool.CreateLibSymlinks(env, symlinks)
return
def installFunc(target, source, env):
@@ -306,22 +243,11 @@ def add_versioned_targets_to_INSTALLED_FILES(target, source, env):
Verbose = False
_INSTALLED_FILES.extend(target)
if Verbose:
- print "ver lib emitter ",repr(target)
-
- # see if we have a versioned shared library, if so generate side effects
- version, libname, install_dir = versionedLibVersion(target[0], source, env)
- if version != None:
- # generate list of link names
- linknames = SCons.Tool.VersionShLibLinkNames(version,libname,env)
- for linkname in linknames:
- if Verbose:
- print "make side effect of %s" % os.path.join(install_dir, linkname)
- fulllinkname = os.path.join(install_dir, linkname)
- env.SideEffect(fulllinkname,target[0])
- env.Clean(target[0],fulllinkname)
- _INSTALLED_FILES.append(fulllinkname)
- if Verbose:
- print "installed list ", _INSTALLED_FILES
+ print "add_versioned_targets_to_INSTALLED_FILES: target=%r" % map(str, target)
+
+ symlinks = listShlibLinksToInstall(target[0], source, env)
+ if symlinks:
+ SCons.Tool.EmitLibSymlinks(env, symlinks, target[0])
_UNIQUE_INSTALLED_FILES = None
return (target, source)
diff --git a/src/engine/SCons/Tool/install.xml b/src/engine/SCons/Tool/install.xml
index 0aa93843..6ae3e307 100644
--- a/src/engine/SCons/Tool/install.xml
+++ b/src/engine/SCons/Tool/install.xml
@@ -82,20 +82,13 @@ env.InstallAs(target = ['../lib/libfoo.a', '../lib/libbar.a'],
<builder name="InstallVersionedLib">
<summary>
<para>
-Installs a versioned shared library. The &cv-link-SHLIBVERSION;
-construction variable should be defined in the environment
-to confirm the version number in the library name.
-If &cv-link-SHLIBVERSION; is not defined a warning will be issued
-and the name of the library will be parsed to derive the version.
-The symlinks appropriate to the architecture will be generated.
+Installs a versioned shared library. The symlinks appropriate to the
+architecture will be generated based on symlinks of the source library.
</para>
<example_commands>
env.InstallVersionedLib(target = '/usr/local/bin/foo',
source = 'libxyz.1.5.2.so')
-env.InstallVersionedLib(target = '/usr/local/bin/foo',
- source = 'libxyz.1.5.2.so',
- SHLIBVERSION='1.5.2')
</example_commands>
</summary>
</builder>
diff --git a/src/engine/SCons/Tool/link.py b/src/engine/SCons/Tool/link.py
index a084bc4b..33e50d9e 100644
--- a/src/engine/SCons/Tool/link.py
+++ b/src/engine/SCons/Tool/link.py
@@ -33,9 +33,10 @@ selection method.
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+import sys
import re
+import os
-import SCons.Defaults
import SCons.Tool
import SCons.Util
import SCons.Warnings
@@ -72,97 +73,66 @@ def smart_link(source, target, env, for_signature):
return '$CXX'
return '$CC'
-def shlib_emitter(target, source, env):
+def _lib_emitter(target, source, env, **kw):
Verbose = False
- platform = env.subst('$PLATFORM')
+ if Verbose:
+ print "_lib_emitter: str(target[0])=%r" % str(target[0])
for tgt in target:
tgt.attributes.shared = 1
+
try:
- # target[0] comes in as libtest.so. Add the version extensions
- version = env.subst('$SHLIBVERSION')
- if version:
- version_names = shlib_emitter_names(target, source, env)
- # mark the target with the shared libraries name, including
- # the version number
- target[0].attributes.shlibname = version_names[0]
- shlib = env.File(version_names[0], directory=target[0].get_dir())
- target[0].attributes.shlibpath = shlib.get_internal_path()
- for name in version_names[1:]:
- env.SideEffect(name, shlib)
- env.Clean(shlib, name)
- if Verbose:
- print "shlib_emitter: add side effect - ",name
- env.Clean(shlib, target[0])
- return ([shlib], source)
+ symlink_generator = kw['symlink_generator']
except KeyError:
- version = None
+ pass
+ else:
+ if Verbose:
+ print "_lib_emitter: symlink_generator=%r" % symlink_generator
+ symlinks = symlink_generator(env, target[0])
+ if Verbose:
+ print "_lib_emitter: symlinks=%r" % symlinks
+
+ if symlinks:
+ SCons.Tool.EmitLibSymlinks(env, symlinks, target[0])
+ target[0].attributes.shliblinks = symlinks
return (target, source)
-def shlib_emitter_names(target, source, env):
- """Return list of file names that are side effects for a versioned library build. The first name in the list is the new name for the target"""
+def shlib_emitter(target, source, env):
+ return _lib_emitter(target, source, env, symlink_generator = SCons.Tool.ShLibSymlinkGenerator)
+
+def ldmod_emitter(target, source, env):
+ return _lib_emitter(target, source, env, symlink_generator = SCons.Tool.LdModSymlinkGenerator)
+
+# This is generic enough to be included here...
+def _versioned_lib_name(env, libnode, version, suffix, suffix_generator, **kw):
+ """For libnode='/optional/dir/libfoo.so.X.Y.Z' it returns 'libfoo.so'"""
Verbose = False
- platform = env.subst('$PLATFORM')
- version_names = []
- try:
- # target[0] comes in as libtest.so. Add the version extensions
- version = env.subst('$SHLIBVERSION')
- if version.count(".") != 2:
- # We need a version of the form x.y.z to proceed
- raise ValueError
- if version:
- if platform == 'posix' or platform == 'sunos':
- versionparts = version.split('.')
- if hasattr(target[0].attributes, 'shlibname'):
- name = target[0].attributes.shlibname
- else:
- name = target[0].name
- # generate library name with the version number
- version_name = name + '.' + version
- if Verbose:
- print "shlib_emitter_names: target is ", version_name
- print "shlib_emitter_names: side effect: ", name
- # add version_name to list of names to be a Side effect
- version_names.append(version_name)
- if Verbose:
- print "shlib_emitter_names: versionparts ",versionparts
- for ver in versionparts[0:-1]:
- name = name + '.' + ver
- if Verbose:
- print "shlib_emitter_names: side effect: ", name
- # add name to list of names to be a Side effect
- version_names.append(name)
- elif platform == 'darwin':
- shlib_suffix = env.subst('$SHLIBSUFFIX')
- if hasattr(target[0].attributes, 'shlibname'):
- name = target[0].attributes.shlibname
- else:
- name = target[0].name
- # generate library name with the version number
- suffix_re = re.escape(shlib_suffix)
- version_name = re.sub(suffix_re, '.' + version + shlib_suffix, name)
- if Verbose:
- print "shlib_emitter_names: target is ", version_name
- print "shlib_emitter_names: side effect: ", name
- # add version_name to list of names to be a Side effect
- version_names.append(version_name)
- elif platform == 'cygwin':
- shlib_suffix = env.subst('$SHLIBSUFFIX')
- if hasattr(target[0].attributes, 'shlibname'):
- name = target[0].attributes.shlibname
- else:
- name = target[0].name
- # generate library name with the version number
- suffix_re = re.escape(shlib_suffix)
- version_name = re.sub(suffix_re, '-' + re.sub('\.', '-', version) + shlib_suffix, name)
- if Verbose:
- print "shlib_emitter_names: target is ", version_name
- print "shlib_emitter_names: side effect: ", name
- # add version_name to list of names to be a Side effect
- version_names.append(version_name)
- except KeyError:
- version = None
- return version_names
+ if Verbose:
+ print "_versioned_lib_name: version=%r" % version
+
+ versioned_name = os.path.basename(str(libnode))
+ if Verbose:
+ print "_versioned_lib_name: versioned_name=%r" % versioned_name
+
+ if Verbose:
+ print "_versioned_lib_name: suffix=%r" % suffix
+
+ versioned_suffix = suffix_generator(env, **kw)
+
+ versioned_suffix_re = re.escape(versioned_suffix) + '$'
+ name = re.sub(versioned_suffix_re, suffix, versioned_name)
+ if Verbose:
+ print "_versioned_lib_name: name=%r" % name
+ return name
+
+def _versioned_shlib_name(env, libnode, version, suffix, **kw):
+ generator = SCons.Tool.ShLibSuffixGenerator
+ return _versioned_lib_name(env, libnode, version, suffix, generator, **kw)
+
+def _versioned_ldmod_name(env, libnode, version, suffix, **kw):
+ generator = SCons.Tool.LdModSuffixGenerator
+ return _versioned_lib_name(env, libnode, version, suffix, generator, **kw)
+
def generate(env):
"""Add Builders and construction variables for gnulink to an Environment."""
@@ -171,7 +141,7 @@ def generate(env):
env['SHLINK'] = '$LINK'
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared')
- env['SHLINKCOM'] = '$SHLINK -o $TARGET $SHLINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
+ env['SHLINKCOM'] = '$SHLINK -o $TARGET $SHLINKFLAGS $__SHLIBVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
# don't set up the emitter, cause AppendUnique will generate a list
# starting with None :-(
env.Append(SHLIBEMITTER = [shlib_emitter])
@@ -196,15 +166,13 @@ def generate(env):
# setting them the same means that LoadableModule works everywhere.
SCons.Tool.createLoadableModuleBuilder(env)
env['LDMODULE'] = '$SHLINK'
- # don't set up the emitter, cause AppendUnique will generate a list
- # starting with None :-(
- env.Append(LDMODULEEMITTER='$SHLIBEMITTER')
+ env.Append(LDMODULEEMITTER = [ldmod_emitter])
env['LDMODULEPREFIX'] = '$SHLIBPREFIX'
env['LDMODULESUFFIX'] = '$SHLIBSUFFIX'
env['LDMODULEFLAGS'] = '$SHLINKFLAGS'
- env['LDMODULECOM'] = '$LDMODULE -o $TARGET $LDMODULEFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
-
-
+ 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/src/engine/SCons/Tool/link.xml b/src/engine/SCons/Tool/link.xml
index d58b9e26..52349da0 100644
--- a/src/engine/SCons/Tool/link.xml
+++ b/src/engine/SCons/Tool/link.xml
@@ -41,11 +41,16 @@ Sets construction variables for generic POSIX linkers.
<item>LIBLINKPREFIX</item>
<item>LIBLINKSUFFIX</item>
<item>SHLIBSUFFIX</item>
+<item>__SHLIBVERSIONFLAGS</item>
<item>LDMODULE</item>
<item>LDMODULEPREFIX</item>
<item>LDMODULESUFFIX</item>
<item>LDMODULEFLAGS</item>
<item>LDMODULECOM</item>
+<item>LDMODULEVERSION</item>
+<item>LDMODULENOVERSIONSYMLINKS</item>
+<item>LDMODULEVERSIONFLAGS</item>
+<item>__LDMODULEVERSIONFLAGS</item>
</sets>
<uses>
<item>SHLINKCOMSTR</item>
@@ -54,6 +59,105 @@ Sets construction variables for generic POSIX linkers.
</uses>
</tool>
+<cvar name="__LDMODULEVERSIONFLAGS">
+<summary>
+<para>
+This construction variable automatically introduces &cv-link-_LDMODULEVERSIONFLAGS;
+if &cv-link-LDMODULEVERSION; is set. Othervise it evaluates to an empty string.
+</para>
+</summary>
+</cvar>
+
+<cvar name="__SHLIBVERSIONFLAGS">
+<summary>
+<para>
+This construction variable automatically introduces &cv-link-_SHLIBVERSIONFLAGS;
+if &cv-link-SHLIBVERSION; is set. Othervise it evaluates to an empty string.
+</para>
+</summary>
+</cvar>
+
+<cvar name="_LDMODULESONAME">
+<summary>
+<para>
+A macro that automatically generates loadable module's SONAME based on $TARGET,
+$LDMODULEVERSION and $LDMODULESUFFIX. Used by &b-link-LoadableModule; builder
+when the linker tool supports SONAME (e.g. &t-link-gnulink;).
+</para>
+</summary>
+</cvar>
+
+<cvar name="_LDMODULEVERSIONFLAGS">
+<summary>
+<para>
+This macro automatically introduces extra flags to &cv-link-LDMODULECOM; when
+building versioned &b-link-LoadableModule; (that is when
+&cv-link-LDMODULEVERSION; is set). <literal>_LDMODULEVERSIONFLAGS</literal>
+usually adds &cv-link-SHLIBVERSIONFLAGS; and some extra dynamically generated
+options (such as <literal>-Wl,-soname=$_LDMODULESONAME</literal>). It is unused
+by plain (unversioned) loadable modules.
+</para>
+</summary>
+</cvar>
+
+<cvar name="_SHLIBVERSIONFLAGS">
+<summary>
+<para>
+This macro automatically introduces extra flags to &cv-link-SHLINKCOM; when
+building versioned &b-link-SharedLibrary; (that is when &cv-link-SHLIBVERSION;
+is set). <literal>_SHLIBVERSIONFLAGS</literal> usually adds &cv-link-SHLIBVERSIONFLAGS;
+and some extra dynamically generated options (such as
+<literal>-Wl,-soname=$_SHLINKSONAME</literal>. It is unused by "plain"
+(unversioned) shared libraries.
+</para>
+</summary>
+</cvar>
+
+<cvar name="_SHLINKSONAME">
+<summary>
+<para>
+A macro that automatically generates shared library's SONAME based on $TARGET,
+$SHLIBVERSION and $SHLIBSUFFIX. Used by &b-link-SharedLibrary; builder when
+the linker tool supports SONAME (e.g. &t-link-gnulink;).
+</para>
+</summary>
+</cvar>
+
+<cvar name="IMPLIBPREFIX">
+<summary>
+<para>
+The prefix used for import library names. For example, cygwin uses import
+libraries (<literal>libfoo.dll.a</literal>) in pair with dynamic libraries
+(<literal>cygfoo.dll</literal>). The &t-link-cyglink; linker sets
+&cv-link-IMPLIBPREFIX; to <literal>'lib'</literal> and &cv-link-SHLIBPREFIX;
+to <literal>'cyg'</literal>.
+</para>
+</summary>
+</cvar>
+
+<cvar name="IMPLIBSUFFIX">
+<summary>
+<para>
+The suffix used for import library names. For example, cygwin uses import
+libraries (<literal>libfoo.dll.a</literal>) in pair with dynamic libraries
+(<literal>cygfoo.dll</literal>). The &t-link-cyglink; linker sets
+&cv-link-IMPLIBSUFFIX; to <literal>'.dll.a'</literal> and &cv-link-SHLIBSUFFIX;
+to <literal>'.dll'</literal>.
+</para>
+</summary>
+</cvar>
+
+<cvar name="IMPLIBNOVERSIONSYMLINKS">
+<summary>
+<para>
+Used to override &cv-link-SHLIBNOVERSIONSYMLINKS;/&cv-link-LDMODULENOVERSIONSYMLINKS; when
+creating versioned import library for a shared library/loadable module. If not defined,
+then &cv-link-SHLIBNOVERSIONSYMLINKS;/&cv-link-LDMODULENOVERSIONSYMLINKS; is used to determine
+whether to disable symlink generation or not.
+</para>
+</summary>
+</cvar>
+
<cvar name="LDMODULE">
<summary>
<para>
@@ -92,6 +196,15 @@ General user options passed to the linker for building loadable modules.
</summary>
</cvar>
+<cvar name="LDMODULENOVERSIONSYMLINKS">
+<summary>
+<para>
+Instructs the &b-link-LoadableModule; builder to not automatically create symlinks
+for versioned modules. Defaults to <literal>$SHLIBNOVERSIONSYMLINKS</literal>
+</para>
+</summary>
+</cvar>
+
<cvar name="LDMODULEPREFIX">
<summary>
<para>
@@ -114,6 +227,16 @@ the same as $SHLIBSUFFIX.
</summary>
</cvar>
+<cvar name="LDMODULEVERSIONFLAGS">
+<summary>
+<para>
+Extra flags added to &cv-link-LDMODULECOM; when building versioned
+&b-link-LoadableModule;. These flags are only used when &cv-link-LDMODULEVERSION; is
+set.
+</para>
+</summary>
+</cvar>
+
<cvar name="LINK">
<summary>
<para>
@@ -169,6 +292,25 @@ for the variable that expands to library search path options.
</summary>
</cvar>
+<cvar name="SHLIBNOVERSIONSYMLINKS">
+<summary>
+<para>
+Instructs the &b-link-SharedLibrary; builder to not create symlinks for versioned
+shared libraries.
+</para>
+</summary>
+</cvar>
+
+<cvar name="SHLIBVERSIONFLAGS">
+<summary>
+<para>
+Extra flags added to &cv-link-SHLINKCOM; when building versioned
+&b-link-SharedLibrary;. These flags are only used when &cv-link-SHLIBVERSION; is
+set.
+</para>
+</summary>
+</cvar>
+
<cvar name="SHLINK">
<summary>
<para>
@@ -223,6 +365,18 @@ for the variable that expands to library search path options.
</summary>
</cvar>
+<cvar name="SONAME">
+<summary>
+<para>
+Variable used to hard-code SONAME for versioned shared library/loadable module.
+<example_commands>
+env.SharedLibrary('test', 'test.c', SHLIBVERSION='0.1.2', SONAME='libtest.so.2')
+</example_commands>
+The variable is used, for example, by &t-link-gnulink; linker tool.
+</para>
+</summary>
+</cvar>
+
<cvar name="STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME">
<summary>
<para>
diff --git a/src/engine/SCons/Tool/linkloc.py b/src/engine/SCons/Tool/linkloc.py
index 9c585619..bd643f7a 100644
--- a/src/engine/SCons/Tool/linkloc.py
+++ b/src/engine/SCons/Tool/linkloc.py
@@ -86,6 +86,7 @@ def generate(env):
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS')
env['SHLINKCOM'] = '${SUBST_CMD_FILE("$SHLINK $SHLINKFLAGS $_LIBDIRFLAGS $_LIBFLAGS -dll $TARGET $SOURCES")}'
env['SHLIBEMITTER']= None
+ env['LDMODULEEMITTER']= None
env['LINK'] = "linkloc"
env['LINKFLAGS'] = SCons.Util.CLVar('')
env['LINKCOM'] = '${SUBST_CMD_FILE("$LINK $LINKFLAGS $_LIBDIRFLAGS $_LIBFLAGS -exe $TARGET $SOURCES")}'
diff --git a/src/engine/SCons/Tool/mingw.py b/src/engine/SCons/Tool/mingw.py
index 601ec3b8..948ebe5e 100644
--- a/src/engine/SCons/Tool/mingw.py
+++ b/src/engine/SCons/Tool/mingw.py
@@ -146,6 +146,7 @@ def generate(env):
env['SHLINKCOM'] = shlib_action
env['LDMODULECOM'] = shlib_action
env.Append(SHLIBEMITTER = [shlib_emitter])
+ env.Append(LDMODULEEMITTER = [shlib_emitter])
env['AS'] = 'as'
env['WIN32DEFPREFIX'] = ''
diff --git a/src/engine/SCons/Tool/mslink.py b/src/engine/SCons/Tool/mslink.py
index 6606e107..1390c206 100644
--- a/src/engine/SCons/Tool/mslink.py
+++ b/src/engine/SCons/Tool/mslink.py
@@ -263,6 +263,7 @@ def generate(env):
env['_SHLINK_SOURCES'] = windowsShlinkSources
env['SHLINKCOM'] = compositeShLinkAction
env.Append(SHLIBEMITTER = [windowsLibEmitter])
+ env.Append(LDMODULEEMITTER = [windowsLibEmitter])
env['LINK'] = 'link'
env['LINKFLAGS'] = SCons.Util.CLVar('/nologo')
env['_PDB'] = pdbGenerator
diff --git a/src/engine/SCons/Tool/mwld.py b/src/engine/SCons/Tool/mwld.py
index e762d559..20676606 100644
--- a/src/engine/SCons/Tool/mwld.py
+++ b/src/engine/SCons/Tool/mwld.py
@@ -56,6 +56,7 @@ def generate(env):
env['SHLINKFLAGS'] = '$LINKFLAGS'
env['SHLINKCOM'] = shlib_action
env['SHLIBEMITTER']= shlib_emitter
+ env['LDMODULEEMITTER']= shlib_emitter
def exists(env):
diff --git a/src/engine/SCons/Tool/qt.py b/src/engine/SCons/Tool/qt.py
index 716c7d52..7bc0ef6d 100644
--- a/src/engine/SCons/Tool/qt.py
+++ b/src/engine/SCons/Tool/qt.py
@@ -320,6 +320,7 @@ def generate(env):
# correctly later by our emitter.
env.AppendUnique(PROGEMITTER =[AutomocStatic],
SHLIBEMITTER=[AutomocShared],
+ LDMODULEEMITTER=[AutomocShared],
LIBEMITTER =[AutomocStatic],
# Of course, we need to link against the qt libraries
CPPPATH=["$QT_CPPPATH"],
diff --git a/test/LINK/VersionedLib-j2.py b/test/LINK/VersionedLib-j2.py
new file mode 100644
index 00000000..076a4dd7
--- /dev/null
+++ b/test/LINK/VersionedLib-j2.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python
+#
+# __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__"
+
+"""
+Ensure that SharedLibrary builder works with SHLIBVERSION and -j2.
+This is regression test for:
+http://article.gmane.org/gmane.comp.programming.tools.scons.user/27049
+"""
+
+import TestSCons
+import os
+import sys
+
+import SCons.Platform
+
+test = TestSCons.TestSCons()
+
+test.write('foo.c', """
+#if _WIN32
+__declspec(dllexport)
+#endif
+int foo() { return 0; }
+""")
+
+
+test.write('main.c', """
+#if _WIN32
+__declspec(dllimport)
+#endif
+int foo();
+int main() { return foo(); }
+""")
+
+test.write('SConstruct', """
+env = Environment()
+env.AppendUnique(LIBPATH = ['.'])
+env.Program('main.c', LIBS = ['foo'])
+env.SharedLibrary('foo', 'foo.c', SHLIBVERSION = '0.1.2')
+""")
+
+test.run(arguments = ['-j 2', '--tree=all'])
+
+platform = SCons.Platform.platform_default()
+
+if platform == 'cygwin':
+ # PATH is used to search for *.dll librarier (cygfoo-0-2-1.dll in our case)
+ path = os.environ.get('PATH','')
+ if path: path = path + os.pathsep
+ path = path + test.workpath('.')
+ os.environ['PATH'] = path
+
+if os.name == 'posix':
+ os.environ['LD_LIBRARY_PATH'] = test.workpath('.')
+if sys.platform.find('irix') != -1:
+ os.environ['LD_LIBRARYN32_PATH'] = test.workpath('.')
+
+test.run(program = test.workpath('main'))
+
+test.run(arguments = ['-c'])
+
+platform = SCons.Platform.platform_default()
+
+if platform == 'posix':
+ # All (?) the files we expect will get created in the current directory
+ files = [
+ 'libfoo.so',
+ 'libfoo.so.0',
+ 'libfoo.so.0.1.2',
+ 'foo.os',
+ ]
+elif platform == 'darwin':
+ # All (?) the files we expect will get created in the current directory
+ files = [
+ 'libfoo.dylib',
+ 'libfoo.0.1.2.dylib',
+ 'foo.os',
+ ]
+elif platform == 'cygwin':
+ # All (?) the files we expect will get created in the current directory
+ files = [
+ 'cygfoo-0-1-2.dll',
+ 'libfoo-0-1-2.dll.a',
+ 'libfoo.dll.a',
+ 'foo.os',
+ ]
+elif platform == 'win32':
+ # All (?) the files we expect will get created in the current directory
+ files = [
+ 'foo.dll',
+ 'foo.lib',
+ 'foo.obj',
+ ]
+else:
+ # All (?) the files we expect will get created in the current directory
+ files= [
+ 'libfoo.so',
+ 'foo.os']
+
+for f in files:
+ test.must_not_exist([ f])
+
+test.must_exist(['main.c'])
+test.must_exist(['foo.c'])
+test.must_exist(['SConstruct'])
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/LINK/VersionedLib-subdir.py b/test/LINK/VersionedLib-subdir.py
new file mode 100644
index 00000000..5fae101e
--- /dev/null
+++ b/test/LINK/VersionedLib-subdir.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python
+#
+# __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__"
+
+"""
+Ensure that SharedLibrary builder with SHLIBVERSION='0.1.2' can build its target
+in a subdirectory containing .so.0.1.2 in name.
+
+This is regression test for issue mentioned in:
+http://thread.gmane.org/gmane.comp.programming.tools.scons.user/27081
+"""
+
+import TestSCons
+import os
+import sys
+
+import SCons.Platform
+
+test = TestSCons.TestSCons()
+
+test.write('foo.c', """
+#if _WIN32
+__declspec(dllexport)
+#endif
+int foo() { return 0; }
+""")
+
+test.write('main.c', """
+#if _WIN32
+__declspec(dllimport)
+#endif
+int foo();
+int main()
+{
+ return foo();
+}
+""")
+
+platform = SCons.Platform.platform_default()
+
+if platform == 'darwin':
+ subdir = 'blah.0.1.2.dylib.blah'
+elif platform == 'cygwin':
+ subdir = 'blah-0-1-2.dll.a.blah'
+else:
+ subdir = 'blah.so.0.1.2.blah'
+
+test.write('SConstruct', """
+env = Environment()
+env.AppendUnique(LIBPATH = [ '%s' ])
+env.SharedLibrary('%s/foo', 'foo.c', SHLIBVERSION = '0.1.2')
+env.Program('main.c', LIBS=['foo'])
+""" % (subdir,subdir))
+
+test.run(arguments = ['--tree=all'])
+
+if platform == 'cygwin':
+ # PATH is used to search for *.dll librarier (cygfoo-0-2-1.dll in our case)
+ path = os.environ.get('PATH','')
+ if path: path = path + os.pathsep
+ path = path + test.workpath(subdir)
+ os.environ['PATH'] = path
+
+if os.name == 'posix':
+ os.environ['LD_LIBRARY_PATH'] = subdir
+if sys.platform.find('irix') != -1:
+ os.environ['LD_LIBRARYN32_PATH'] = subdir
+
+test.run(program = test.workpath('main'))
+
+if platform == 'posix':
+ # All (?) the files we expect will get created in the current directory
+ files = [
+ 'libfoo.so',
+ 'libfoo.so.0',
+ 'libfoo.so.0.1.2',
+ ]
+ obj = 'foo.os'
+elif platform == 'darwin':
+ # All (?) the files we expect will get created in the current directory
+ files = [
+ 'libfoo.dylib',
+ 'libfoo.0.1.2.dylib',
+ ]
+ obj = 'foo.os'
+elif platform == 'cygwin':
+ # All (?) the files we expect will get created in the current directory
+ files = [
+ 'cygfoo-0-1-2.dll',
+ 'libfoo-0-1-2.dll.a',
+ 'libfoo.dll.a',
+ ]
+ obj = 'foo.os'
+elif platform == 'win32':
+ # All (?) the files we expect will get created in the current directory
+ files = [
+ 'foo.dll',
+ 'foo.lib',
+ ]
+ obj = 'foo.obj'
+else:
+ # All (?) the files we expect will get created in the current directory
+ files= [
+ 'libfoo.so',
+ ]
+ obj = 'foo.os'
+
+test.must_exist([ obj ])
+for f in files:
+ test.must_exist([ subdir, f ])
+
+test.run(arguments = ['-c'])
+
+test.must_not_exist([ obj ])
+for f in files:
+ test.must_not_exist([ subdir, f ])
+
+test.must_exist(['foo.c'])
+test.must_exist(['SConstruct'])
+
+test.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/LINK/VersionedLib.py b/test/LINK/VersionedLib.py
index a2345d6e..c68dd552 100644
--- a/test/LINK/VersionedLib.py
+++ b/test/LINK/VersionedLib.py
@@ -39,8 +39,8 @@ import os
env = Environment()
objs = env.SharedObject('test.c')
mylib = env.SharedLibrary('test', objs, SHLIBVERSION = '2.5.4')
-env.Program(source=['testapp.c',mylib])
-env.Program(target=['testapp2'],source=['testapp.c','libtest.dylib'])
+env.Program('testapp1.c', LIBS = mylib, LIBPATH='.')
+env.Program('testapp2.c', LIBS = ['test'], LIBPATH='.')
instnode = env.InstallVersionedLib("#/installtest",mylib)
env.Default(instnode)
""")
@@ -55,22 +55,28 @@ return n+1 ;
}
""")
-test.write('testapp.c', """\
+testapp_src = """\
+#if _WIN32
+__declspec(dllimport)
+#endif
+int testlib(int n);
#include <stdio.h>
int main(int argc, char **argv)
{
int itest ;
itest = testlib(2) ;
-printf("results: testlib(2) = %d\n",itest) ;
+printf("results: testlib(2) = %d\\n",itest) ;
return 0 ;
}
-""")
+"""
+test.write('testapp1.c', testapp_src)
+test.write('testapp2.c', testapp_src)
platform = SCons.Platform.platform_default()
-test.run()
+test.run(arguments = ['--tree=all'])
if platform == 'posix':
# All (?) the files we expect will get created in the current directory
@@ -103,12 +109,14 @@ elif platform == 'cygwin':
files = [
'cygtest-2-5-4.dll',
'libtest-2-5-4.dll.a',
+ 'libtest.dll.a',
'test.os',
]
# All (?) the files we expect will get created in the 'installtest' directory
instfiles = [
'cygtest-2-5-4.dll',
'libtest-2-5-4.dll.a',
+ 'libtest.dll.a',
]
elif platform == 'win32':
# All (?) the files we expect will get created in the current directory
@@ -148,7 +156,7 @@ return n+11 ;
test.run()
-test.run(arguments = '-c')
+test.run(arguments = ['-c'])
for f in files:
test.must_not_exist([ f])