From 596b7aca20e286ecb45dade015ab9e89ac6aa791 Mon Sep 17 00:00:00 2001 From: Pawel Tomulik Date: Thu, 3 Sep 2015 01:02:08 +0200 Subject: new versioned libraries - gnulink and cyglink for now --- src/engine/SCons/Defaults.py | 7 + src/engine/SCons/Platform/cygwin.py | 4 +- src/engine/SCons/Tool/__init__.py | 428 ++++++++++++++++++++++++------------ src/engine/SCons/Tool/__init__.xml | 37 +++- src/engine/SCons/Tool/cyglink.py | 148 ++++++++++++- src/engine/SCons/Tool/cyglink.xml | 49 +++++ src/engine/SCons/Tool/gnulink.py | 117 ++++++++++ src/engine/SCons/Tool/gnulink.xml | 4 + src/engine/SCons/Tool/install.py | 130 +++-------- src/engine/SCons/Tool/install.xml | 11 +- src/engine/SCons/Tool/link.py | 148 +++++-------- src/engine/SCons/Tool/link.xml | 154 +++++++++++++ src/engine/SCons/Tool/linkloc.py | 1 + src/engine/SCons/Tool/mingw.py | 1 + src/engine/SCons/Tool/mslink.py | 1 + src/engine/SCons/Tool/mwld.py | 1 + src/engine/SCons/Tool/qt.py | 1 + test/LINK/VersionedLib-j2.py | 135 ++++++++++++ test/LINK/VersionedLib-subdir.py | 149 +++++++++++++ test/LINK/VersionedLib.py | 22 +- 20 files changed, 1187 insertions(+), 361 deletions(-) create mode 100644 src/engine/SCons/Tool/cyglink.xml create mode 100644 test/LINK/VersionedLib-j2.py create mode 100644 test/LINK/VersionedLib-subdir.py diff --git a/src/engine/SCons/Defaults.py b/src/engine/SCons/Defaults.py index 6500443..db48969 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 a012682..34c79ff 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 efd2e33..4a27c0d 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 ee56fc3..7102fa4 100644 --- a/src/engine/SCons/Tool/__init__.xml +++ b/src/engine/SCons/Tool/__init__.xml @@ -464,6 +464,17 @@ as C++ files. + + + +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. + + + + @@ -472,6 +483,21 @@ TODO + + + +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. + + + + @@ -492,11 +518,12 @@ TODO 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. diff --git a/src/engine/SCons/Tool/cyglink.py b/src/engine/SCons/Tool/cyglink.py index 87716cf..4033978 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 0000000..42208f1 --- /dev/null +++ b/src/engine/SCons/Tool/cyglink.xml @@ -0,0 +1,49 @@ + + + + +%scons; + +%builders-mod; + +%functions-mod; + +%tools-mod; + +%variables-mod; +]> + + + + + + +Set construction variables for cygwin linker/loader. + + + +IMPLIBPREFIX +IMPLIBSUFFIX +LDMODULEVERSIONFLAGS +LINKFLAGS +RPATHPREFIX +RPATHSUFFIX +SHLIBPREFIX +SHLIBSUFFIX +SHLIBVERSIONFLAGS +SHLINKCOM +SHLINKFLAGS +_LDMODULEVERSIONFLAGS +_SHLIBVERSIONFLAGS + + + + diff --git a/src/engine/SCons/Tool/gnulink.py b/src/engine/SCons/Tool/gnulink.py index 3dc8f51..ea0ca5a 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 2a36de2..63ce0f4 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. SHLINKFLAGS RPATHPREFIX RPATHSUFFIX +_LDMODULESONAME +_SHLINKSONAME +LDMODULEVERSIONFLAGS +SHLIBVERSIONFLAGS diff --git a/src/engine/SCons/Tool/install.py b/src/engine/SCons/Tool/install.py index 9f2e937..c5c2adb 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 0aa9384..6ae3e30 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'], -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. 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') diff --git a/src/engine/SCons/Tool/link.py b/src/engine/SCons/Tool/link.py index a084bc4..33e50d9 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 d58b9e2..52349da 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. LIBLINKPREFIX LIBLINKSUFFIX SHLIBSUFFIX +__SHLIBVERSIONFLAGS LDMODULE LDMODULEPREFIX LDMODULESUFFIX LDMODULEFLAGS LDMODULECOM +LDMODULEVERSION +LDMODULENOVERSIONSYMLINKS +LDMODULEVERSIONFLAGS +__LDMODULEVERSIONFLAGS SHLINKCOMSTR @@ -54,6 +59,105 @@ Sets construction variables for generic POSIX linkers. + + + +This construction variable automatically introduces &cv-link-_LDMODULEVERSIONFLAGS; +if &cv-link-LDMODULEVERSION; is set. Othervise it evaluates to an empty string. + + + + + + + +This construction variable automatically introduces &cv-link-_SHLIBVERSIONFLAGS; +if &cv-link-SHLIBVERSION; is set. Othervise it evaluates to an empty string. + + + + + + + +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;). + + + + + + + +This macro automatically introduces extra flags to &cv-link-LDMODULECOM; when +building versioned &b-link-LoadableModule; (that is when +&cv-link-LDMODULEVERSION; is set). _LDMODULEVERSIONFLAGS +usually adds &cv-link-SHLIBVERSIONFLAGS; and some extra dynamically generated +options (such as -Wl,-soname=$_LDMODULESONAME). It is unused +by plain (unversioned) loadable modules. + + + + + + + +This macro automatically introduces extra flags to &cv-link-SHLINKCOM; when +building versioned &b-link-SharedLibrary; (that is when &cv-link-SHLIBVERSION; +is set). _SHLIBVERSIONFLAGS usually adds &cv-link-SHLIBVERSIONFLAGS; +and some extra dynamically generated options (such as +-Wl,-soname=$_SHLINKSONAME. It is unused by "plain" +(unversioned) shared libraries. + + + + + + + +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;). + + + + + + + +The prefix used for import library names. For example, cygwin uses import +libraries (libfoo.dll.a) in pair with dynamic libraries +(cygfoo.dll). The &t-link-cyglink; linker sets +&cv-link-IMPLIBPREFIX; to 'lib' and &cv-link-SHLIBPREFIX; +to 'cyg'. + + + + + + + +The suffix used for import library names. For example, cygwin uses import +libraries (libfoo.dll.a) in pair with dynamic libraries +(cygfoo.dll). The &t-link-cyglink; linker sets +&cv-link-IMPLIBSUFFIX; to '.dll.a' and &cv-link-SHLIBSUFFIX; +to '.dll'. + + + + + + + +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. + + + + @@ -92,6 +196,15 @@ General user options passed to the linker for building loadable modules. + + + +Instructs the &b-link-LoadableModule; builder to not automatically create symlinks +for versioned modules. Defaults to $SHLIBNOVERSIONSYMLINKS + + + + @@ -114,6 +227,16 @@ the same as $SHLIBSUFFIX. + + + +Extra flags added to &cv-link-LDMODULECOM; when building versioned +&b-link-LoadableModule;. These flags are only used when &cv-link-LDMODULEVERSION; is +set. + + + + @@ -169,6 +292,25 @@ for the variable that expands to library search path options. + + + +Instructs the &b-link-SharedLibrary; builder to not create symlinks for versioned +shared libraries. + + + + + + + +Extra flags added to &cv-link-SHLINKCOM; when building versioned +&b-link-SharedLibrary;. These flags are only used when &cv-link-SHLIBVERSION; is +set. + + + + @@ -223,6 +365,18 @@ for the variable that expands to library search path options. + + + +Variable used to hard-code SONAME for versioned shared library/loadable module. + +env.SharedLibrary('test', 'test.c', SHLIBVERSION='0.1.2', SONAME='libtest.so.2') + +The variable is used, for example, by &t-link-gnulink; linker tool. + + + + diff --git a/src/engine/SCons/Tool/linkloc.py b/src/engine/SCons/Tool/linkloc.py index 9c58561..bd643f7 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 601ec3b..948ebe5 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 6606e10..1390c20 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 e762d55..2067660 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 716c7d5..7bc0ef6 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 0000000..076a4dd --- /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 0000000..5fae101 --- /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 a2345d6..c68dd55 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 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]) -- cgit v0.12 From 97a7990e29435b7fe752ce220aac9a6048393395 Mon Sep 17 00:00:00 2001 From: Pawel Tomulik Date: Fri, 4 Sep 2015 03:34:59 +0200 Subject: reivised code, fixed cygwin/variant-dir issue, cleaned-up some areas --- src/engine/SCons/Tool/__init__.py | 67 +++++++++------ src/engine/SCons/Tool/cyglink.py | 32 ++++--- src/engine/SCons/Tool/gnulink.py | 19 ++--- src/engine/SCons/Tool/install.py | 23 ++--- test/LINK/VersionedLib-VariantDir.py | 157 +++++++++++++++++++++++++++++++++++ test/LINK/VersionedLib-subdir.py | 4 +- 6 files changed, 242 insertions(+), 60 deletions(-) create mode 100644 test/LINK/VersionedLib-VariantDir.py diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py index 4a27c0d..0e6e7d8 100644 --- a/src/engine/SCons/Tool/__init__.py +++ b/src/engine/SCons/Tool/__init__.py @@ -367,7 +367,7 @@ LdModSuffixGenerator = _LibSuffixGenerator('LdMod') ImpLibSuffixGenerator = _LibSuffixGenerator('ImpLib') class _LibSymlinkGenerator(_LibInfoGeneratorBase): - """Library symlink map generator. It generates a dict of symlinks that + """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') @@ -397,7 +397,7 @@ class _LibSymlinkGenerator(_LibInfoGeneratorBase): Verbose = False if Verbose: - print "_LibSymLinkGenerator: str(libnode)=%r" % str(libnode) + print "_LibSymLinkGenerator: libnode=%r" % libnode.get_path() symlinks = None @@ -412,7 +412,7 @@ class _LibSymlinkGenerator(_LibInfoGeneratorBase): symlinks = self.generate_versioned_lib_info(env, [libnode, version, suffix], **kw) if Verbose: - print '_LibSymlinkGenerator: return symlinks=%r' % symlinks + print '_LibSymlinkGenerator: return symlinks=%r' % StringizeLibSymlinks(symlinks) return symlinks ShLibSymlinkGenerator = _LibSymlinkGenerator('ShLib') @@ -430,7 +430,7 @@ class _LibNameGenerator(_LibInfoGeneratorBase): Verbose = False if Verbose: - print "_LibNameGenerator: str(libnode)=%r" % str(libnode) + print "_LibNameGenerator: libnode=%r" % libnode.get_path() version = self.get_lib_version(env, **kw) if Verbose: @@ -442,7 +442,7 @@ class _LibNameGenerator(_LibInfoGeneratorBase): name = self.generate_versioned_lib_info(env, [libnode, version, suffix], **kw) if not name: - name = os.path.basename(str(libnode)) + name = os.path.basename(libnode.get_path()) if Verbose: print '_LibNameGenerator: return name=%r' % name @@ -464,7 +464,7 @@ class _LibSonameGenerator(_LibInfoGeneratorBase): Verbose = False if Verbose: - print "_LibSonameGenerator: str(libnode)=%r" % str(libnode) + print "_LibSonameGenerator: libnode=%r" % libnode.get_path() soname = env.subst('$SONAME') if not soname: @@ -489,41 +489,56 @@ class _LibSonameGenerator(_LibInfoGeneratorBase): ShLibSonameGenerator = _LibSonameGenerator('ShLib') LdModSonameGenerator = _LibSonameGenerator('LdMod') +def StringizeLibSymlinks(symlinks): + """Converts list with pairs of nodes to list with pairs of node paths + (strings). Used mainly for debugging.""" + if SCons.Util.is_List(symlinks): + try: + return [ (k.get_path(), v.get_path()) for k,v in symlinks ] + except TypeError: + return symlinks + except ValueError: + return symlinks + else: + return symlinks + 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) + + # nodes involved in process... all symlinks + library + nodes = list(set([ x for x,y in symlinks ] + [libnode])) + + for link, linktgt in symlinks: + env.SideEffect(link, linktgt) if(Verbose): - print "EmitLibSymlinks: SideEffect(", linkname, ", ", linktgt, ")" - clean = list(set(filter(lambda x : x != linktgt, symlinks.keys() + [str(libnode)]))) - env.Clean(linktgt, clean) + print "EmitLibSymlinks: SideEffect(%r,%r)" % (link.get_path(), linktgt.get_path()) + clean_list = filter(lambda x : x != linktgt, nodes) + env.Clean(linktgt, clean_list) if(Verbose): - print "EmitLibSymlinks: Clean(%r,%r)" % (linktgt, clean) + print "EmitLibSymlinks: Clean(%r,%r)" % (linktgt.get_path(), map(lambda x : x.get_path(), clean_list)) def CreateLibSymlinks(env, symlinks): - """Physically creates symlinks. The symlinks argument must be a dict in - form { linkname : linktarget } + """Physically creates symlinks. The symlinks argument must be a list in + form [ (link, linktarget), ... ], where link and linktarget are SCons + nodes. """ 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) + for link, linktgt in symlinks: + linktgt = link.get_dir().rel_path(linktgt) + link = link.get_path() if(Verbose): - print "CreateLibSymlinks: preparing to add symlink ", linkname, " -> ", linktgt + print "CreateLibSymlinks: preparing to add symlink %r -> %r" % (link, linktgt) try: - os.remove(linkname) + os.remove(link) + if(Verbose): + print "CreateLibSymlinks: removed old file %r" % link except: pass - os.symlink(linktgt, linkname) + os.symlink(linktgt, link) if(Verbose): - print "CreateLibSymlinks: add symlink ", linkname, " -> ", linktgt + print "CreateLibSymlinks: add symlink %r -> %r" % (link, linktgt) return 0 def LibSymlinksActionFunction(target, source, env): diff --git a/src/engine/SCons/Tool/cyglink.py b/src/engine/SCons/Tool/cyglink.py index 4033978..59258b2 100644 --- a/src/engine/SCons/Tool/cyglink.py +++ b/src/engine/SCons/Tool/cyglink.py @@ -56,6 +56,9 @@ def ldmod_generator(target, source, env, for_signature): def _lib_emitter(target, source, env, **kw): Verbose = False + if Verbose: + print "_lib_emitter: target[0]=%r" % target[0].get_path() + try: vp = kw['varprefix'] except KeyError: vp = 'SHLIB' @@ -65,6 +68,9 @@ def _lib_emitter(target, source, env, **kw): dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp) no_import_lib = env.get('no_import_lib', 0) + if Verbose: + print "_lib_emitter: dll=%r" % dll.get_path() + if not dll or len(target) > 1: raise SCons.Errors.UserError("A shared library should have exactly one target with the suffix: %s" % env.subst("$%sSUFFIX" % vp)) @@ -73,20 +79,28 @@ def _lib_emitter(target, source, env, **kw): if dll.name[len(pre):len(pre)+3] == 'lib': dll.name = pre + dll.name[len(pre)+3:] + if Verbose: + print "_lib_emitter: dll.name=%r" % dll.name + orig_target = target target = [env.fs.File(dll)] target[0].attributes.shared = 1 + if Verbose: + print "_lib_emitter: after target=[env.fs.File(dll)]: target[0]=%r" % target[0].get_path() + # 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" % str(implib_target) + print "_lib_emitter: implib_target=%r" % implib_target.get_path() implib_target.attributes.shared = 1 target.append(implib_target) @@ -94,7 +108,7 @@ def _lib_emitter(target, source, env, **kw): implib_libtype=libtype, generator_libtype=libtype+'ImpLib') if Verbose: - print "_lib_emitter: implib symlinks=%r" % symlinks + print "_lib_emitter: implib symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks) if symlinks: SCons.Tool.EmitLibSymlinks(env, symlinks, implib_target) implib_target.attributes.shliblinks = symlinks @@ -129,20 +143,19 @@ def _versioned_implib_name(env, libnode, version, suffix, **kw): 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 } + Returns a list in the form [ (link, linktarget), ... ] """ Verbose = False if Verbose: - print "_versioned_implib_symlinks: str(libnode)=%r" % str(libnode) + print "_versioned_implib_symlinks: libnode=%r" % libnode.get_path() print "_versioned_implib_symlinks: version=%r" % version try: libtype = kw['libtype'] except KeyError: libtype = 'ShLib' - symlinks = {} - linkdir = os.path.dirname(str(libnode)) + linkdir = os.path.dirname(libnode.get_path()) if Verbose: print "_versioned_implib_symlinks: linkdir=%r" % linkdir @@ -154,12 +167,11 @@ def _versioned_implib_symlinks(env, libnode, version, suffix, **kw): major = version.split('.')[0] - link0 = os.path.join(str(linkdir), name) - - symlinks[link0] = str(libnode) + link0 = env.fs.File(os.path.join(linkdir, name)) + symlinks = [(link0, libnode)] if Verbose: - print "_versioned_implib_symlinks: return symlinks=%r" % symlinks + print "_versioned_implib_symlinks: return symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks) return symlinks diff --git a/src/engine/SCons/Tool/gnulink.py b/src/engine/SCons/Tool/gnulink.py index ea0ca5a..14007af 100644 --- a/src/engine/SCons/Tool/gnulink.py +++ b/src/engine/SCons/Tool/gnulink.py @@ -85,18 +85,16 @@ def _versioned_lib_symlinks(env, libnode, version, suffix, name_generator, sonam 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 + print "_versioned_lib_symlinks: return symlinks=%r" % None + return None - linkdir = os.path.dirname(str(libnode)) + linkdir = libnode.get_dir() if Verbose: - print "_versioned_lib_symlinks: linkdir=%r" % linkdir + print "_versioned_lib_symlinks: linkdir=%r" % linkdir.get_path() name = name_generator(env, libnode) if Verbose: @@ -104,14 +102,13 @@ def _versioned_lib_symlinks(env, libnode, version, suffix, name_generator, sonam soname = soname_generator(env, libnode) - link0 = os.path.join(str(linkdir), soname) - link1 = os.path.join(str(linkdir), name) + link0 = env.fs.File(soname, linkdir) + link1 = env.fs.File(name, linkdir) - symlinks[link0] = str(libnode) - symlinks[link1] = link0 + symlinks = [ (link0, libnode), (link1, link0) ] if Verbose: - print "_versioned_lib_symlinks: return symlinks=%r" % symlinks + print "_versioned_lib_symlinks: return symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks) return symlinks diff --git a/src/engine/SCons/Tool/install.py b/src/engine/SCons/Tool/install.py index c5c2adb..9d5db9f 100644 --- a/src/engine/SCons/Tool/install.py +++ b/src/engine/SCons/Tool/install.py @@ -147,18 +147,19 @@ def copyFuncVersionedLib(dest, source, env): return 0 def listShlibLinksToInstall(dest, source, env): - install_links = {} - install_dir = os.path.dirname(str(dest)) + install_links = [] source = env.arg2nodes(source) + dest = env.fs.File(dest) + install_dir = dest.get_dir() 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 + symlinks = getattr(getattr(src,'attributes',None), 'shliblinks', None) + if symlinks: + for link, linktgt in symlinks: + link_base = os.path.basename(link.get_path()) + linktgt_base = os.path.basename(linktgt.get_path()) + install_link = env.fs.File(link_base, install_dir) + install_linktgt = env.fs.File(linktgt_base, install_dir) + install_links.append((install_link, install_linktgt)) return install_links def installShlibLinks(dest, source, env): @@ -167,7 +168,7 @@ def installShlibLinks(dest, source, env): symlinks = listShlibLinksToInstall(dest, source, env) if Verbose: - print 'installShlibLinks: symlinks=%r' % symlinks + print 'installShlibLinks: symlinks=%r' % SCons.Tool.StringizeLibSymlinks(symlinks) if symlinks: SCons.Tool.CreateLibSymlinks(env, symlinks) return diff --git a/test/LINK/VersionedLib-VariantDir.py b/test/LINK/VersionedLib-VariantDir.py new file mode 100644 index 0000000..a3ea660 --- /dev/null +++ b/test/LINK/VersionedLib-VariantDir.py @@ -0,0 +1,157 @@ +#!/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 set works with VariantDir. +""" + +import TestSCons +import os +import sys + +import SCons.Platform + +platform = SCons.Platform.platform_default() + +test = TestSCons.TestSCons() + +test.subdir(['src']) +test.subdir(['src','lib']) +test.subdir(['src','bin']) + +test.write(['src','lib','foo.c'], """ +#if _WIN32 +__declspec(dllexport) +#endif +int foo() { return 0; } +""") + +test.write(['src','bin','main.c'], """ +#if _WIN32 +__declspec(dllimport) +#endif +int foo(); +int main() +{ + return foo(); +} +""") + +test.write('SConstruct', """ +env = Environment() +variant = { 'variant_dir' : 'build', + 'src_dir' : 'src', + 'duplicate' : 0, + 'exports' : { 'env' : env } } +SConscript('src/lib/SConscript', **variant) +SConscript('src/bin/SConscript', **variant) +""") + +test.write(['src','lib','SConscript'], """ +Import('env') +env.SharedLibrary('foo', 'foo.c', SHLIBVERSION = '0.1.2') +""" ) + +test.write(['src','bin','SConscript'], """ +Import('env') +env.Program('main.c', LIBS=['foo'], LIBPATH=['../lib']) +""") + +test.run(arguments = ['--tree=all']) + +if platform == 'cygwin' or platform == 'win32': + # PATH is used to search for *.dll libraries on windows + path = os.environ.get('PATH','') + if path: path = path + os.pathsep + path = path + test.workpath('build/lib') + os.environ['PATH'] = path + +if os.name == 'posix': + os.environ['LD_LIBRARY_PATH'] = test.workpath('build/lib') +if sys.platform.find('irix') != -1: + os.environ['LD_LIBRARYN32_PATH'] = test.workpath('build/lib') + +test.run(program = test.workpath('build/bin/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([ 'build', 'lib', obj ]) +for f in files: + test.must_exist([ 'build', 'lib', f ]) + +test.run(arguments = ['-c']) + +test.must_not_exist([ 'build', 'lib', obj ]) +for f in files: + test.must_not_exist([ 'build', 'lib', f ]) + +test.must_exist(['src', 'lib', 'foo.c']) +test.must_exist(['SConstruct']) +test.must_exist(['src', 'lib', 'SConscript']) +test.must_exist(['src', 'bin', 'SConscript']) + +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 index 5fae101..6facd41 100644 --- a/test/LINK/VersionedLib-subdir.py +++ b/test/LINK/VersionedLib-subdir.py @@ -76,8 +76,8 @@ env.Program('main.c', LIBS=['foo']) test.run(arguments = ['--tree=all']) -if platform == 'cygwin': - # PATH is used to search for *.dll librarier (cygfoo-0-2-1.dll in our case) +if platform == 'cygwin' or platform == 'win32': + # PATH is used to search for *.dll libraries on windows path = os.environ.get('PATH','') if path: path = path + os.pathsep path = path + test.workpath(subdir) -- cgit v0.12 From d124e8dd69f7c73e7ce82d55abf5f69e12379098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Tomulik?= Date: Fri, 4 Sep 2015 23:37:17 +0200 Subject: refactored the versioned lib code a little --- src/engine/SCons/Tool/__init__.py | 98 ++++++++++++++++++++++++++++++--------- src/engine/SCons/Tool/cyglink.py | 48 +++++++++---------- src/engine/SCons/Tool/gnulink.py | 56 +++++++++++----------- src/engine/SCons/Tool/link.py | 35 ++++++++------ 4 files changed, 148 insertions(+), 89 deletions(-) diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py index 0e6e7d8..0b09a13 100644 --- a/src/engine/SCons/Tool/__init__.py +++ b/src/engine/SCons/Tool/__init__.py @@ -236,31 +236,31 @@ def createStaticLibBuilder(env): return static_lib -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""" +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 meet, 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 - + print '_call_linker_cb: args=%r' % args + print '_call_linker_cb: callback=%r' % callback + try: - cbfun = env[callback] - except KeyError: + cbfun = env['LINKCALLBACKS'][callback] + except (KeyError, TypeError): pass else: if Verbose: - print '_call_env_cb: env[%r] found' % callback - print '_call_env_cb: env[%r]=%r' % (callback, cbfun) + print '_call_linker_cb: env[%r] found' % callback + print '_call_linker_cb: env[%r]=%r' % (callback, cbfun) if(callable(cbfun)): if Verbose: - print '_call_env_cb: env[%r] is callable' % callback + print '_call_linker_cb: env[%r] is callable' % callback result = cbfun(env, *args) return result @@ -298,6 +298,17 @@ class _LibInfoGeneratorBase(object): prefix = env.subst('$IMPLIBPREFIX') return prefix + 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() @@ -332,11 +343,39 @@ class _LibInfoGeneratorBase(object): try: libtype = kw['generator_libtype'] except KeyError: libtype = self.get_libtype() infoname = self.get_infoname() - return 'GenerateVersioned%s%s' % (libtype, infoname) + return 'Versioned%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) + 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 + + prefix = self.get_lib_prefix(env) + if Verbose: + print "_LibPrefixGenerator: input prefix=%r" % prefix + + version = self.get_lib_version(env, **kw) + if Verbose: + print "_LibPrefixGenerator: version=%r" % version + + if version: + prefix = self.generate_versioned_lib_info(env, [prefix, version], prefix, **kw) + + 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 @@ -408,8 +447,9 @@ class _LibSymlinkGenerator(_LibInfoGeneratorBase): print '_LibSymlinkGenerator: disable=%r' % disable if version and not disable: + prefix = self.get_lib_prefix(env) suffix = self.get_lib_suffix(env) - symlinks = self.generate_versioned_lib_info(env, [libnode, version, suffix], **kw) + symlinks = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw) if Verbose: print '_LibSymlinkGenerator: return symlinks=%r' % StringizeLibSymlinks(symlinks) @@ -420,8 +460,19 @@ 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)""" + """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') @@ -438,8 +489,9 @@ class _LibNameGenerator(_LibInfoGeneratorBase): name = None if version: + prefix = self.get_lib_prefix(env) suffix = self.get_lib_suffix(env) - name = self.generate_versioned_lib_info(env, [libnode, version, suffix], **kw) + name = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw) if not name: name = os.path.basename(libnode.get_path()) @@ -566,7 +618,7 @@ def createSharedLibBuilder(env): LibSymlinksAction ] shared_lib = SCons.Builder.Builder(action = action_list, emitter = "$SHLIBEMITTER", - prefix = '$SHLIBPREFIX', + prefix = ShLibPrefixGenerator, suffix = ShLibSuffixGenerator, target_scanner = ProgramScanner, src_suffix = '$SHOBJSUFFIX', @@ -591,7 +643,7 @@ def createLoadableModuleBuilder(env): LibSymlinksAction ] ld_module = SCons.Builder.Builder(action = action_list, emitter = "$LDMODULEEMITTER", - prefix = '$LDMODULEPREFIX', + prefix = ShLibPrefixGenerator, suffix = LdModSuffixGenerator, target_scanner = ProgramScanner, src_suffix = '$SHOBJSUFFIX', diff --git a/src/engine/SCons/Tool/cyglink.py b/src/engine/SCons/Tool/cyglink.py index 59258b2..e05e85f 100644 --- a/src/engine/SCons/Tool/cyglink.py +++ b/src/engine/SCons/Tool/cyglink.py @@ -15,6 +15,7 @@ import SCons.Util import SCons.Tool import gnulink +import link def _lib_generator(target, source, env, for_signature, **kw): try: cmd = kw['cmd'] @@ -135,13 +136,13 @@ def _versioned_lib_suffix(env, suffix, version): 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_name(env, libnode, version, prefix, suffix, **kw): + return link._versioned_lib_name(env, libnode, version, prefix, suffix, + SCons.Tool.ImpLibPrefixGenerator, + SCons.Tool.ImpLibSuffixGenerator, + implib_libtype=kw['libtype']) -def _versioned_implib_symlinks(env, libnode, version, suffix, **kw): +def _versioned_implib_symlinks(env, libnode, version, prefix, suffix, **kw): """Generate link names that should be created for a versioned shared lirbrary. Returns a list in the form [ (link, linktarget), ... ] """ @@ -201,27 +202,24 @@ def generate(env): # 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 + # LINKCALLBACKS are NOT inherited from gnulink + env['LINKCALLBACKS'] = { + 'VersionedShLibSuffix' : _versioned_lib_suffix, + 'VersionedLdModSuffix' : _versioned_lib_suffix, + 'VersionedImpLibSuffix' : _versioned_lib_suffix, + 'VersionedShLibName' : link._versioned_shlib_name, + 'VersionedLdModName' : link._versioned_ldmod_name, + 'VersionedShLibImpLibName' : lambda *args: _versioned_implib_name(*args, libtype='ShLib'), + 'VersionedLdModImpLibName' : lambda *args: _versioned_implib_name(*args, libtype='LdMod'), + 'VersionedShLibImpLibSymlinks' : lambda *args: _versioned_implib_symlinks(*args, libtype='ShLib'), + 'VersionedLdModImpLibSymlinks' : lambda *args: _versioned_implib_symlinks(*args, libtype='LdMod'), + } # 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') + try: del env['_SHLINKSONAME'] + except KeyError: pass + try: del env['_LDMODULESONAME'] + except KeyError: pass def exists(env): return gnulink.exists(env) diff --git a/src/engine/SCons/Tool/gnulink.py b/src/engine/SCons/Tool/gnulink.py index 14007af..e5e8818 100644 --- a/src/engine/SCons/Tool/gnulink.py +++ b/src/engine/SCons/Tool/gnulink.py @@ -53,12 +53,12 @@ def _versioned_lib_suffix(env, suffix, version): print "_versioned_lib_suffix: return suffix=%r" % suffix return suffix -def _versioned_lib_soname(env, libnode, version, suffix, name_generator): +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" % version - name = name_generator(env, libnode) + name = name_func(env, libnode, version, prefix, suffix) if Verbose: print "_versioned_lib_soname: name=%r" % name major = version.split('.')[0] @@ -67,22 +67,20 @@ def _versioned_lib_soname(env, libnode, version, suffix, name_generator): 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_shlib_soname(env, libnode, version, prefix, suffix): + return _versioned_lib_soname(env, libnode, version, prefix, suffix, link._versioned_shlib_name) -def _versioned_ldmod_soname(env, libnode, version, suffix): - generator = SCons.Tool.LdModNameGenerator - return _versioned_lib_soname(env, libnode, version, suffix, generator) +def _versioned_ldmod_soname(env, libnode, version, prefix, suffix): + return _versioned_lib_soname(env, libnode, version, prefix, suffix, link._versioned_ldmod_name) -def _versioned_lib_symlinks(env, libnode, version, suffix, name_generator, soname_generator): +def _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, soname_func): """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: libnode=%r" % libnode.get_path() print "_versioned_lib_symlinks: version=%r" % version if sys.platform.startswith('openbsd'): @@ -96,11 +94,11 @@ def _versioned_lib_symlinks(env, libnode, version, suffix, name_generator, sonam if Verbose: print "_versioned_lib_symlinks: linkdir=%r" % linkdir.get_path() - name = name_generator(env, libnode) + name = name_func(env, libnode, version, prefix, suffix) if Verbose: print "_versioned_lib_symlinks: name=%r" % name - soname = soname_generator(env, libnode) + soname = soname_func(env, libnode, version, prefix, suffix) link0 = env.fs.File(soname, linkdir) link1 = env.fs.File(name, linkdir) @@ -112,15 +110,15 @@ def _versioned_lib_symlinks(env, libnode, version, suffix, name_generator, sonam 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_shlib_symlinks(env, libnode, version, prefix, suffix): + nf = link._versioned_shlib_name + sf = _versioned_shlib_soname + return _versioned_lib_symlinks(env, libnode, version, prefix, suffix, nf, sf) -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 _versioned_ldmod_symlinks(env, libnode, version, prefix, suffix): + nf = link._versioned_ldmod_name + sf = _versioned_ldmod_soname + return _versioned_lib_symlinks(env, libnode, version, prefix, suffix, nf, sf) def generate(env): """Add Builders and construction variables for gnulink to an Environment.""" @@ -155,14 +153,16 @@ def generate(env): 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 + env['LINKCALLBACKS'] = { + 'VersionedShLibSuffix' : _versioned_lib_suffix, + 'VersionedLdModSuffix' : _versioned_lib_suffix, + 'VersionedShLibSymlinks' : _versioned_shlib_symlinks, + 'VersionedLdModSymlinks' : _versioned_ldmod_symlinks, + 'VersionedShLibName' : link._versioned_shlib_name, + 'VersionedLdModName' : link._versioned_ldmod_name, + 'VersionedShLibSoname' : _versioned_shlib_soname, + 'VersionedLdModSoname' : _versioned_shlib_soname, + } def exists(env): # TODO: sync with link.smart_link() to choose a linker diff --git a/src/engine/SCons/Tool/link.py b/src/engine/SCons/Tool/link.py index 33e50d9..d52a9e5 100644 --- a/src/engine/SCons/Tool/link.py +++ b/src/engine/SCons/Tool/link.py @@ -76,7 +76,7 @@ def smart_link(source, target, env, for_signature): def _lib_emitter(target, source, env, **kw): Verbose = False if Verbose: - print "_lib_emitter: str(target[0])=%r" % str(target[0]) + print "_lib_emitter: target[0]=%r" % target[0].get_path() for tgt in target: tgt.attributes.shared = 1 @@ -103,35 +103,44 @@ 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): +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" % libnode.get_path() print "_versioned_lib_name: version=%r" % version + print "_versioned_lib_name: prefix=%r" % prefix + print "_versioned_lib_name: suffix=%r" % suffix + print "_versioned_lib_name: suffix_generator=%r" % suffix_generator - versioned_name = os.path.basename(str(libnode)) + versioned_name = os.path.basename(libnode.get_path()) if Verbose: print "_versioned_lib_name: versioned_name=%r" % versioned_name - if Verbose: - print "_versioned_lib_name: suffix=%r" % suffix - + versioned_prefix = prefix_generator(env, **kw) versioned_suffix = suffix_generator(env, **kw) + if Verbose: + print "_versioned_lib_name: versioned_prefix=%r" % versioned_prefix + print "_versioned_lib_name: versioned_suffix=%r" % versioned_suffix + versioned_prefix_re = '^' + re.escape(versioned_prefix) versioned_suffix_re = re.escape(versioned_suffix) + '$' - name = re.sub(versioned_suffix_re, suffix, versioned_name) + 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" % 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_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) -def _versioned_ldmod_name(env, libnode, version, suffix, **kw): - generator = SCons.Tool.LdModSuffixGenerator - return _versioned_lib_name(env, libnode, version, 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) def generate(env): -- cgit v0.12 From 76b1f15cd9d50e70672908bed0a5c065232e4301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Tomulik?= Date: Fri, 4 Sep 2015 23:44:31 +0200 Subject: remove redundant get_lib_prefix() method --- src/engine/SCons/Tool/__init__.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py index 0b09a13..23b08c6 100644 --- a/src/engine/SCons/Tool/__init__.py +++ b/src/engine/SCons/Tool/__init__.py @@ -298,17 +298,6 @@ class _LibInfoGeneratorBase(object): prefix = env.subst('$IMPLIBPREFIX') return prefix - 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() -- cgit v0.12 From 13c193a7dabeecc0381a6ef770e72de216eb3f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Tomulik?= Date: Fri, 4 Sep 2015 23:55:20 +0200 Subject: minor fix in Tool/__init__.py --- src/engine/SCons/Tool/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py index 23b08c6..df917ed 100644 --- a/src/engine/SCons/Tool/__init__.py +++ b/src/engine/SCons/Tool/__init__.py @@ -632,7 +632,7 @@ def createLoadableModuleBuilder(env): LibSymlinksAction ] ld_module = SCons.Builder.Builder(action = action_list, emitter = "$LDMODULEEMITTER", - prefix = ShLibPrefixGenerator, + prefix = LdModPrefixGenerator, suffix = LdModSuffixGenerator, target_scanner = ProgramScanner, src_suffix = '$SHOBJSUFFIX', -- cgit v0.12 From cf4df802f7c81e2eb07628850165ad1e2269334a Mon Sep 17 00:00:00 2001 From: Pawel Tomulik Date: Sat, 5 Sep 2015 00:50:43 +0200 Subject: add action string function for LibSymlinksAction --- src/engine/SCons/Tool/__init__.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py index df917ed..d1f41ec 100644 --- a/src/engine/SCons/Tool/__init__.py +++ b/src/engine/SCons/Tool/__init__.py @@ -466,7 +466,7 @@ class _LibNameGenerator(_LibInfoGeneratorBase): super(_LibNameGenerator, self).__init__(libtype, 'Name') def __call__(self, env, libnode, **kw): - """Returns library name with version suffixes stripped""" + """Returns "demangled" library name""" Verbose = False if Verbose: @@ -536,9 +536,7 @@ def StringizeLibSymlinks(symlinks): if SCons.Util.is_List(symlinks): try: return [ (k.get_path(), v.get_path()) for k,v in symlinks ] - except TypeError: - return symlinks - except ValueError: + except (TypeError, ValueError): return symlinks else: return symlinks @@ -589,7 +587,24 @@ def LibSymlinksActionFunction(target, source, env): CreateLibSymlinks(env, symlinks) return 0 -LibSymlinksAction = SCons.Action.Action(LibSymlinksActionFunction, None) +def LibSymlinksStrFun(target, source, env,*args): + cmd = None + for tgt in target: + symlinks = getattr(getattr(tgt,'attributes', None), 'shliblinks', None) + if symlinks: + if cmd is None: cmd = "" + if cmd: cmd += "\n" + cmd += "Create symlinks for: %r" % tgt.get_path() + try: + linkstr = ', '.join([ "%r->%r" %(k,v) for k,v in StringizeLibSymlinks(symlinks)]) + except (KeyError, ValueError): + pass + else: + cmd += ": %s" % linkstr + return cmd + + +LibSymlinksAction = SCons.Action.Action(LibSymlinksActionFunction, LibSymlinksStrFun) def createSharedLibBuilder(env): """This is a utility function that creates the SharedLibrary -- cgit v0.12 From 2a1a18d6c6a311f28eca6b97372475a09732bad0 Mon Sep 17 00:00:00 2001 From: Pawel Tomulik Date: Mon, 7 Sep 2015 09:34:25 +0200 Subject: minor correction to debug code in Tool/__init__.py --- src/engine/SCons/Tool/__init__.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py index d1f41ec..87a4cf4 100644 --- a/src/engine/SCons/Tool/__init__.py +++ b/src/engine/SCons/Tool/__init__.py @@ -253,14 +253,16 @@ def _call_linker_cb(env, callback, args, result = None): try: cbfun = env['LINKCALLBACKS'][callback] except (KeyError, TypeError): + if Verbose: + print '_call_linker_cb: env["LINKCALLBACKS"][%r] not found or can not be used' pass else: if Verbose: - print '_call_linker_cb: env[%r] found' % callback - print '_call_linker_cb: env[%r]=%r' % (callback, cbfun) + print '_call_linker_cb: env["LINKCALLBACKS"][%r] found' % callback + print '_call_linker_cb: env["LINKCALLBACKS"][%r]=%r' % (callback, cbfun) if(callable(cbfun)): if Verbose: - print '_call_linker_cb: env[%r] is callable' % callback + print '_call_linker_cb: env["LINKCALLBACKS"][%r] is callable' % callback result = cbfun(env, *args) return result -- cgit v0.12 From 4f3e3c23da4fe1b1cc22ac1c1030c94f26217ec5 Mon Sep 17 00:00:00 2001 From: ptomulik Date: Tue, 15 Sep 2015 16:06:48 +0200 Subject: revision: address remarks made by Gary Oberbrunner --- src/engine/SCons/Tool/__init__.py | 234 +++++++++++++++++++++++-------------- src/engine/SCons/Tool/__init__.xml | 2 +- 2 files changed, 145 insertions(+), 91 deletions(-) diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py index 87a4cf4..357b765 100644 --- a/src/engine/SCons/Tool/__init__.py +++ b/src/engine/SCons/Tool/__init__.py @@ -239,7 +239,7 @@ def createStaticLibBuilder(env): 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 meet, return the value provided as + 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""" @@ -254,7 +254,7 @@ def _call_linker_cb(env, callback, args, result = None): cbfun = env['LINKCALLBACKS'][callback] except (KeyError, TypeError): if Verbose: - print '_call_linker_cb: env["LINKCALLBACKS"][%r] not found or can not be used' + print '_call_linker_cb: env["LINKCALLBACKS"][%r] not found or can not be used' % callback pass else: if Verbose: @@ -266,22 +266,91 @@ def _call_linker_cb(env, callback, args, result = None): result = cbfun(env, *args) return result +def _call_env_subst(env, string, *args, **kw): + kw2 = {} + for k in ('raw', 'target', 'source', 'conv', 'executor'): + try: kw2[k] = kw[k] + except KeyError: pass + return env.subst(string, *args, **kw2) + +class _ShLibInfoSupport(object): + def get_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(object): + def get_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(object): + def get_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(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 """ + _support_classes = { 'ShLib' : _ShLibInfoSupport, + 'LdMod' : _LdModInfoSupport, + 'ImpLib' : _ImpLibInfoSupport } 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']: + try: + support_class = self._support_classes[libtype] + except KeyError: raise ValueError('unsupported libtype %r' % libtype) - self.libtype = libtype + self._support = support_class() def get_libtype(self): - return self.libtype + return self._support.get_libtype() def set_infoname(self, infoname): self.infoname = infoname @@ -289,47 +358,21 @@ class _LibInfoGeneratorBase(object): 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_prefix(self, env, *args, **kw): + return self._support.get_lib_prefix(env,*args,**kw) - 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_suffix(self, env, *args, **kw): + return self._support.get_lib_suffix(env,*args,**kw) - 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_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) + + # Returns name of generator linker callback that shall 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'. def get_versioned_lib_info_generator(self, **kw): try: libtype = kw['generator_libtype'] except KeyError: libtype = self.get_libtype() @@ -349,16 +392,22 @@ class _LibPrefixGenerator(_LibInfoGeneratorBase): def __call__(self, env, sources = None, **kw): Verbose = False - prefix = self.get_lib_prefix(env) + 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, **kw) + 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, **kw) + prefix = self.generate_versioned_lib_info(env, [prefix, version], prefix, **kw2) if Verbose: print "_LibPrefixGenerator: return prefix=%r" % prefix @@ -377,16 +426,22 @@ class _LibSuffixGenerator(_LibInfoGeneratorBase): def __call__(self, env, sources = None, **kw): Verbose = False - suffix = self.get_lib_suffix(env) + 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, **kw) + 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, **kw) + suffix = self.generate_versioned_lib_info(env, [suffix, version], suffix, **kw2) if Verbose: print "_LibSuffixGenerator: return suffix=%r" % suffix @@ -402,45 +457,30 @@ class _LibSymlinkGenerator(_LibInfoGeneratorBase): 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 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, **kw) - disable = self.get_noversionsymlinks(env, **kw) + 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) - suffix = self.get_lib_suffix(env) - symlinks = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw) + 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) @@ -471,18 +511,24 @@ class _LibNameGenerator(_LibInfoGeneratorBase): """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, **kw) + version = self.get_lib_version(env, **kw2) if Verbose: print '_LibNameGenerator: version=%r' % version name = None if version: - prefix = self.get_lib_prefix(env) - suffix = self.get_lib_suffix(env) - name = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw) + 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()) @@ -506,17 +552,23 @@ class _LibSonameGenerator(_LibInfoGeneratorBase): """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 = env.subst('$SONAME') + soname = _call_env_subst(env, '$SONAME', **kw2) if not soname: - version = self.get_lib_version(env,**kw) + version = self.get_lib_version(env,**kw2) if Verbose: print "_LibSonameGenerator: version=%r" % version if version: - suffix = self.get_lib_suffix(env) - soname = self.generate_versioned_lib_info(env, [libnode, version, suffix], **kw) + suffix = self.get_lib_suffix(env,**kw2) + soname = self.generate_versioned_lib_info(env, [libnode, version, suffix], **kw2) if not soname: # fallback to library name (as returned by appropriate _LibNameGenerator) @@ -571,13 +623,15 @@ def CreateLibSymlinks(env, symlinks): link = link.get_path() if(Verbose): print "CreateLibSymlinks: preparing to add symlink %r -> %r" % (link, linktgt) - try: - os.remove(link) + # Delete the (previously created) symlink if exists. Let only symlinks + # to be deleted to prevent accidental deletion of source files... + if env.fs.islink(link): + env.fs.unlink(link) if(Verbose): - print "CreateLibSymlinks: removed old file %r" % link - except: - pass - os.symlink(linktgt, link) + print "CreateLibSymlinks: removed old symlink %r" % link + # If a file or directory exists with the same name as link, an OSError + # will be thrown, which should be enough, I think. + env.fs.symlink(linktgt, link) if(Verbose): print "CreateLibSymlinks: add symlink %r -> %r" % (link, linktgt) return 0 @@ -589,7 +643,7 @@ def LibSymlinksActionFunction(target, source, env): CreateLibSymlinks(env, symlinks) return 0 -def LibSymlinksStrFun(target, source, env,*args): +def LibSymlinksStrFun(target, source, env, *args): cmd = None for tgt in target: symlinks = getattr(getattr(tgt,'attributes', None), 'shliblinks', None) diff --git a/src/engine/SCons/Tool/__init__.xml b/src/engine/SCons/Tool/__init__.xml index 7102fa4..7f19bfc 100644 --- a/src/engine/SCons/Tool/__init__.xml +++ b/src/engine/SCons/Tool/__init__.xml @@ -469,7 +469,7 @@ as C++ files. 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 +undefined, the &cv-link-SHLIBVERSION;/&cv-link-LDMODULEVERSION; is used to determine the version of versioned import library. -- cgit v0.12 From 3173faf4aa18308832c7c8a983e3ff556d2cb5ba Mon Sep 17 00:00:00 2001 From: Pawel Tomulik Date: Sat, 19 Sep 2015 02:09:53 +0200 Subject: support free-form SHLIBVERSION/LDMODULEVERSION --- src/engine/SCons/Tool/gnulink.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/engine/SCons/Tool/gnulink.py b/src/engine/SCons/Tool/gnulink.py index e5e8818..0c5087b 100644 --- a/src/engine/SCons/Tool/gnulink.py +++ b/src/engine/SCons/Tool/gnulink.py @@ -103,7 +103,11 @@ def _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, so link0 = env.fs.File(soname, linkdir) link1 = env.fs.File(name, linkdir) - symlinks = [ (link0, libnode), (link1, link0) ] + # This allows anything in SHLIBVERSION (especially SHLIBVERSION=1). + if link0 == libnode: + symlinks = [ (link1, libnode) ] + else: + symlinks = [ (link0, libnode), (link1, link0) ] if Verbose: print "_versioned_lib_symlinks: return symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks) -- cgit v0.12 From f6f919842bf5dc265422309b98546e182e3ee9ae Mon Sep 17 00:00:00 2001 From: Pawel Tomulik Date: Sat, 19 Sep 2015 21:24:29 +0200 Subject: gnulink: create direct symlinks instead of daisy-chained ones --- src/engine/SCons/Tool/gnulink.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/engine/SCons/Tool/gnulink.py b/src/engine/SCons/Tool/gnulink.py index 0c5087b..aabc2f1 100644 --- a/src/engine/SCons/Tool/gnulink.py +++ b/src/engine/SCons/Tool/gnulink.py @@ -103,11 +103,13 @@ def _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, so link0 = env.fs.File(soname, linkdir) link1 = env.fs.File(name, linkdir) - # This allows anything in SHLIBVERSION (especially SHLIBVERSION=1). + # We create direct symlinks, not daisy-chained. if link0 == libnode: + # This enables SHLIBVERSION without periods (e.g. SHLIBVERSION=1) symlinks = [ (link1, libnode) ] else: - symlinks = [ (link0, libnode), (link1, link0) ] + # 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" % SCons.Tool.StringizeLibSymlinks(symlinks) -- cgit v0.12 From 9a43408e4419ba54733222df65a38a9d1a925b6d Mon Sep 17 00:00:00 2001 From: Pawel Tomulik Date: Sun, 20 Sep 2015 02:24:11 +0200 Subject: support for versioned libraries for sunlink --- src/engine/SCons/Tool/gnulink.py | 96 +++--------------------------------- src/engine/SCons/Tool/link.py | 85 +++++++++++++++++++++++++++++++ src/engine/SCons/Tool/sunlink.py | 21 ++++++++ test/LINK/VersionedLib-VariantDir.py | 8 +++ test/LINK/VersionedLib-j2.py | 8 +++ test/LINK/VersionedLib-subdir.py | 8 +++ test/LINK/VersionedLib.py | 14 ++++++ 7 files changed, 150 insertions(+), 90 deletions(-) diff --git a/src/engine/SCons/Tool/gnulink.py b/src/engine/SCons/Tool/gnulink.py index aabc2f1..92c38c4 100644 --- a/src/engine/SCons/Tool/gnulink.py +++ b/src/engine/SCons/Tool/gnulink.py @@ -41,90 +41,6 @@ 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, 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" % version - name = name_func(env, libnode, version, prefix, suffix) - 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, prefix, suffix): - return _versioned_lib_soname(env, libnode, version, prefix, suffix, link._versioned_shlib_name) - -def _versioned_ldmod_soname(env, libnode, version, prefix, suffix): - return _versioned_lib_soname(env, libnode, version, prefix, suffix, link._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 lirbrary. - Returns a dictionary in the form { linkname : linktarget } - """ - Verbose = False - - if Verbose: - print "_versioned_lib_symlinks: libnode=%r" % libnode.get_path() - print "_versioned_lib_symlinks: version=%r" % 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" % None - return None - - linkdir = libnode.get_dir() - if Verbose: - print "_versioned_lib_symlinks: linkdir=%r" % linkdir.get_path() - - name = name_func(env, libnode, version, prefix, suffix) - if Verbose: - print "_versioned_lib_symlinks: name=%r" % name - - soname = soname_func(env, libnode, version, prefix, suffix) - - 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" % SCons.Tool.StringizeLibSymlinks(symlinks) - - return symlinks - -def _versioned_shlib_symlinks(env, libnode, version, prefix, suffix): - nf = link._versioned_shlib_name - sf = _versioned_shlib_soname - return _versioned_lib_symlinks(env, libnode, version, prefix, suffix, nf, sf) - -def _versioned_ldmod_symlinks(env, libnode, version, prefix, suffix): - nf = link._versioned_ldmod_name - sf = _versioned_ldmod_soname - return _versioned_lib_symlinks(env, libnode, version, prefix, suffix, nf, sf) def generate(env): """Add Builders and construction variables for gnulink to an Environment.""" @@ -160,14 +76,14 @@ def generate(env): env['LdModSonameGenerator'] = SCons.Tool.LdModSonameGenerator env['LINKCALLBACKS'] = { - 'VersionedShLibSuffix' : _versioned_lib_suffix, - 'VersionedLdModSuffix' : _versioned_lib_suffix, - 'VersionedShLibSymlinks' : _versioned_shlib_symlinks, - 'VersionedLdModSymlinks' : _versioned_ldmod_symlinks, + 'VersionedShLibSuffix' : link._versioned_lib_suffix, + 'VersionedLdModSuffix' : link._versioned_lib_suffix, + 'VersionedShLibSymlinks' : link._versioned_shlib_symlinks, + 'VersionedLdModSymlinks' : link._versioned_ldmod_symlinks, 'VersionedShLibName' : link._versioned_shlib_name, 'VersionedLdModName' : link._versioned_ldmod_name, - 'VersionedShLibSoname' : _versioned_shlib_soname, - 'VersionedLdModSoname' : _versioned_shlib_soname, + 'VersionedShLibSoname' : link._versioned_shlib_soname, + 'VersionedLdModSoname' : link._versioned_shlib_soname, } def exists(env): diff --git a/src/engine/SCons/Tool/link.py b/src/engine/SCons/Tool/link.py index d52a9e5..0af7776 100644 --- a/src/engine/SCons/Tool/link.py +++ b/src/engine/SCons/Tool/link.py @@ -142,6 +142,91 @@ def _versioned_ldmod_name(env, libnode, version, prefix, suffix, **kw): sg = SCons.Tool.LdModSuffixGenerator return _versioned_lib_name(env, libnode, version, prefix, suffix, pg, sg, **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" % 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, 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" % version + name = name_func(env, libnode, version, prefix, suffix) + 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, 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 lirbrary. + Returns a dictionary in the form { linkname : linktarget } + """ + Verbose = False + + if Verbose: + print "_versioned_lib_symlinks: libnode=%r" % libnode.get_path() + print "_versioned_lib_symlinks: version=%r" % 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" % None + return None + + linkdir = libnode.get_dir() + if Verbose: + print "_versioned_lib_symlinks: linkdir=%r" % linkdir.get_path() + + name = name_func(env, libnode, version, prefix, suffix) + if Verbose: + print "_versioned_lib_symlinks: name=%r" % name + + soname = soname_func(env, libnode, version, prefix, suffix) + + 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" % SCons.Tool.StringizeLibSymlinks(symlinks) + + return symlinks + +def _versioned_shlib_symlinks(env, libnode, version, prefix, suffix): + nf = _versioned_shlib_name + sf = _versioned_shlib_soname + return _versioned_lib_symlinks(env, libnode, version, prefix, suffix, nf, sf) + +def _versioned_ldmod_symlinks(env, libnode, version, prefix, suffix): + nf = _versioned_ldmod_name + sf = _versioned_ldmod_soname + return _versioned_lib_symlinks(env, libnode, version, prefix, suffix, nf, sf) + def generate(env): """Add Builders and construction variables for gnulink to an Environment.""" diff --git a/src/engine/SCons/Tool/sunlink.py b/src/engine/SCons/Tool/sunlink.py index 5996a30..c9bb17d 100644 --- a/src/engine/SCons/Tool/sunlink.py +++ b/src/engine/SCons/Tool/sunlink.py @@ -66,6 +66,27 @@ def generate(env): env['RPATHSUFFIX'] = '' env['_RPATH'] = '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}' + # Support for versioned libraries + env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS -h $_SHLINKSONAME' + env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS -h $_LDMODULESONAME' + + env['_SHLINKSONAME'] = '${ShLibSonameGenerator(__env__,TARGET)}' + env['_LDMODULESONAME'] = '${LdModSonameGenerator(__env__,TARGET)}' + + env['ShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator + env['LdModSonameGenerator'] = SCons.Tool.LdModSonameGenerator + + env['LINKCALLBACKS'] = { + 'VersionedShLibSuffix' : link._versioned_lib_suffix, + 'VersionedLdModSuffix' : link._versioned_lib_suffix, + 'VersionedShLibSymlinks' : link._versioned_shlib_symlinks, + 'VersionedLdModSymlinks' : link._versioned_ldmod_symlinks, + 'VersionedShLibName' : link._versioned_shlib_name, + 'VersionedLdModName' : link._versioned_ldmod_name, + 'VersionedShLibSoname' : link._versioned_shlib_soname, + 'VersionedLdModSoname' : link._versioned_shlib_soname, + } + def exists(env): return ccLinker diff --git a/test/LINK/VersionedLib-VariantDir.py b/test/LINK/VersionedLib-VariantDir.py index a3ea660..7406a33 100644 --- a/test/LINK/VersionedLib-VariantDir.py +++ b/test/LINK/VersionedLib-VariantDir.py @@ -126,6 +126,14 @@ elif platform == 'win32': 'foo.lib', ] obj = 'foo.obj' +elif platform == 'sunos': + # All (?) the files we expect will get created in the current directory + files = [ + 'libfoo.so', + 'libfoo.so.0', + 'libfoo.so.0.1.2', + ] + obj = 'so_foo.os' else: # All (?) the files we expect will get created in the current directory files= [ diff --git a/test/LINK/VersionedLib-j2.py b/test/LINK/VersionedLib-j2.py index 076a4dd..6f37e54 100644 --- a/test/LINK/VersionedLib-j2.py +++ b/test/LINK/VersionedLib-j2.py @@ -113,6 +113,14 @@ elif platform == 'win32': 'foo.lib', 'foo.obj', ] +elif platform == 'sunos': + # All (?) the files we expect will get created in the current directory + files = [ + 'libfoo.so', + 'libfoo.so.0', + 'libfoo.so.0.1.2', + 'so_foo.os', + ] else: # All (?) the files we expect will get created in the current directory files= [ diff --git a/test/LINK/VersionedLib-subdir.py b/test/LINK/VersionedLib-subdir.py index 6facd41..15369ef 100644 --- a/test/LINK/VersionedLib-subdir.py +++ b/test/LINK/VersionedLib-subdir.py @@ -120,6 +120,14 @@ elif platform == 'win32': 'foo.lib', ] obj = 'foo.obj' +elif platform == 'sunos': + # All (?) the files we expect will get created in the current directory + files = [ + 'libfoo.so', + 'libfoo.so.0', + 'libfoo.so.0.1.2', + ] + obj = 'so_foo.os' else: # All (?) the files we expect will get created in the current directory files= [ diff --git a/test/LINK/VersionedLib.py b/test/LINK/VersionedLib.py index c68dd55..a75e4a5 100644 --- a/test/LINK/VersionedLib.py +++ b/test/LINK/VersionedLib.py @@ -130,6 +130,20 @@ elif platform == 'win32': 'test.dll', 'test.lib', ] +elif platform == 'sunos': + # All (?) the files we expect will get created in the current directory + files = [ + 'libtest.so', + 'libtest.so.2', + 'libtest.so.2.5.4', + 'so_test.os', + ] + # All (?) the files we expect will get created in the 'installtest' directory + instfiles = [ + 'libtest.so', + 'libtest.so.2', + 'libtest.so.2.5.4', + ] else: # All (?) the files we expect will get created in the current directory files= [ -- cgit v0.12 From cb508c9a37c2a3cd5fcf55cc1efd4c47a0abdd41 Mon Sep 17 00:00:00 2001 From: Pawel Tomulik Date: Sun, 20 Sep 2015 04:21:27 +0200 Subject: fix broken soname generator --- src/engine/SCons/Defaults.py | 17 ++++++++++++----- src/engine/SCons/Tool/__init__.py | 3 ++- src/engine/SCons/Tool/gnulink.py | 2 +- src/engine/SCons/Tool/sunlink.py | 2 +- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/engine/SCons/Defaults.py b/src/engine/SCons/Defaults.py index db48969..c8170c3 100644 --- a/src/engine/SCons/Defaults.py +++ b/src/engine/SCons/Defaults.py @@ -482,9 +482,14 @@ 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) +# if env[version_var] id defined, returns env[flags_var], otherwise returns None +def __libversionflags(env, version_var, flags_var): + try: + if env[version_var]: + return env[flags_var] + except KeyError: + pass + return None ConstructionEnvironment = { 'BUILDERS' : {}, @@ -504,8 +509,10 @@ ConstructionEnvironment = { '_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', '_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}', - '__SHLIBVERSIONFLAGS' : __libversionflags_string('SHLIBVERSION'), - '__LDMODULEVERSIONFLAGS' : __libversionflags_string('LDMODULEVERSION'), + '__libversionflags' : __libversionflags, + '__SHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}', + '__LDMODULEVERSIONFLAGS' : '${__libversionflags(__env__,"LDMODULEVERSION","_LDMODULEVERSIONFLAGS")}', + 'TEMPFILE' : NullCmdGenerator, 'Dir' : Variable_Method_Caller('TARGET', 'Dir'), 'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'), diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py index 357b765..96b9d98 100644 --- a/src/engine/SCons/Tool/__init__.py +++ b/src/engine/SCons/Tool/__init__.py @@ -567,8 +567,9 @@ class _LibSonameGenerator(_LibInfoGeneratorBase): 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, suffix], **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) diff --git a/src/engine/SCons/Tool/gnulink.py b/src/engine/SCons/Tool/gnulink.py index 92c38c4..2e0ed03 100644 --- a/src/engine/SCons/Tool/gnulink.py +++ b/src/engine/SCons/Tool/gnulink.py @@ -83,7 +83,7 @@ def generate(env): 'VersionedShLibName' : link._versioned_shlib_name, 'VersionedLdModName' : link._versioned_ldmod_name, 'VersionedShLibSoname' : link._versioned_shlib_soname, - 'VersionedLdModSoname' : link._versioned_shlib_soname, + 'VersionedLdModSoname' : link._versioned_ldmod_soname, } def exists(env): diff --git a/src/engine/SCons/Tool/sunlink.py b/src/engine/SCons/Tool/sunlink.py index c9bb17d..751bf92 100644 --- a/src/engine/SCons/Tool/sunlink.py +++ b/src/engine/SCons/Tool/sunlink.py @@ -84,7 +84,7 @@ def generate(env): 'VersionedShLibName' : link._versioned_shlib_name, 'VersionedLdModName' : link._versioned_ldmod_name, 'VersionedShLibSoname' : link._versioned_shlib_soname, - 'VersionedLdModSoname' : link._versioned_shlib_soname, + 'VersionedLdModSoname' : link._versioned_ldmod_soname, } def exists(env): -- cgit v0.12 From 31a9cc12812eeb3a83dd26010ec6947a79368f96 Mon Sep 17 00:00:00 2001 From: Pawel Tomulik Date: Sun, 20 Sep 2015 05:36:54 +0200 Subject: refactor code -> avoid code duplication --- src/engine/SCons/Tool/gnulink.py | 35 ++++++------------------------- src/engine/SCons/Tool/link.py | 45 ++++++++++++++++++++++++++++++++++++++++ src/engine/SCons/Tool/sunar.py | 2 +- src/engine/SCons/Tool/sunlink.py | 21 ++----------------- 4 files changed, 54 insertions(+), 49 deletions(-) diff --git a/src/engine/SCons/Tool/gnulink.py b/src/engine/SCons/Tool/gnulink.py index 2e0ed03..6b0d5b3 100644 --- a/src/engine/SCons/Tool/gnulink.py +++ b/src/engine/SCons/Tool/gnulink.py @@ -55,36 +55,13 @@ def generate(env): 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)}' + # OpenBSD doesn't usually use SONAME for libraries + use_soname = not sys.platform.startswith('openbsd') + link._setup_versioned_lib_variables(env, tool = 'gnulink', use_soname = use_soname) + env['LINKCALLBACKS'] = link._versioned_lib_callbacks() - env['ShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator - env['LdModSonameGenerator'] = SCons.Tool.LdModSonameGenerator - - env['LINKCALLBACKS'] = { - 'VersionedShLibSuffix' : link._versioned_lib_suffix, - 'VersionedLdModSuffix' : link._versioned_lib_suffix, - 'VersionedShLibSymlinks' : link._versioned_shlib_symlinks, - 'VersionedLdModSymlinks' : link._versioned_ldmod_symlinks, - 'VersionedShLibName' : link._versioned_shlib_name, - 'VersionedLdModName' : link._versioned_ldmod_name, - 'VersionedShLibSoname' : link._versioned_shlib_soname, - 'VersionedLdModSoname' : link._versioned_ldmod_soname, - } + # For backward-compatiblity with older SCons versions + env['SHLIBVERSIONFLAGS'] = SCons.Util.CLVar('-Wl,-Bsymbolic') def exists(env): # TODO: sync with link.smart_link() to choose a linker diff --git a/src/engine/SCons/Tool/link.py b/src/engine/SCons/Tool/link.py index 0af7776..6bd36e4 100644 --- a/src/engine/SCons/Tool/link.py +++ b/src/engine/SCons/Tool/link.py @@ -227,6 +227,51 @@ def _versioned_ldmod_symlinks(env, libnode, version, prefix, suffix): sf = _versioned_ldmod_soname return _versioned_lib_symlinks(env, libnode, version, prefix, suffix, nf, sf) +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() + +# Setup all variables required by the versioning machinery +def _setup_versioned_lib_variables(env, **kw): + + 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 + if tool == 'sunlink': + env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS -h $_SHLINKSONAME' + env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS -h $_LDMODULESONAME' + else: + env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS -Wl,-soname=$_SHLINKSONAME' + env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS -Wl,-soname=$_LDMODULESONAME' + env['_SHLINKSONAME'] = '${ShLibSonameGenerator(__env__,TARGET)}' + env['_LDMODULESONAME'] = '${LdModSonameGenerator(__env__,TARGET)}' + env['ShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator + env['LdModSonameGenerator'] = SCons.Tool.LdModSonameGenerator + else: + env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS' + env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS' + + # LDOMDULVERSIONFLAGS should always default to $SHLIBVERSIONFLAGS + env['LDMODULEVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS' + def generate(env): """Add Builders and construction variables for gnulink to an Environment.""" diff --git a/src/engine/SCons/Tool/sunar.py b/src/engine/SCons/Tool/sunar.py index 779414f..3ee4344 100644 --- a/src/engine/SCons/Tool/sunar.py +++ b/src/engine/SCons/Tool/sunar.py @@ -53,7 +53,7 @@ def generate(env): env['SHLINK'] = '$LINK' env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -G') - env['SHLINKCOM'] = '$SHLINK $SHLINKFLAGS -o $TARGET $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' + env['SHLINKCOM'] = '$SHLINK -o $TARGET $SHLINKFLAGS $__SHLIBVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' env['LIBPREFIX'] = 'lib' env['LIBSUFFIX'] = '.a' diff --git a/src/engine/SCons/Tool/sunlink.py b/src/engine/SCons/Tool/sunlink.py index 751bf92..680af03 100644 --- a/src/engine/SCons/Tool/sunlink.py +++ b/src/engine/SCons/Tool/sunlink.py @@ -67,25 +67,8 @@ def generate(env): env['_RPATH'] = '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}' # Support for versioned libraries - env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS -h $_SHLINKSONAME' - env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS -h $_LDMODULESONAME' - - env['_SHLINKSONAME'] = '${ShLibSonameGenerator(__env__,TARGET)}' - env['_LDMODULESONAME'] = '${LdModSonameGenerator(__env__,TARGET)}' - - env['ShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator - env['LdModSonameGenerator'] = SCons.Tool.LdModSonameGenerator - - env['LINKCALLBACKS'] = { - 'VersionedShLibSuffix' : link._versioned_lib_suffix, - 'VersionedLdModSuffix' : link._versioned_lib_suffix, - 'VersionedShLibSymlinks' : link._versioned_shlib_symlinks, - 'VersionedLdModSymlinks' : link._versioned_ldmod_symlinks, - 'VersionedShLibName' : link._versioned_shlib_name, - 'VersionedLdModName' : link._versioned_ldmod_name, - 'VersionedShLibSoname' : link._versioned_shlib_soname, - 'VersionedLdModSoname' : link._versioned_ldmod_soname, - } + link._setup_versioned_lib_variables(env, tool = 'sunlink', use_soname = True) + env['LINKCALLBACKS'] = link._versioned_lib_callbacks() def exists(env): return ccLinker -- cgit v0.12 From 9e5928980c0855f91de016467ef752d3aa338f1a Mon Sep 17 00:00:00 2001 From: Pawel Tomulik Date: Sun, 20 Sep 2015 13:42:22 +0200 Subject: do not set SHxxxx variables in sunar.py --- src/engine/SCons/Tool/sunar.py | 3 --- src/engine/SCons/Tool/sunar.xml | 4 ---- 2 files changed, 7 deletions(-) diff --git a/src/engine/SCons/Tool/sunar.py b/src/engine/SCons/Tool/sunar.py index 3ee4344..eb58457 100644 --- a/src/engine/SCons/Tool/sunar.py +++ b/src/engine/SCons/Tool/sunar.py @@ -51,9 +51,6 @@ def generate(env): env['ARFLAGS'] = SCons.Util.CLVar('r') env['ARCOM'] = '$AR $ARFLAGS $TARGET $SOURCES' - env['SHLINK'] = '$LINK' - env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -G') - env['SHLINKCOM'] = '$SHLINK -o $TARGET $SHLINKFLAGS $__SHLIBVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' env['LIBPREFIX'] = 'lib' env['LIBSUFFIX'] = '.a' diff --git a/src/engine/SCons/Tool/sunar.xml b/src/engine/SCons/Tool/sunar.xml index 65f0c9e..f875217 100644 --- a/src/engine/SCons/Tool/sunar.xml +++ b/src/engine/SCons/Tool/sunar.xml @@ -33,15 +33,11 @@ Sets construction variables for the Sun library archiver. AR ARFLAGS ARCOM -SHLINK -SHLINKFLAGS -SHLINKCOM LIBPREFIX LIBSUFFIX ARCOMSTR -SHLINKCOMSTR -- cgit v0.12 From 123fea257474ede95fa6bef8fb403cc83eff5cdc Mon Sep 17 00:00:00 2001 From: Pawel Tomulik Date: Sun, 20 Sep 2015 17:01:35 +0200 Subject: add tests to test/LINK/VersionedLib.py --- test/LINK/VersionedLib.py | 332 ++++++++++++++++++++++++++++++---------------- 1 file changed, 215 insertions(+), 117 deletions(-) diff --git a/test/LINK/VersionedLib.py b/test/LINK/VersionedLib.py index a75e4a5..2e38dee 100644 --- a/test/LINK/VersionedLib.py +++ b/test/LINK/VersionedLib.py @@ -32,30 +32,167 @@ import SCons.Platform _exe = TestSCons._exe -test = TestSCons.TestSCons() +platform = SCons.Platform.platform_default() -test.write('SConstruct', """\ -import os -env = Environment() -objs = env.SharedObject('test.c') -mylib = env.SharedLibrary('test', objs, SHLIBVERSION = '2.5.4') -env.Program('testapp1.c', LIBS = mylib, LIBPATH='.') -env.Program('testapp2.c', LIBS = ['test'], LIBPATH='.') -instnode = env.InstallVersionedLib("#/installtest",mylib) -env.Default(instnode) -""") +if platform == 'posix': + test_plan = [ + { + 'libversion' : '2', + 'files' : [ 'libtest.so', 'libtest.so.2', 'test.os' ], + 'instfiles' : [ 'libtest.so', 'libtest.so.2' ], + 'symlinks' : [ ('libtest.so', 'libtest.so.2') ], + }, + { + 'libversion' : '2.5', + 'files' : [ 'libtest.so', 'libtest.so.2', 'libtest.so.2.5', 'test.os' ], + 'instfiles' : [ 'libtest.so', 'libtest.so.2', 'libtest.so.2.5' ], + 'symlinks' : [ ('libtest.so', 'libtest.so.2.5'), ('libtest.so.2', 'libtest.so.2.5') ], + }, + { + 'libversion' : '2.5.4', + 'files' : [ 'libtest.so', 'libtest.so.2', 'libtest.so.2.5.4', 'test.os' ], + 'instfiles' : [ 'libtest.so', 'libtest.so.2', 'libtest.so.2.5.4' ], + 'symlinks' : [ ('libtest.so', 'libtest.so.2.5.4'), ('libtest.so.2', 'libtest.so.2.5.4') ], + }, + { + 'libversion' : '2.5.4.7.8', + 'files' : [ 'libtest.so', 'libtest.so.2', 'libtest.so.2.5.4.7.8', 'test.os' ], + 'instfiles' : [ 'libtest.so', 'libtest.so.2', 'libtest.so.2.5.4.7.8' ], + 'symlinks' : [ ('libtest.so', 'libtest.so.2.5.4.7.8'), ('libtest.so.2', 'libtest.so.2.5.4.7.8') ], + }, + { + 'libversion' : 'aabf114f', + 'files' : [ 'libtest.so', 'libtest.so.aabf114f', 'test.os' ], + 'instfiles' : [ 'libtest.so', 'libtest.so.aabf114f' ], + 'symlinks' : [ ('libtest.so', 'libtest.so.aabf114f') ], + }, + { + 'libversion' : '2.dfffa11', + 'files' : [ 'libtest.so', 'libtest.so.2', 'libtest.so.2.dfffa11', 'test.os' ], + 'instfiles' : [ 'libtest.so', 'libtest.so.2', 'libtest.so.2.dfffa11' ], + 'symlinks' : [ ('libtest.so', 'libtest.so.2.dfffa11'), ('libtest.so.2', 'libtest.so.2.dfffa11') ], + }, + ] +elif platform == 'darwin': + # All (?) the files we expect will get created in the current directory + test_plan = [ + { + 'libversion' : '2.5.4', + 'files' : [ 'libtest.dylib', 'libtest.2.5.4.dylib', 'test.os' ], + 'instfiles' : [ 'libtest.dylib', 'libtest.2.5.4.dylib' ], + 'symlinks' : [], + }, + ] +elif platform == 'cygwin': + test_plan = [ + { + 'libversion' : '2.5.4', + 'files' : [ 'cygtest-2-5-4.dll', 'libtest-2-5-4.dll.a', 'libtest.dll.a', 'test.os' ], + 'instfiles' : [ 'cygtest-2-5-4.dll', 'libtest-2-5-4.dll.a', 'libtest.dll.a' ], + 'symlinks' : [], + }, + { + 'libversion' : '2', + 'files' : [ 'cygtest-2.dll', 'libtest-2.dll.a', 'libtest.dll.a', 'test.os' ], + 'instfiles' : [ 'cygtest-2.dll', 'libtest-2.dll.a', 'libtest.dll.a' ], + 'symlinks' : [ ('libtest.dll.a', 'libtest-2.dll.a') ], + }, + { + 'libversion' : '2.5', + 'files' : [ 'cygtest-2-5.dll', 'libtest-2-5.dll.a', 'libtest.dll.a', 'test.os' ], + 'instfiles' : [ 'cygtest-2-5.dll', 'libtest-2-5.dll.a', 'libtest.dll.a' ], + 'symlinks' : [ ('libtest.dll.a', 'libtest-2-5.dll.a') ], + }, + { + 'libversion' : '2.5.4', + 'files' : [ 'cygtest-2-5-4.dll', 'libtest-2-5-4.dll.a', 'libtest.dll.a', 'test.os' ], + 'instfiles' : [ 'cygtest-2-5-4.dll', 'libtest-2-5-4.dll.a', 'libtest.dll.a' ], + 'symlinks' : [ ('libtest.dll.a', 'libtest-2-5-4.dll.a') ], + }, + { + 'libversion' : '2.5.4.7.8', + 'files' : [ 'cygtest-2-5-4-7-8.dll', 'libtest-2-5-4-7-8.dll.a', 'libtest.dll.a', 'test.os' ], + 'instfiles' : [ 'cygtest-2-5-4-7-8.dll', 'libtest-2-5-4-7-8.dll.a', 'libtest.dll.a' ], + 'symlinks' : [ ('libtest.dll.a', 'libtest-2-5-4-7-8.dll.a') ], + }, + { + 'libversion' : 'aabf114f', + 'files' : [ 'cygtest-aabf114f.dll', 'libtest-aabf114f.dll.a', 'libtest.dll.a', 'test.os' ], + 'instfiles' : [ 'cygtest-aabf114f.dll', 'libtest-aabf114f.dll.a', 'libtest.dll.a' ], + 'symlinks' : [ ('libtest.dll.a', 'libtest-aabf114f.dll.a') ], + }, + { + 'libversion' : '2.dfffa11', + 'files' : [ 'cygtest-2-dfffa11.dll', 'libtest-2-dfffa11.dll.a', 'libtest.dll.a', 'test.os' ], + 'instfiles' : [ 'cygtest-2-dfffa11.dll', 'libtest-2-dfffa11.dll.a', 'libtest.dll.a' ], + 'symlinks' : [ ('libtest.dll.a', 'libtest-2-dfffa11.dll.a') ], + }, + ] +elif platform == 'win32': + test_plan = [ + { + 'libversion' : '2.5.4', + 'files' : [ 'test.dll', 'test.lib', 'test.obj' ], + 'instfiles' : [ 'test.dll', 'test.lib' ], + 'symlinks' : [], + }, + ] +elif platform == 'sunos': + test_plan = [ + { + 'libversion' : '2', + 'files' : [ 'libtest.so', 'libtest.so.2', 'so_test.os' ], + 'instfiles' : [ 'libtest.so', 'libtest.so.2' ], + 'symlinks' : [ ('libtest.so', 'libtest.so.2') ], + }, + { + 'libversion' : '2.5', + 'files' : [ 'libtest.so', 'libtest.so.2', 'libtest.so.2.5', 'so_test.os' ], + 'instfiles' : [ 'libtest.so', 'libtest.so.2', 'libtest.so.2.5' ], + 'symlinks' : [ ('libtest.so', 'libtest.so.2.5'), ('libtest.so.2', 'libtest.so.2.5') ], + }, + { + 'libversion' : '2.5.4', + 'files' : [ 'libtest.so', 'libtest.so.2', 'libtest.so.2.5.4', 'so_test.os' ], + 'instfiles' : [ 'libtest.so', 'libtest.so.2', 'libtest.so.2.5.4' ], + 'symlinks' : [ ('libtest.so', 'libtest.so.2.5.4'), ('libtest.so.2', 'libtest.so.2.5.4') ], + }, + { + 'libversion' : '2.5.4.7.8', + 'files' : [ 'libtest.so', 'libtest.so.2', 'libtest.so.2.5.4.7.8', 'so_test.os' ], + 'instfiles' : [ 'libtest.so', 'libtest.so.2', 'libtest.so.2.5.4.7.8' ], + 'symlinks' : [ ('libtest.so', 'libtest.so.2.5.4.7.8'), ('libtest.so.2', 'libtest.so.2.5.4.7.8') ], + }, + { + 'libversion' : 'aabf114f', + 'files' : [ 'libtest.so', 'libtest.so.aabf114f', 'so_test.os' ], + 'instfiles' : [ 'libtest.so', 'libtest.so.aabf114f' ], + 'symlinks' : [ ('libtest.so', 'libtest.so.aabf114f') ], + }, + { + 'libversion' : '2.dfffa11', + 'files' : [ 'libtest.so', 'libtest.so.2', 'libtest.so.2.dfffa11', 'so_test.os' ], + 'instfiles' : [ 'libtest.so', 'libtest.so.2', 'libtest.so.2.dfffa11' ], + 'symlinks' : [ ('libtest.so', 'libtest.so.2.dfffa11'), ('libtest.so.2', 'libtest.so.2.dfffa11') ], + }, + ] +else: + test_plan = [ + { + 'libversion' : '2.5.4', + 'files' : [ 'libtest.so', 'test.os' ], + 'instfiles' : [ ], + }, + ] -test.write('test.c', """\ +test_c_src = """\ #if _WIN32 __declspec(dllexport) #endif -int testlib(int n) -{ -return n+1 ; -} -""") +int testlib(int n) { return n+1 ; } +""" -testapp_src = """\ +testapp_c_src = """\ #if _WIN32 __declspec(dllimport) #endif @@ -70,112 +207,73 @@ 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() +for t in test_plan: + test = TestSCons.TestSCons() -test.run(arguments = ['--tree=all']) + libversion = t['libversion'] + files = t['files'] + symlinks = t['symlinks'] + instfiles = t['instfiles'] -if platform == 'posix': - # All (?) the files we expect will get created in the current directory - files = [ - 'libtest.so', - 'libtest.so.2', - 'libtest.so.2.5.4', - 'test.os', - ] - # All (?) the files we expect will get created in the 'installtest' directory - instfiles = [ - 'libtest.so', - 'libtest.so.2', - 'libtest.so.2.5.4', - ] -elif platform == 'darwin': - # All (?) the files we expect will get created in the current directory - files = [ - 'libtest.dylib', - 'libtest.2.5.4.dylib', - 'test.os', - ] - # All (?) the files we expect will get created in the 'installtest' directory - instfiles = [ - 'libtest.dylib', - 'libtest.2.5.4.dylib', - ] -elif platform == 'cygwin': - # All (?) the files we expect will get created in the current directory - 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 - files = [ - 'test.dll', - 'test.lib', - 'test.obj', - ] - # All (?) the files we expect will get created in the 'installtest' directory - instfiles = [ - 'test.dll', - 'test.lib', - ] -elif platform == 'sunos': - # All (?) the files we expect will get created in the current directory - files = [ - 'libtest.so', - 'libtest.so.2', - 'libtest.so.2.5.4', - 'so_test.os', - ] - # All (?) the files we expect will get created in the 'installtest' directory - instfiles = [ - 'libtest.so', - 'libtest.so.2', - 'libtest.so.2.5.4', - ] -else: - # All (?) the files we expect will get created in the current directory - files= [ - 'libtest.so', - 'test.os'] - # All (?) the files we expect will get created in the 'installtest' directory - instfiles = [] - -for f in files: - test.must_exist([ f]) -for f in instfiles: - test.must_exist(['installtest', f]) - -# modify test.c and make sure it can recompile when links already exist -test.write('test.c', """\ -#if _WIN32 -__declspec(dllexport) -#endif -int testlib(int n) -{ -return n+11 ; -} -""") + test.write('SConstruct', """\ +import os +env = Environment() +objs = env.SharedObject('test.c') +mylib = env.SharedLibrary('test', objs, SHLIBVERSION = '%s') +env.Program('testapp1.c', LIBS = mylib, LIBPATH='.') +env.Program('testapp2.c', LIBS = ['test'], LIBPATH='.') +instnode = env.InstallVersionedLib("#/installtest",mylib) +env.Default(instnode) +""" % libversion) + + test.write('test.c', test_c_src) + test.write('testapp1.c', testapp_c_src) + test.write('testapp2.c', testapp_c_src) + + test.run(arguments = ['--tree=all']) + + for f in files: + test.must_exist([ f]) + for f in instfiles: + test.must_exist(['installtest', f]) + + wrong_symlinks = [] + for (linkname,expected) in symlinks: + try: + endpoint = os.readlink(linkname) + except OSError, err: + print "%s (expected symlink %r -> %r)" % (err, linkname, expected) + wrong_symlinks.append(linkname) + else: + if endpoint != expected: + print "Wrong symlink: %r -> %r (expected symlink: %r -> %r)" % (linkname, endpoint, linkname, expected) + wrong_symlinks.append(linkname) + + if wrong_symlinks: + test.fail_test(wrong_symlinks) + + # modify test.c and make sure it can recompile when links already exist + test.write('test.c', """\ + #if _WIN32 + __declspec(dllexport) + #endif + int testlib(int n) + { + return n+11 ; + } + """) + + test.run() -test.run() + test.run(arguments = ['-c']) -test.run(arguments = ['-c']) + for f in files: + test.must_not_exist([ f]) -for f in files: - test.must_not_exist([ f]) -for f in instfiles: - test.must_not_exist(['installtest', f]) + for f in instfiles: + test.must_not_exist(['installtest', f]) test.pass_test() -- cgit v0.12 From 26f6e3f56d9741cc91cbe034a0e43d91e0fac6a3 Mon Sep 17 00:00:00 2001 From: Pawel Tomulik Date: Sun, 20 Sep 2015 17:09:34 +0200 Subject: fix test/LINK/VersionedLib.py to convince sun studio compiler --- test/LINK/VersionedLib.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/test/LINK/VersionedLib.py b/test/LINK/VersionedLib.py index 2e38dee..0d74a35 100644 --- a/test/LINK/VersionedLib.py +++ b/test/LINK/VersionedLib.py @@ -192,6 +192,13 @@ __declspec(dllexport) int testlib(int n) { return n+1 ; } """ +test_c_src2 = """\ +#if _WIN32 +__declspec(dllexport) +#endif +int testlib(int n) { return n+11 ; } +""" + testapp_c_src = """\ #if _WIN32 __declspec(dllimport) @@ -255,15 +262,7 @@ env.Default(instnode) test.fail_test(wrong_symlinks) # modify test.c and make sure it can recompile when links already exist - test.write('test.c', """\ - #if _WIN32 - __declspec(dllexport) - #endif - int testlib(int n) - { - return n+11 ; - } - """) + test.write('test.c', test_c_src2) test.run() -- cgit v0.12 From ffcb8963212db0e83b79c9cbb584ed6ff3da837a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Tomulik?= Date: Sun, 20 Sep 2015 19:55:34 +0200 Subject: cyglink: fix for shlib symlink not being cleaned correctly --- src/engine/SCons/Tool/__init__.py | 8 ++++++-- src/engine/SCons/Tool/cyglink.py | 2 +- test/LINK/VersionedLib.py | 6 ------ 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py index 96b9d98..7374687 100644 --- a/src/engine/SCons/Tool/__init__.py +++ b/src/engine/SCons/Tool/__init__.py @@ -596,19 +596,23 @@ def StringizeLibSymlinks(symlinks): else: return symlinks -def EmitLibSymlinks(env, symlinks, libnode): +def EmitLibSymlinks(env, symlinks, libnode, **kw): """Used by emitters to handle (shared/versioned) library symlinks""" Verbose = False # nodes involved in process... all symlinks + library nodes = list(set([ x for x,y in symlinks ] + [libnode])) + + clean_targets = kw.get('clean_targets', []) + if not SCons.Util.is_List(clean_targets): + clean_targets = [ clean_targets ] for link, linktgt in symlinks: env.SideEffect(link, linktgt) if(Verbose): print "EmitLibSymlinks: SideEffect(%r,%r)" % (link.get_path(), linktgt.get_path()) clean_list = filter(lambda x : x != linktgt, nodes) - env.Clean(linktgt, clean_list) + env.Clean(list(set([linktgt] + clean_targets)), clean_list) if(Verbose): print "EmitLibSymlinks: Clean(%r,%r)" % (linktgt.get_path(), map(lambda x : x.get_path(), clean_list)) diff --git a/src/engine/SCons/Tool/cyglink.py b/src/engine/SCons/Tool/cyglink.py index e05e85f..deeb410 100644 --- a/src/engine/SCons/Tool/cyglink.py +++ b/src/engine/SCons/Tool/cyglink.py @@ -111,7 +111,7 @@ def _lib_emitter(target, source, env, **kw): if Verbose: print "_lib_emitter: implib symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks) if symlinks: - SCons.Tool.EmitLibSymlinks(env, symlinks, implib_target) + SCons.Tool.EmitLibSymlinks(env, symlinks, implib_target, clean_targets = target[0]) implib_target.attributes.shliblinks = symlinks return (target, source) diff --git a/test/LINK/VersionedLib.py b/test/LINK/VersionedLib.py index 0d74a35..360fa24 100644 --- a/test/LINK/VersionedLib.py +++ b/test/LINK/VersionedLib.py @@ -86,12 +86,6 @@ elif platform == 'darwin': elif platform == 'cygwin': test_plan = [ { - 'libversion' : '2.5.4', - 'files' : [ 'cygtest-2-5-4.dll', 'libtest-2-5-4.dll.a', 'libtest.dll.a', 'test.os' ], - 'instfiles' : [ 'cygtest-2-5-4.dll', 'libtest-2-5-4.dll.a', 'libtest.dll.a' ], - 'symlinks' : [], - }, - { 'libversion' : '2', 'files' : [ 'cygtest-2.dll', 'libtest-2.dll.a', 'libtest.dll.a', 'test.os' ], 'instfiles' : [ 'cygtest-2.dll', 'libtest-2.dll.a', 'libtest.dll.a' ], -- cgit v0.12 From 11711340ea36b162fcef4462f4f01d1d223700cf Mon Sep 17 00:00:00 2001 From: Pawel Tomulik Date: Sun, 20 Sep 2015 21:37:39 +0200 Subject: s/SHLINKSONAME/SHLIBSONAME/ --- src/engine/SCons/Defaults.py | 1 + src/engine/SCons/Tool/cyglink.py | 2 +- src/engine/SCons/Tool/gdc.py | 2 +- src/engine/SCons/Tool/gnulink.xml | 2 +- src/engine/SCons/Tool/link.py | 6 +++--- src/engine/SCons/Tool/link.xml | 4 ++-- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/engine/SCons/Defaults.py b/src/engine/SCons/Defaults.py index c8170c3..744da5f 100644 --- a/src/engine/SCons/Defaults.py +++ b/src/engine/SCons/Defaults.py @@ -512,6 +512,7 @@ ConstructionEnvironment = { '__libversionflags' : __libversionflags, '__SHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}', '__LDMODULEVERSIONFLAGS' : '${__libversionflags(__env__,"LDMODULEVERSION","_LDMODULEVERSIONFLAGS")}', + '__DSHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}', 'TEMPFILE' : NullCmdGenerator, 'Dir' : Variable_Method_Caller('TARGET', 'Dir'), diff --git a/src/engine/SCons/Tool/cyglink.py b/src/engine/SCons/Tool/cyglink.py index deeb410..5230910 100644 --- a/src/engine/SCons/Tool/cyglink.py +++ b/src/engine/SCons/Tool/cyglink.py @@ -216,7 +216,7 @@ def generate(env): } # these variables were set by gnulink but are not used in cyglink - try: del env['_SHLINKSONAME'] + try: del env['_SHLIBSONAME'] except KeyError: pass try: del env['_LDMODULESONAME'] except KeyError: pass diff --git a/src/engine/SCons/Tool/gdc.py b/src/engine/SCons/Tool/gdc.py index 799c3ab..347efef 100644 --- a/src/engine/SCons/Tool/gdc.py +++ b/src/engine/SCons/Tool/gdc.py @@ -97,7 +97,7 @@ def generate(env): env['DSHLINK'] = '$DC' env['DSHLINKFLAGS'] = SCons.Util.CLVar('$DLINKFLAGS -shared') - env['SHDLINKCOM'] = '$DLINK -o $TARGET $DSHLINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' + env['SHDLINKCOM'] = '$DLINK -o $TARGET $DSHLINKFLAGS $__DSHLIBVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' env['DLIB'] = 'lib' if env['PLATFORM'] == 'win32' else 'ar cr' env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {0}$TARGET $SOURCES $_DLINKLIBFLAGS'.format('-c ' if env['PLATFORM'] == 'win32' else '') diff --git a/src/engine/SCons/Tool/gnulink.xml b/src/engine/SCons/Tool/gnulink.xml index 63ce0f4..0e055c7 100644 --- a/src/engine/SCons/Tool/gnulink.xml +++ b/src/engine/SCons/Tool/gnulink.xml @@ -34,7 +34,7 @@ Set construction variables for GNU linker/loader. RPATHPREFIX RPATHSUFFIX _LDMODULESONAME -_SHLINKSONAME +_SHLIBSONAME LDMODULEVERSIONFLAGS SHLIBVERSIONFLAGS diff --git a/src/engine/SCons/Tool/link.py b/src/engine/SCons/Tool/link.py index 6bd36e4..a4a2a4c 100644 --- a/src/engine/SCons/Tool/link.py +++ b/src/engine/SCons/Tool/link.py @@ -256,12 +256,12 @@ def _setup_versioned_lib_variables(env, **kw): if use_soname: # If the linker uses SONAME, then we need this little automata if tool == 'sunlink': - env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS -h $_SHLINKSONAME' + env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS -h $_SHLIBSONAME' env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS -h $_LDMODULESONAME' else: - env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS -Wl,-soname=$_SHLINKSONAME' + env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS -Wl,-soname=$_SHLIBSONAME' env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS -Wl,-soname=$_LDMODULESONAME' - env['_SHLINKSONAME'] = '${ShLibSonameGenerator(__env__,TARGET)}' + env['_SHLIBSONAME'] = '${ShLibSonameGenerator(__env__,TARGET)}' env['_LDMODULESONAME'] = '${LdModSonameGenerator(__env__,TARGET)}' env['ShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator env['LdModSonameGenerator'] = SCons.Tool.LdModSonameGenerator diff --git a/src/engine/SCons/Tool/link.xml b/src/engine/SCons/Tool/link.xml index 52349da..2f913fe 100644 --- a/src/engine/SCons/Tool/link.xml +++ b/src/engine/SCons/Tool/link.xml @@ -107,13 +107,13 @@ This macro automatically introduces extra flags to &cv-link-SHLINKCOM; when building versioned &b-link-SharedLibrary; (that is when &cv-link-SHLIBVERSION; is set). _SHLIBVERSIONFLAGS usually adds &cv-link-SHLIBVERSIONFLAGS; and some extra dynamically generated options (such as --Wl,-soname=$_SHLINKSONAME. It is unused by "plain" +-Wl,-soname=$_SHLIBSONAME. It is unused by "plain" (unversioned) shared libraries. - + A macro that automatically generates shared library's SONAME based on $TARGET, -- cgit v0.12 From 0662dc87640b0b2b42e51b87aa611e666c8a99eb Mon Sep 17 00:00:00 2001 From: Pawel Tomulik Date: Sun, 20 Sep 2015 22:22:10 +0200 Subject: gdc: support soname in D versioned libraries --- src/engine/SCons/Defaults.py | 1 - src/engine/SCons/Tool/gdc.py | 10 +++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/engine/SCons/Defaults.py b/src/engine/SCons/Defaults.py index 744da5f..c8170c3 100644 --- a/src/engine/SCons/Defaults.py +++ b/src/engine/SCons/Defaults.py @@ -512,7 +512,6 @@ ConstructionEnvironment = { '__libversionflags' : __libversionflags, '__SHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}', '__LDMODULEVERSIONFLAGS' : '${__libversionflags(__env__,"LDMODULEVERSION","_LDMODULEVERSIONFLAGS")}', - '__DSHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}', 'TEMPFILE' : NullCmdGenerator, 'Dir' : Variable_Method_Caller('TARGET', 'Dir'), diff --git a/src/engine/SCons/Tool/gdc.py b/src/engine/SCons/Tool/gdc.py index 347efef..255e6f1 100644 --- a/src/engine/SCons/Tool/gdc.py +++ b/src/engine/SCons/Tool/gdc.py @@ -97,7 +97,15 @@ def generate(env): env['DSHLINK'] = '$DC' env['DSHLINKFLAGS'] = SCons.Util.CLVar('$DLINKFLAGS -shared') - env['SHDLINKCOM'] = '$DLINK -o $TARGET $DSHLINKFLAGS $__DSHLIBVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' + # NOTE: using $__SHLIBVERSIONFLAGS here is just a quick hack. The macro + # $__SHLIBVERSIONFLAGS involves _SHLIBVERSIONFLAGS, which are set by + # current linker tool. If the current linker tool is not same as that used + # by gdc, and SHLIBVERSION is defined, an invalid flags may be generated + # for the gdc linker. It looks like the D tools should define its own + # set of variables (__DSHLIBVERSIONFLAGS, _DSHLIBVERSIONFLAGS, + # DSHLIBVERSIONFLAGS, DSHLIBVERSION, etc...) and duplicate the versioning + # machinery. + env['SHDLINKCOM'] = '$DLINK -o $TARGET $DSHLINKFLAGS $__SHLIBVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' env['DLIB'] = 'lib' if env['PLATFORM'] == 'win32' else 'ar cr' env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {0}$TARGET $SOURCES $_DLINKLIBFLAGS'.format('-c ' if env['PLATFORM'] == 'win32' else '') -- cgit v0.12 From 48fcd009ca14235134b8bcc45e9fef7dde472a70 Mon Sep 17 00:00:00 2001 From: Pawel Tomulik Date: Mon, 21 Sep 2015 00:59:51 +0200 Subject: add simple test for $__SHLIBVERSIONFLAGS --- test/LINK/SHLIBVERSIONFLAGS.py | 59 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 test/LINK/SHLIBVERSIONFLAGS.py diff --git a/test/LINK/SHLIBVERSIONFLAGS.py b/test/LINK/SHLIBVERSIONFLAGS.py new file mode 100644 index 0000000..d8fd2e6 --- /dev/null +++ b/test/LINK/SHLIBVERSIONFLAGS.py @@ -0,0 +1,59 @@ +#!/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__" + +import os +import re + +import TestSCons +import SCons.Platform +import SCons.Defaults + +linkers = [ 'gnulink', 'cyglink', 'sunlink' ] + +foo_c_src = "void foo() {}\n" + +env = SCons.Defaults.DefaultEnvironment() +platform = SCons.Platform.platform_default() +tool_list = SCons.Platform.DefaultToolList(platform, env) + +test = TestSCons.TestSCons() +test.write('foo.c', foo_c_src) +test.write('SConstruct', "SharedLibrary('foo','foo.c',SHLIBVERSION='1.2.3')\n") + +if 'gnulink' in tool_list: + test.run(stdout = r".+ -Wl,-Bsymbolic -Wl,-soname=libfoo.so.1( .+)+", match = TestSCons.match_re_dotall) + test.run(arguments = ['-c']) +elif 'sunlink' in tool_list: + test.run(stdout = r".+ -h libfoo.so.1( .+)+", match = TestSCons.match_re_dotall) + test.run(arguments = ['-c']) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: -- cgit v0.12 From c9aab89dd20ec11842c0183cf3c68fa5b8870155 Mon Sep 17 00:00:00 2001 From: Pawel Tomulik Date: Mon, 21 Sep 2015 01:55:43 +0200 Subject: add SONAME support to D tools --- src/engine/SCons/Defaults.py | 1 + src/engine/SCons/Tool/dmd.py | 13 ++++++++++++- src/engine/SCons/Tool/gdc.py | 21 ++++++++++++--------- src/engine/SCons/Tool/ldc.py | 14 +++++++++++++- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/engine/SCons/Defaults.py b/src/engine/SCons/Defaults.py index c8170c3..744da5f 100644 --- a/src/engine/SCons/Defaults.py +++ b/src/engine/SCons/Defaults.py @@ -512,6 +512,7 @@ ConstructionEnvironment = { '__libversionflags' : __libversionflags, '__SHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}', '__LDMODULEVERSIONFLAGS' : '${__libversionflags(__env__,"LDMODULEVERSION","_LDMODULEVERSIONFLAGS")}', + '__DSHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}', 'TEMPFILE' : NullCmdGenerator, 'Dir' : Variable_Method_Caller('TARGET', 'Dir'), diff --git a/src/engine/SCons/Tool/dmd.py b/src/engine/SCons/Tool/dmd.py index a7d46c6..3722936 100644 --- a/src/engine/SCons/Tool/dmd.py +++ b/src/engine/SCons/Tool/dmd.py @@ -114,7 +114,7 @@ def generate(env): env['DSHLINK'] = '$DC' env['DSHLINKFLAGS'] = SCons.Util.CLVar('$DLINKFLAGS -shared -defaultlib=libphobos2.so') - env['SHDLINKCOM'] = '$DLINK -of$TARGET $DSHLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS' + env['SHDLINKCOM'] = '$DLINK -of$TARGET $DSHLINKFLAGS $__DSHLIBVERSIONFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS' env['DLIBLINKPREFIX'] = '' if env['PLATFORM'] == 'win32' else '-L-l' env['DLIBLINKSUFFIX'] = '.lib' if env['PLATFORM'] == 'win32' else '' @@ -139,6 +139,17 @@ def generate(env): env['DRPATHSUFFIX'] = '' env['_DRPATH'] = '${_concat(DRPATHPREFIX, RPATH, DRPATHSUFFIX, __env__)}' + # Support for versioned libraries + env['_DSHLIBVERSIONFLAGS'] = '$DSHLIBVERSIONFLAGS -L-soname=$_DSHLIBSONAME' + env['_DSHLIBSONAME'] = '${DShLibSonameGenerator(__env__,TARGET)}' + # NOTE: this is a quick hack, the soname will only work if there is + # c/c++ linker loaded which provides callback for the ShLibSonameGenerator + env['DShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator + # NOTE: this is only for further reference, currently $DSHLIBVERSION does + # not work, the user must use $SHLIBVERSION + env['DSHLIBVERSION'] = '$SHLIBVERSION' + env['DSHLIBVERSIONFLAGS'] = [] + SCons.Tool.createStaticLibBuilder(env) diff --git a/src/engine/SCons/Tool/gdc.py b/src/engine/SCons/Tool/gdc.py index 255e6f1..32199b3 100644 --- a/src/engine/SCons/Tool/gdc.py +++ b/src/engine/SCons/Tool/gdc.py @@ -97,15 +97,7 @@ def generate(env): env['DSHLINK'] = '$DC' env['DSHLINKFLAGS'] = SCons.Util.CLVar('$DLINKFLAGS -shared') - # NOTE: using $__SHLIBVERSIONFLAGS here is just a quick hack. The macro - # $__SHLIBVERSIONFLAGS involves _SHLIBVERSIONFLAGS, which are set by - # current linker tool. If the current linker tool is not same as that used - # by gdc, and SHLIBVERSION is defined, an invalid flags may be generated - # for the gdc linker. It looks like the D tools should define its own - # set of variables (__DSHLIBVERSIONFLAGS, _DSHLIBVERSIONFLAGS, - # DSHLIBVERSIONFLAGS, DSHLIBVERSION, etc...) and duplicate the versioning - # machinery. - env['SHDLINKCOM'] = '$DLINK -o $TARGET $DSHLINKFLAGS $__SHLIBVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' + env['SHDLINKCOM'] = '$DLINK -o $TARGET $DSHLINKFLAGS $__DSHLIBVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' env['DLIB'] = 'lib' if env['PLATFORM'] == 'win32' else 'ar cr' env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {0}$TARGET $SOURCES $_DLINKLIBFLAGS'.format('-c ' if env['PLATFORM'] == 'win32' else '') @@ -123,6 +115,17 @@ def generate(env): env['RPATHSUFFIX'] = '' env['_RPATH'] = '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}' + # Support for versioned libraries + env['_DSHLIBVERSIONFLAGS'] = '$DSHLIBVERSIONFLAGS -Wl,-soname=$_DSHLIBSONAME' + env['_DSHLIBSONAME'] = '${DShLibSonameGenerator(__env__,TARGET)}' + # NOTE: this is a quick hack, the soname will only work if there is + # c/c++ linker loaded which provides callback for the ShLibSonameGenerator + env['DShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator + # NOTE: this is only for further reference, currently $DSHLIBVERSION does + # not work, the user must use $SHLIBVERSION + env['DSHLIBVERSION'] = '$SHLIBVERSION' + env['DSHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS' + SCons.Tool.createStaticLibBuilder(env) diff --git a/src/engine/SCons/Tool/ldc.py b/src/engine/SCons/Tool/ldc.py index 8f9b117..a3c1275 100644 --- a/src/engine/SCons/Tool/ldc.py +++ b/src/engine/SCons/Tool/ldc.py @@ -105,7 +105,7 @@ def generate(env): # Hack for Fedora the packages of which use the wrong name :-( if os.path.exists('/usr/lib64/libphobos-ldc.so') or os.path.exists('/usr/lib32/libphobos-ldc.so') or os.path.exists('/usr/lib/libphobos-ldc.so') : env['DSHLINKFLAGS'] = SCons.Util.CLVar('$DLINKFLAGS -shared -defaultlib=phobos-ldc') - env['SHDLINKCOM'] = '$DLINK -of=$TARGET $DSHLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS' + env['SHDLINKCOM'] = '$DLINK -of=$TARGET $DSHLINKFLAGS $__DSHLIBVERSIONFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS' env['DLIBLINKPREFIX'] = '' if env['PLATFORM'] == 'win32' else '-L-l' env['DLIBLINKSUFFIX'] = '.lib' if env['PLATFORM'] == 'win32' else '' @@ -131,6 +131,18 @@ def generate(env): env['DRPATHSUFFIX'] = '' env['_DRPATH'] = '${_concat(DRPATHPREFIX, RPATH, DRPATHSUFFIX, __env__)}' + # Support for versioned libraries + env['_DSHLIBVERSIONFLAGS'] = '$DSHLIBVERSIONFLAGS -L-soname=$_DSHLIBSONAME' + env['_DSHLIBSONAME'] = '${DShLibSonameGenerator(__env__,TARGET)}' + # NOTE: this is a quick hack, the soname will only work if there is + # c/c++ linker loaded which provides callback for the ShLibSonameGenerator + env['DShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator + # NOTE: this is only for further reference, currently $DSHLIBVERSION does + # not work, the user must use $SHLIBVERSION + env['DSHLIBVERSION'] = '$SHLIBVERSION' + env['DSHLIBVERSIONFLAGS'] = [] + print "AKUKU: %r" % env.subst('$_DSHLIBVERSIONFLAGS') + SCons.Tool.createStaticLibBuilder(env) -- cgit v0.12 From 810d9787e113ec41451bb4722a764f551cb35178 Mon Sep 17 00:00:00 2001 From: Pawel Tomulik Date: Mon, 21 Sep 2015 02:03:24 +0200 Subject: remove debug message from ldc.py --- src/engine/SCons/Tool/ldc.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/engine/SCons/Tool/ldc.py b/src/engine/SCons/Tool/ldc.py index a3c1275..ade95db 100644 --- a/src/engine/SCons/Tool/ldc.py +++ b/src/engine/SCons/Tool/ldc.py @@ -141,7 +141,6 @@ def generate(env): # not work, the user must use $SHLIBVERSION env['DSHLIBVERSION'] = '$SHLIBVERSION' env['DSHLIBVERSIONFLAGS'] = [] - print "AKUKU: %r" % env.subst('$_DSHLIBVERSIONFLAGS') SCons.Tool.createStaticLibBuilder(env) -- cgit v0.12 From 30664716b8dd63de48ab40865c48db8580f4956b Mon Sep 17 00:00:00 2001 From: Pawel Tomulik Date: Mon, 21 Sep 2015 02:28:58 +0200 Subject: correct logic in VersionedLib*.py tests --- test/LINK/VersionedLib-VariantDir.py | 13 ++++++++----- test/LINK/VersionedLib-j2.py | 13 ++++++++----- test/LINK/VersionedLib-subdir.py | 17 ++++++++++------- test/LINK/VersionedLib.py | 15 ++++++++------- 4 files changed, 34 insertions(+), 24 deletions(-) diff --git a/test/LINK/VersionedLib-VariantDir.py b/test/LINK/VersionedLib-VariantDir.py index 7406a33..0a631b0 100644 --- a/test/LINK/VersionedLib-VariantDir.py +++ b/test/LINK/VersionedLib-VariantDir.py @@ -33,8 +33,11 @@ import os import sys import SCons.Platform +import SCons.Defaults +env = SCons.Defaults.DefaultEnvironment() platform = SCons.Platform.platform_default() +tool_list = SCons.Platform.DefaultToolList(platform, env) test = TestSCons.TestSCons() @@ -96,7 +99,7 @@ if sys.platform.find('irix') != -1: test.run(program = test.workpath('build/bin/main')) -if platform == 'posix': +if 'gnulink' in tool_list: # All (?) the files we expect will get created in the current directory files = [ 'libfoo.so', @@ -104,14 +107,14 @@ if platform == 'posix': 'libfoo.so.0.1.2', ] obj = 'foo.os' -elif platform == 'darwin': +elif 'applelink' in tool_list: # 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': +elif 'cyglink' in tool_list: # All (?) the files we expect will get created in the current directory files = [ 'cygfoo-0-1-2.dll', @@ -119,14 +122,14 @@ elif platform == 'cygwin': 'libfoo.dll.a', ] obj = 'foo.os' -elif platform == 'win32': +elif 'mslink' in tool_list: # All (?) the files we expect will get created in the current directory files = [ 'foo.dll', 'foo.lib', ] obj = 'foo.obj' -elif platform == 'sunos': +elif 'sunlink' in tool_list: # All (?) the files we expect will get created in the current directory files = [ 'libfoo.so', diff --git a/test/LINK/VersionedLib-j2.py b/test/LINK/VersionedLib-j2.py index 6f37e54..249b54f 100644 --- a/test/LINK/VersionedLib-j2.py +++ b/test/LINK/VersionedLib-j2.py @@ -35,6 +35,7 @@ import os import sys import SCons.Platform +import SCons.Defaults test = TestSCons.TestSCons() @@ -63,7 +64,9 @@ env.SharedLibrary('foo', 'foo.c', SHLIBVERSION = '0.1.2') test.run(arguments = ['-j 2', '--tree=all']) +env = SCons.Defaults.DefaultEnvironment() platform = SCons.Platform.platform_default() +tool_list = SCons.Platform.DefaultToolList(platform, env) if platform == 'cygwin': # PATH is used to search for *.dll librarier (cygfoo-0-2-1.dll in our case) @@ -83,7 +86,7 @@ test.run(arguments = ['-c']) platform = SCons.Platform.platform_default() -if platform == 'posix': +if 'gnulink' in tool_list: # All (?) the files we expect will get created in the current directory files = [ 'libfoo.so', @@ -91,14 +94,14 @@ if platform == 'posix': 'libfoo.so.0.1.2', 'foo.os', ] -elif platform == 'darwin': +elif 'applelink' in tool_list: # 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': +elif 'cyglink' in tool_list: # All (?) the files we expect will get created in the current directory files = [ 'cygfoo-0-1-2.dll', @@ -106,14 +109,14 @@ elif platform == 'cygwin': 'libfoo.dll.a', 'foo.os', ] -elif platform == 'win32': +elif 'mslink' in tool_list: # All (?) the files we expect will get created in the current directory files = [ 'foo.dll', 'foo.lib', 'foo.obj', ] -elif platform == 'sunos': +elif 'sunlink' in tool_list: # All (?) the files we expect will get created in the current directory files = [ 'libfoo.so', diff --git a/test/LINK/VersionedLib-subdir.py b/test/LINK/VersionedLib-subdir.py index 15369ef..a2e141b 100644 --- a/test/LINK/VersionedLib-subdir.py +++ b/test/LINK/VersionedLib-subdir.py @@ -37,6 +37,7 @@ import os import sys import SCons.Platform +import SCons.Defaults test = TestSCons.TestSCons() @@ -58,11 +59,13 @@ int main() } """) +env = SCons.Defaults.DefaultEnvironment() platform = SCons.Platform.platform_default() +tool_list = SCons.Platform.DefaultToolList(platform, env) -if platform == 'darwin': +if 'applelink' in tool_list: subdir = 'blah.0.1.2.dylib.blah' -elif platform == 'cygwin': +elif 'cyglink' in tool_list: subdir = 'blah-0-1-2.dll.a.blah' else: subdir = 'blah.so.0.1.2.blah' @@ -90,7 +93,7 @@ if sys.platform.find('irix') != -1: test.run(program = test.workpath('main')) -if platform == 'posix': +if 'gnulink' in tool_list: # All (?) the files we expect will get created in the current directory files = [ 'libfoo.so', @@ -98,14 +101,14 @@ if platform == 'posix': 'libfoo.so.0.1.2', ] obj = 'foo.os' -elif platform == 'darwin': +elif 'applelink' in tool_list: # 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': +elif 'cyglink' in tool_list: # All (?) the files we expect will get created in the current directory files = [ 'cygfoo-0-1-2.dll', @@ -113,14 +116,14 @@ elif platform == 'cygwin': 'libfoo.dll.a', ] obj = 'foo.os' -elif platform == 'win32': +elif 'mslink' in tool_list: # All (?) the files we expect will get created in the current directory files = [ 'foo.dll', 'foo.lib', ] obj = 'foo.obj' -elif platform == 'sunos': +elif 'sunlink' in tool_list: # All (?) the files we expect will get created in the current directory files = [ 'libfoo.so', diff --git a/test/LINK/VersionedLib.py b/test/LINK/VersionedLib.py index 360fa24..599c8aa 100644 --- a/test/LINK/VersionedLib.py +++ b/test/LINK/VersionedLib.py @@ -29,12 +29,13 @@ import sys import TestSCons import SCons.Platform +import SCons.Defaults -_exe = TestSCons._exe - +env = SCons.Defaults.DefaultEnvironment() platform = SCons.Platform.platform_default() +tool_list = SCons.Platform.DefaultToolList(platform, env) -if platform == 'posix': +if 'gnulink' in tool_list: test_plan = [ { 'libversion' : '2', @@ -73,7 +74,7 @@ if platform == 'posix': 'symlinks' : [ ('libtest.so', 'libtest.so.2.dfffa11'), ('libtest.so.2', 'libtest.so.2.dfffa11') ], }, ] -elif platform == 'darwin': +elif 'applelink' in tool_list: # All (?) the files we expect will get created in the current directory test_plan = [ { @@ -83,7 +84,7 @@ elif platform == 'darwin': 'symlinks' : [], }, ] -elif platform == 'cygwin': +elif 'cyglink' in tool_list: test_plan = [ { 'libversion' : '2', @@ -122,7 +123,7 @@ elif platform == 'cygwin': 'symlinks' : [ ('libtest.dll.a', 'libtest-2-dfffa11.dll.a') ], }, ] -elif platform == 'win32': +elif 'mslink' in tool_list: test_plan = [ { 'libversion' : '2.5.4', @@ -131,7 +132,7 @@ elif platform == 'win32': 'symlinks' : [], }, ] -elif platform == 'sunos': +elif 'sunlink' in tool_list: test_plan = [ { 'libversion' : '2', -- cgit v0.12 From 5a0037f5d5b0cdf34e3d61aa4ce702d805ccab2a Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 21 Sep 2015 08:51:12 -0700 Subject: adding amd64 win installer to list of files --- bin/upload-release-files.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/upload-release-files.sh b/bin/upload-release-files.sh index bf09751..735f143 100755 --- a/bin/upload-release-files.sh +++ b/bin/upload-release-files.sh @@ -1,4 +1,6 @@ #!/bin/sh +set -e +set -x if [ $# -lt 2 ]; then echo Usage: $0 VERSION SF_USERNAME @@ -17,6 +19,8 @@ SF_TOPDIR='/home/frs/project/scons' cd build/dist cp -f ../../src/CHANGES.txt ../../src/RELEASE.txt ../../src/Announce.txt . +cp scons-$VERSION.win32.exe scons-$VERSION-setup.exe + set -x # Upload main scons release files: @@ -24,6 +28,7 @@ $RSYNC $RSYNCOPTS \ scons-$VERSION-1.noarch.rpm \ scons-$VERSION-1.src.rpm \ scons-$VERSION-setup.exe \ + scons-$VERSION.win-amd64.exe \ scons-$VERSION.tar.gz \ scons-$VERSION.zip \ Announce.txt CHANGES.txt RELEASE.txt \ -- cgit v0.12 From 1b99bf81ad3ce90268f2b8097946bb2e24ef05b6 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 21 Sep 2015 08:56:47 -0700 Subject: Regenerated docs for 2.4.0 Release --- doc/generated/examples/caching_ex-random_1.xml | 4 ++-- doc/generated/examples/troubleshoot_stacktrace_2.xml | 2 +- doc/generated/variables.gen | 6 ++---- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/doc/generated/examples/caching_ex-random_1.xml b/doc/generated/examples/caching_ex-random_1.xml index 6f64f8f..e7aa631 100644 --- a/doc/generated/examples/caching_ex-random_1.xml +++ b/doc/generated/examples/caching_ex-random_1.xml @@ -1,9 +1,9 @@ % scons -Q -cc -o f2.o -c f2.c cc -o f4.o -c f4.c -cc -o f3.o -c f3.c cc -o f5.o -c f5.c +cc -o f2.o -c f2.c +cc -o f3.o -c f3.c cc -o f1.o -c f1.c cc -o prog f1.o f2.o f3.o f4.o f5.o diff --git a/doc/generated/examples/troubleshoot_stacktrace_2.xml b/doc/generated/examples/troubleshoot_stacktrace_2.xml index 1ab65ee..add59ff 100644 --- a/doc/generated/examples/troubleshoot_stacktrace_2.xml +++ b/doc/generated/examples/troubleshoot_stacktrace_2.xml @@ -8,6 +8,6 @@ scons: internal stack trace: return SCons.Taskmaster.OutOfDateTask.prepare(self) File "bootstrap/src/engine/SCons/Taskmaster.py", line 191, in prepare executor.prepare() - File "bootstrap/src/engine/SCons/Executor.py", line 396, in prepare + File "bootstrap/src/engine/SCons/Executor.py", line 430, in prepare raise SCons.Errors.StopError(msg % (s, self.batches[0].targets[0])) diff --git a/doc/generated/variables.gen b/doc/generated/variables.gen index bf18796..04c3efe 100644 --- a/doc/generated/variables.gen +++ b/doc/generated/variables.gen @@ -6753,9 +6753,7 @@ and translated into the The list of directories that the scripting language wrapper and interface generate will search for included files. The SWIG implicit dependency scanner will search these -directories for include files. -The default is to use the same path -specified as $CPPPATH. +directories for include files. The default value is an empty list. @@ -6802,7 +6800,7 @@ include $_SWIGINCFLAGS: -env = Environment(SWIGCOM="my_swig -o $TARGET $_SWIGINCFLAGS $SORUCES") +env = Environment(SWIGCOM="my_swig -o $TARGET $_SWIGINCFLAGS $SOURCES") -- cgit v0.12 From 093d03ccf05f2a317a6e68efb57f35f79af6d450 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 21 Sep 2015 09:07:09 -0700 Subject: updates for 2.4.0 release --- debian/changelog | 6 ++++++ src/Announce.txt | 8 +++++--- src/CHANGES.txt | 9 ++++++--- src/RELEASE.txt | 55 +++++++++++++++---------------------------------------- 4 files changed, 32 insertions(+), 46 deletions(-) diff --git a/debian/changelog b/debian/changelog index b161db1..7311f78 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +scons (2.4.0) unstable; urgency=low + + * Maintenance release. + + -- William Deegan Mon, 21 Sep 2015 08:56:00 -0700 + scons (2.3.6) unstable; urgency=low * Maintenance release. diff --git a/src/Announce.txt b/src/Announce.txt index f96e703..1d59702 100644 --- a/src/Announce.txt +++ b/src/Announce.txt @@ -18,9 +18,8 @@ So that everyone using SCons can help each other learn how to use it more effectively, please go to http://scons.org/lists.php#users to sign up for the scons-users mailing list. -==============IMPORTANT NOTICE FOR NEXT VERSION V2.4.0=========== +==============IMPORTANT NOTICE=========== -PLEASE READ. CHANGES COMING IN NEXT MAJOR RELEASE V2.4.0 As has been pre-announced in SCons's mailing lists: * https://pairlist4.pair.net/pipermail/scons-users/2014-July/002734.html , @@ -37,13 +36,16 @@ released. Especially if you are directly using the Node class. ================================================================= -RELEASE VERSION/DATE TO BE FILLED IN LATER +RELEASE 2.4.0 - Mon, 21 Sep 2015 08:56:00 -0700 Please consult the RELEASE.txt file for a summary of changes since the last release and consult the CHANGES.txt file for complete a list of changes since last release. This announcement highlights only the important changes. + Please note the following important changes since release 2.3.6: + - Switch several core classes to use "slots" to reduce memory + usage. (PR #2180, #2178, #2198) Please note the following important changes since release 2.3.5: - Support for Visual Studio 2015 diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 977d00f..0299718 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -4,15 +4,18 @@ Change Log -RELEASE VERSION/DATE TO BE FILLED IN LATER +RELEASE 2.4.0 - Mon, 21 Sep 2015 08:56:00 -0700 From Dirk Baechle: - - Switched several core classes to using "slots", for - reducing the overall memory consumption in large + - Switched several core classes to use "slots", to + reduce the overall memory consumption in large projects (fixes #2180, #2178, #2198) - Memoizer counting uses decorators now, instead of the old metaclasses approach. + From Andrew Featherstone + - Fixed typo in SWIGPATH description + RELEASE 2.3.6 - Mon, 31 Jul 2015 14:35:03 -0700 From Rob Smith: diff --git a/src/RELEASE.txt b/src/RELEASE.txt index 83212a7..0bb481d 100644 --- a/src/RELEASE.txt +++ b/src/RELEASE.txt @@ -1,72 +1,47 @@ - A new SCons checkpoint release, 2.3.8.alpha.yyyymmdd, is now available + A new SCons release, 2.4.0, is now available on the SCons download page: http://www.scons.org/download.php - XXX The primary purpose of this release ... XXX - - A SCons "checkpoint release" is intended to provide early access to - new features so they can be tested in the field before being released - for adoption by other software distributions. - - Note that a checkpoint release is developed using the same test-driven - development methodology as all SCons releases. Existing SCons - functionality should all work as it does in previous releases (except - for any changes identified in the release notes) and early adopters - should be able to use a checkpoint release safely for production work - with existing SConscript files. If not, it represents not only a bug - in SCons but also a hole in the regression test suite, and we want to - hear about it. - - New features may be more lightly tested than in past releases, - especially as concerns their interaction with all of the other - functionality in SCons. We are especially interested in hearing bug - reports about new functionality. - - We do not recommend that downstream distributions (Debian, Fedora, - etc.) package a checkpoint release, mainly to avoid confusing the - "public" release numbering with the long checkpoint release names. - - Here is a summary of the changes since 1.3.0: + Here is a summary of the changes since 2.3.6: NEW FUNCTIONALITY - - List new features (presumably why a checkpoint is being released) + - None DEPRECATED FUNCTIONALITY - - List anything that's been deprecated since the last release + - None CHANGED/ENHANCED EXISTING FUNCTIONALITY - - List modifications to existing features, where the previous behavior - wouldn't actually be considered a bug + - None FIXES - - List fixes of outright bugs + - None IMPROVEMENTS - - List improvements that wouldn't be visible to the user in the - documentation: performance improvements (describe the circumstances - under which they would be observed), or major code cleanups + - Switched several core classes to use "slots", to + reduce the overall memory consumption in large + projects (fixes #2180, #2178, #2198) + - Memoizer counting uses decorators now, instead of + the old metaclasses approach. PACKAGING - - List changes in the way SCons is packaged and/or released + - Added new amd64 windows 64 bit installer DOCUMENTATION - - List any significant changes to the documentation (not individual - typo fixes, even if they're mentioned in src/CHANGES.txt to give - the contributor credit) + - None DEVELOPMENT - - List visible changes in the way SCons is developed + - None - Thanks to CURLY, LARRY, and MOE for their contributions to this release. + Thanks to Dirk Baechle, Andrew Featherstone for their contributions to this release. Contributors are listed alphabetically by their last name. __COPYRIGHT__ -- cgit v0.12 From 61aa2966263cdff2cada2f2a9853e982206f989a Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 21 Sep 2015 10:03:12 -0700 Subject: release 2.4.0 --- QMTest/TestSCons.py | 2 +- README.rst | 38 +++++++++++++++++++------------------- ReleaseConfig | 2 +- SConstruct | 4 ++-- src/Announce.txt | 2 +- src/CHANGES.txt | 2 +- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/QMTest/TestSCons.py b/QMTest/TestSCons.py index a9b4e3e..06fa575 100644 --- a/QMTest/TestSCons.py +++ b/QMTest/TestSCons.py @@ -34,7 +34,7 @@ from TestCmd import PIPE # here provides some independent verification that what we packaged # conforms to what we expect. -default_version = '2.3.6' +default_version = '2.4.0' python_version_unsupported = (2, 3, 0) python_version_deprecated = (2, 7, 0) diff --git a/README.rst b/README.rst index 9ed0ccc..4f51523 100644 --- a/README.rst +++ b/README.rst @@ -156,7 +156,7 @@ Or on Windows:: By default, the above commands will do the following: -- Install the version-numbered "scons-2.3.3" and "sconsign-2.3.3" scripts in +- Install the version-numbered "scons-2.4.0" and "sconsign-2.4.0" scripts in the default system script directory (/usr/bin or C:\\Python\*\\Scripts, for example). This can be disabled by specifying the "--no-version-script" option on the command line. @@ -168,23 +168,23 @@ By default, the above commands will do the following: before making it the default on your system. On UNIX or Linux systems, you can have the "scons" and "sconsign" scripts be - hard links or symbolic links to the "scons-2.3.3" and "sconsign-2.3.3" + hard links or symbolic links to the "scons-2.4.0" and "sconsign-2.4.0" scripts by specifying the "--hardlink-scons" or "--symlink-scons" options on the command line. -- Install "scons-2.3.3.bat" and "scons.bat" wrapper scripts in the Python +- Install "scons-2.4.0.bat" and "scons.bat" wrapper scripts in the Python prefix directory on Windows (C:\\Python\*, for example). This can be disabled by specifying the "--no-install-bat" option on the command line. On UNIX or Linux systems, the "--install-bat" option may be specified to - have "scons-2.3.3.bat" and "scons.bat" files installed in the default system + have "scons-2.4.0.bat" and "scons.bat" files installed in the default system script directory, which is useful if you want to install SCons in a shared file system directory that can be used to execute SCons from both UNIX/Linux and Windows systems. - Install the SCons build engine (a Python module) in an appropriate - version-numbered SCons library directory (/usr/lib/scons-2.3.3 or - C:\\Python\*\\scons-2.3.3, for example). See below for more options related to + version-numbered SCons library directory (/usr/lib/scons-2.4.0 or + C:\\Python\*\\scons-2.4.0, for example). See below for more options related to installing the build engine library. - Install the troff-format man pages in an appropriate directory on UNIX or @@ -462,7 +462,7 @@ running all of "runtest.py -a". Building Packages ================= -We use SCons (version 2.3.3 or later) to build its own packages. If you +We use SCons (version 2.4.0 or later) to build its own packages. If you already have an appropriate version of SCons installed on your system, you can build everything by simply running it:: @@ -477,18 +477,18 @@ about `Executing SCons Without Installing`_):: Depending on the utilities installed on your system, any or all of the following packages will be built:: - build/dist/scons-2.3.3-1.noarch.rpm - build/dist/scons-2.3.3-1.src.rpm - build/dist/scons-2.3.3.linux-i686.tar.gz - build/dist/scons-2.3.6.tar.gz - build/dist/scons-2.3.6.win32.exe - build/dist/scons-2.3.6.zip - build/dist/scons-doc-2.3.6.tar.gz - build/dist/scons-local-2.3.6.tar.gz - build/dist/scons-local-2.3.6.zip - build/dist/scons-src-2.3.6.tar.gz - build/dist/scons-src-2.3.6.zip - build/dist/scons_2.3.3-1_all.deb + build/dist/scons-2.4.0-1.noarch.rpm + build/dist/scons-2.4.0-1.src.rpm + build/dist/scons-2.4.0.linux-i686.tar.gz + build/dist/scons-2.4.0.tar.gz + build/dist/scons-2.4.0.win32.exe + build/dist/scons-2.4.0.zip + build/dist/scons-doc-2.4.0.tar.gz + build/dist/scons-local-2.4.0.tar.gz + build/dist/scons-local-2.4.0.zip + build/dist/scons-src-2.4.0.tar.gz + build/dist/scons-src-2.4.0.zip + build/dist/scons_2.4.0-1_all.deb The SConstruct file is supposed to be smart enough to avoid trying to build packages for which you don't have the proper utilities installed. For diff --git a/ReleaseConfig b/ReleaseConfig index 5a191ba..1026c58 100644 --- a/ReleaseConfig +++ b/ReleaseConfig @@ -32,7 +32,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" # 'final', the patchlevel is set to the release date. This value is # mandatory and must be present in this file. #version_tuple = (2, 2, 0, 'final', 0) -version_tuple = (2, 3, 8, 'alpha', 0) +version_tuple = (2, 4, 0) # Python versions prior to unsupported_python_version cause a fatal error # when that version is used. Python versions prior to deprecate_python_version diff --git a/SConstruct b/SConstruct index e8b6c9a..4bff134 100644 --- a/SConstruct +++ b/SConstruct @@ -6,7 +6,7 @@ copyright_years = '2001 - 2015' # This gets inserted into the man pages to reflect the month of release. -month_year = 'July 2015' +month_year = 'September 2015' # # __COPYRIGHT__ @@ -43,7 +43,7 @@ import tempfile import bootstrap project = 'scons' -default_version = '2.3.6' +default_version = '2.4.0' copyright = "Copyright (c) %s The SCons Foundation" % copyright_years platform = distutils.util.get_platform() diff --git a/src/Announce.txt b/src/Announce.txt index 1d59702..25f6b15 100644 --- a/src/Announce.txt +++ b/src/Announce.txt @@ -36,7 +36,7 @@ released. Especially if you are directly using the Node class. ================================================================= -RELEASE 2.4.0 - Mon, 21 Sep 2015 08:56:00 -0700 +RELEASE 2.4.0 - Mon, 21 Sep 2015 09:07:51 -0700 Please consult the RELEASE.txt file for a summary of changes since the last release and consult the CHANGES.txt file for complete a list of changes diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 0299718..8e25e37 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -4,7 +4,7 @@ Change Log -RELEASE 2.4.0 - Mon, 21 Sep 2015 08:56:00 -0700 +RELEASE 2.4.0 - Mon, 21 Sep 2015 09:07:51 -0700 From Dirk Baechle: - Switched several core classes to use "slots", to -- cgit v0.12 -- cgit v0.12 From 8d3afad7ff75457151e6321f05a858f0f2be5dff Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 21 Sep 2015 10:48:21 -0700 Subject: update readme's --- README.rst | 4 ++-- src/README.txt | 55 +++++++++++++++++++++++++++++++------------------------ 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/README.rst b/README.rst index 4f51523..05be712 100644 --- a/README.rst +++ b/README.rst @@ -47,7 +47,7 @@ version at the SCons download page: Execution Requirements ====================== -Running SCons requires Python version 2.6 or later (Python 3 is not +Running SCons requires Python version 2.7 or later (Python 3 is not yet supported). There should be no other dependencies or requirements to run SCons. @@ -748,5 +748,5 @@ many contributors, including but not at all limited to: \... and many others. -__COPYRIGHT__ +Copyright (c) 2001 - 2015 The SCons Foundation diff --git a/src/README.txt b/src/README.txt index 5d880c2..d16433e 100644 --- a/src/README.txt +++ b/src/README.txt @@ -2,7 +2,7 @@ SCons - a software construction tool - Version __VERSION__ + Version 2.4.0 This is SCons, a tool for building software (and other files). SCons is @@ -28,7 +28,8 @@ the latest version by checking the SCons download page at: EXECUTION REQUIREMENTS ====================== -Running SCons requires Python version 2.4 or later. There should be +Running SCons requires Python version 2.7.*. Currently it does not +run on the Python 3.x release. There should be no other dependencies or requirements to run SCons. (There is, however, an additional requirement to *install* SCons from this particular package; see the next section.) @@ -70,17 +71,17 @@ By default, the above command will do the following: making it the default on your system. On UNIX or Linux systems, you can have the "scons" and "sconsign" - scripts be hard links or symbolic links to the "scons-__VERSION__" and - "sconsign-__VERSION__" scripts by specifying the "--hardlink-scons" + scripts be hard links or symbolic links to the "scons-2.4.0" and + "sconsign-2.4.0" scripts by specifying the "--hardlink-scons" or "--symlink-scons" options on the command line. - -- Install "scons-__VERSION__.bat" and "scons.bat" wrapper scripts in the + -- Install "scons-2.4.0.bat" and "scons.bat" wrapper scripts in the Python prefix directory on Windows (C:\Python*, for example). This can be disabled by specifying the "--no-install-bat" option on the command line. On UNIX or Linux systems, the "--install-bat" option may be - specified to have "scons-__VERSION__.bat" and "scons.bat" files + specified to have "scons-2.4.0.bat" and "scons.bat" files installed in the default system script directory, which is useful if you want to install SCons in a shared file system directory that can be used to execute SCons from both UNIX/Linux and @@ -88,7 +89,7 @@ By default, the above command will do the following: -- Install the SCons build engine (a Python module) in an appropriate version-numbered SCons library directory - (/usr/lib/scons-__VERSION__ or C:\Python*\scons-__VERSION__, for example). + (/usr/lib/scons-2.4.0 or C:\Python*\scons-2.4.0, for example). See below for more options related to installing the build engine library. @@ -224,20 +225,26 @@ Check the SCons web site at: AUTHOR INFO =========== - -Steven Knight -knight at baldmt dot com -http://www.baldmt.com/~knight/ - -With plenty of help from the SCons Development team: - Chad Austin - Charles Crain - Steve Leblanc - Greg Noel - Gary Oberbrunner - Anthony Roach - Greg Spencer - Christoph Wiedemann - -__COPYRIGHT__ -__FILE__ __REVISION__ __DATE__ __DEVELOPER__ +SCons was originally written by Steven Knight, knight at baldmt dot com. +Since around 2010 it has been maintained by the SCons +development team, co-managed by Bill Deegan and Gary Oberbrunner, with +many contributors, including but not at all limited to: + +- Chad Austin +- Dirk Baechle +- Charles Crain +- William Deegan +- Steve Leblanc +- Rob Managan +- Greg Noel +- Gary Oberbrunner +- Anthony Roach +- Greg Spencer +- Tom Tanner +- Anatoly Techtonik +- Christoph Wiedemann +- Russel Winder + +\... and many others. + +Copyright (c) 2001 - 2015 The SCons Foundation -- cgit v0.12 From 016463aaaafff9fb747d6a7c4cbed53220b601b5 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 21 Sep 2015 10:55:47 -0700 Subject: add uploading src/README.txt to sourceforge --- bin/upload-release-files.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/bin/upload-release-files.sh b/bin/upload-release-files.sh index 735f143..c853bda 100755 --- a/bin/upload-release-files.sh +++ b/bin/upload-release-files.sh @@ -17,9 +17,10 @@ SF_TOPDIR='/home/frs/project/scons' # the build products are here: cd build/dist -cp -f ../../src/CHANGES.txt ../../src/RELEASE.txt ../../src/Announce.txt . +cp -f ../../src/CHANGES.txt ../../src/RELEASE.txt ../../src/Announce.txt ../../src/README.txt . cp scons-$VERSION.win32.exe scons-$VERSION-setup.exe +cp scons-$VERSION.win-amd64.exe scons-$VERSION-amd64-setup.exe set -x @@ -28,7 +29,7 @@ $RSYNC $RSYNCOPTS \ scons-$VERSION-1.noarch.rpm \ scons-$VERSION-1.src.rpm \ scons-$VERSION-setup.exe \ - scons-$VERSION.win-amd64.exe \ + scons-$VERSION-amd64-setup.exe \ scons-$VERSION.tar.gz \ scons-$VERSION.zip \ Announce.txt CHANGES.txt RELEASE.txt \ @@ -48,6 +49,12 @@ $RSYNC $RSYNCOPTS \ Announce.txt CHANGES.txt RELEASE.txt \ $SF_USER@$SF_MACHINE:$SF_TOPDIR/scons-src/$VERSION/ +# Readme +$RSYNC $RSYNCOPTS \ + README.txt \ + $SF_USER@$SF_MACHINE:$SF_TOPDIR/ + + # # scons.org stuff: -- cgit v0.12 From 859dd4545a76e4f2d7bc90e8193a9175fbc0060b Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 21 Sep 2015 10:58:16 -0700 Subject: switch back to develop content --- ReleaseConfig | 2 +- src/Announce.txt | 2 +- src/CHANGES.txt | 7 +++++++ src/RELEASE.txt | 55 ++++++++++++++++++++++++++++++++++++++++--------------- 4 files changed, 49 insertions(+), 17 deletions(-) diff --git a/ReleaseConfig b/ReleaseConfig index 5a191ba..07cbe44 100644 --- a/ReleaseConfig +++ b/ReleaseConfig @@ -32,7 +32,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" # 'final', the patchlevel is set to the release date. This value is # mandatory and must be present in this file. #version_tuple = (2, 2, 0, 'final', 0) -version_tuple = (2, 3, 8, 'alpha', 0) +version_tuple = (2, 3, 9, 'alpha', 0) # Python versions prior to unsupported_python_version cause a fatal error # when that version is used. Python versions prior to deprecate_python_version diff --git a/src/Announce.txt b/src/Announce.txt index 1d59702..7a13b81 100644 --- a/src/Announce.txt +++ b/src/Announce.txt @@ -36,7 +36,7 @@ released. Especially if you are directly using the Node class. ================================================================= -RELEASE 2.4.0 - Mon, 21 Sep 2015 08:56:00 -0700 +RELEASE VERSION/DATE TO BE FILLED IN LATER Please consult the RELEASE.txt file for a summary of changes since the last release and consult the CHANGES.txt file for complete a list of changes diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 0299718..fd617cb 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -4,6 +4,13 @@ Change Log +RELEASE VERSION/DATE TO BE FILLED IN LATER + + From John Doe: + + - Whatever John Doe did. + + RELEASE 2.4.0 - Mon, 21 Sep 2015 08:56:00 -0700 From Dirk Baechle: diff --git a/src/RELEASE.txt b/src/RELEASE.txt index 0bb481d..d13de57 100644 --- a/src/RELEASE.txt +++ b/src/RELEASE.txt @@ -1,47 +1,72 @@ - A new SCons release, 2.4.0, is now available + A new SCons checkpoint release, 2.3.9.alpha.yyyymmdd, is now available on the SCons download page: http://www.scons.org/download.php - Here is a summary of the changes since 2.3.6: + XXX The primary purpose of this release ... XXX + + A SCons "checkpoint release" is intended to provide early access to + new features so they can be tested in the field before being released + for adoption by other software distributions. + + Note that a checkpoint release is developed using the same test-driven + development methodology as all SCons releases. Existing SCons + functionality should all work as it does in previous releases (except + for any changes identified in the release notes) and early adopters + should be able to use a checkpoint release safely for production work + with existing SConscript files. If not, it represents not only a bug + in SCons but also a hole in the regression test suite, and we want to + hear about it. + + New features may be more lightly tested than in past releases, + especially as concerns their interaction with all of the other + functionality in SCons. We are especially interested in hearing bug + reports about new functionality. + + We do not recommend that downstream distributions (Debian, Fedora, + etc.) package a checkpoint release, mainly to avoid confusing the + "public" release numbering with the long checkpoint release names. + + Here is a summary of the changes since 1.3.0: NEW FUNCTIONALITY - - None + - List new features (presumably why a checkpoint is being released) DEPRECATED FUNCTIONALITY - - None + - List anything that's been deprecated since the last release CHANGED/ENHANCED EXISTING FUNCTIONALITY - - None + - List modifications to existing features, where the previous behavior + wouldn't actually be considered a bug FIXES - - None + - List fixes of outright bugs IMPROVEMENTS - - Switched several core classes to use "slots", to - reduce the overall memory consumption in large - projects (fixes #2180, #2178, #2198) - - Memoizer counting uses decorators now, instead of - the old metaclasses approach. + - List improvements that wouldn't be visible to the user in the + documentation: performance improvements (describe the circumstances + under which they would be observed), or major code cleanups PACKAGING - - Added new amd64 windows 64 bit installer + - List changes in the way SCons is packaged and/or released DOCUMENTATION - - None + - List any significant changes to the documentation (not individual + typo fixes, even if they're mentioned in src/CHANGES.txt to give + the contributor credit) DEVELOPMENT - - None + - List visible changes in the way SCons is developed - Thanks to Dirk Baechle, Andrew Featherstone for their contributions to this release. + Thanks to CURLY, LARRY, and MOE for their contributions to this release. Contributors are listed alphabetically by their last name. __COPYRIGHT__ -- cgit v0.12 From 9fee88e50ebc808dff8aae58fea35b354af83d0a Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 21 Sep 2015 17:46:28 -0700 Subject: remove extraneous release boilerplate text --- src/CHANGES.txt | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 31cc073..fd617cb 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -11,34 +11,6 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Whatever John Doe did. -RELEASE VERSION/DATE TO BE FILLED IN LATER - - From John Doe: - - - Whatever John Doe did. - - -RELEASE VERSION/DATE TO BE FILLED IN LATER - - From John Doe: - - - Whatever John Doe did. - - -RELEASE VERSION/DATE TO BE FILLED IN LATER - - From John Doe: - - - Whatever John Doe did. - - -RELEASE VERSION/DATE TO BE FILLED IN LATER - - From John Doe: - - - Whatever John Doe did. - - RELEASE 2.4.0 - Mon, 21 Sep 2015 08:56:00 -0700 From Dirk Baechle: -- cgit v0.12 From 600def5cde72f16a2684005ced499dff9d0e5653 Mon Sep 17 00:00:00 2001 From: Florian Miedniak Date: Tue, 22 Sep 2015 10:47:29 +0200 Subject: Fixed #3011: Glob() called with exclude didn't work when called from a SConscript that is executed with variant_dir set and duplicate=0 --- src/engine/SCons/Node/FS.py | 7 ++++++- test/Glob/VariantDir.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index a3db8fe..7461710 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -2182,7 +2182,12 @@ class Dir(Base): r = [os.path.join(str(dir), x) for x in r] result.extend(r) if exclude: - result = filter(lambda x: not any(fnmatch.fnmatch(str(x), e) for e in SCons.Util.flatten(exclude)), result) + excludes = [] + excludeList = SCons.Util.flatten(exclude) + for x in excludeList: + r = self.glob(x, ondisk, source, strings) + excludes.extend(r) + result = filter(lambda x: not any(fnmatch.fnmatch(str(x), str(e)) for e in SCons.Util.flatten(excludes)), result) return sorted(result, key=lambda a: str(a)) def _glob1(self, pattern, ondisk=True, source=False, strings=False): diff --git a/test/Glob/VariantDir.py b/test/Glob/VariantDir.py index 175e5b9..c9c1d07 100644 --- a/test/Glob/VariantDir.py +++ b/test/Glob/VariantDir.py @@ -34,6 +34,7 @@ import TestSCons test = TestSCons.TestSCons() test.subdir('src') +test.subdir('src/sub1') test.write('SConstruct', """\ VariantDir('var1', 'src') @@ -41,6 +42,9 @@ VariantDir('var2', 'src') SConscript('var1/SConscript') SConscript('var2/SConscript') +SConscript('var1/sub1/SConscript') +SConscript('var2/sub1/SConscript') +SConscript('src/sub1/SConscript', src_dir = 'src', variant_dir = 'var3', duplicate=0) """) test.write(['src', 'SConscript'], """\ @@ -55,16 +59,46 @@ def concatenate(target, source, env): env['BUILDERS']['Concatenate'] = Builder(action=concatenate) env.Concatenate('f.out', sorted(Glob('f*.in'), key=lambda t: t.name)) +env.Concatenate('fex.out', sorted(Glob('f*.in', exclude = 'f1.in'), key=lambda t: t.name)) +""") + +test.write(['src', 'sub1', 'SConscript'], """\ +env = Environment() + +def concatenate(target, source, env): + fp = open(str(target[0]), 'wb') + for s in source: + fp.write(open(str(s), 'rb').read()) + fp.close() + +env['BUILDERS']['Concatenate'] = Builder(action=concatenate) + +env.Concatenate('f.out', sorted(Glob('f*.in'), key=lambda t: t.name)) +env.Concatenate('fex.out', sorted(Glob('f*.in', exclude = 'f1.in'), key=lambda t: t.name)) """) test.write(['src', 'f1.in'], "src/f1.in\n") test.write(['src', 'f2.in'], "src/f2.in\n") test.write(['src', 'f3.in'], "src/f3.in\n") +test.write(['src', 'sub1', 'f1.in'], "src/sub1/f1.in\n") +test.write(['src', 'sub1', 'f2.in'], "src/sub1/f2.in\n") +test.write(['src', 'sub1', 'f3.in'], "src/sub1/f3.in\n") + test.run(arguments = '.') test.must_match(['var1', 'f.out'], "src/f1.in\nsrc/f2.in\nsrc/f3.in\n") test.must_match(['var2', 'f.out'], "src/f1.in\nsrc/f2.in\nsrc/f3.in\n") +test.must_match(['var1', 'fex.out'], "src/f2.in\nsrc/f3.in\n") +test.must_match(['var2', 'fex.out'], "src/f2.in\nsrc/f3.in\n") + +test.must_match(['var1', 'sub1', 'f.out'], "src/sub1/f1.in\nsrc/sub1/f2.in\nsrc/sub1/f3.in\n") +test.must_match(['var2', 'sub1', 'f.out'], "src/sub1/f1.in\nsrc/sub1/f2.in\nsrc/sub1/f3.in\n") +test.must_match(['var1', 'sub1', 'fex.out'], "src/sub1/f2.in\nsrc/sub1/f3.in\n") +test.must_match(['var2', 'sub1', 'fex.out'], "src/sub1/f2.in\nsrc/sub1/f3.in\n") + +test.must_match(['var3', 'sub1', 'f.out'], "src/sub1/f1.in\nsrc/sub1/f2.in\nsrc/sub1/f3.in\n") +test.must_match(['var3', 'sub1', 'fex.out'], "src/sub1/f2.in\nsrc/sub1/f3.in\n") test.pass_test() -- cgit v0.12 From e902d86ed981c406ce5a8d120c46f580d8ef0717 Mon Sep 17 00:00:00 2001 From: ptomulik Date: Tue, 22 Sep 2015 12:57:48 +0200 Subject: add blurb to src/CHANGES.txt --- src/CHANGES.txt | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 977d00f..860df99 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -6,6 +6,33 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER + From Paweł Tomulik: + - Reimplemented versioning for shared libraries, with the following effects + - Fixed tigris issues #3001, #3006. + - Fixed several other issues not reported to tigris, including: + issues with versioned libraries in subdirectories with tricky names, + issues with versioned libraries and variant directories, + issue with soname not being injected to library when using D linkers, + - Switched to direct symlinks instead of daisy-chained ones -- soname and + development symlinks point directly to the versioned shared library now), + for rationale see: + https://www.debian.org/doc/debian-policy/ch-sharedlibs.html + https://fedoraproject.org/wiki/Packaging:Guidelines#Devel_Packages + https://bitbucket.org/scons/scons/pull-requests/247/new-versioned-libraries-gnulink-cyglink/diff#comment-10063929 + - New construction variables to allow override default behavior: SONAME, + SHLIBVERSIONFLAGS, _SHLIBVERSIONFLAGS, SHLIBNOVERSIONSYMLINKS, + LDMODULEVERSION, LDMODULEVERSIONFLAGS, _LDMODULEVERSIONFLAGS, + LDMODULENOVERSIONSYMLINKS. + - Changed logic used to configure the versioning machinery from + platform-centric to linker-oriented. + - The SHLIBVERSION/LDMODULEVERSION variables are no longer validated by + SCons (more freedom to users). + - InstallVersionedLib() doesn't use SHLIBVERSION anymore. + - Enchanced docs for the library versioning stuff. + - New tests for versioned libraries. + - Library versioning is currently implemented for the following linker + tools: 'cyglink', 'gnulink', 'sunlink'. + From Dirk Baechle: - Switched several core classes to using "slots", for reducing the overall memory consumption in large -- cgit v0.12 From 0179419a4beb70434d930d418dbbcfa7cd628afb Mon Sep 17 00:00:00 2001 From: William Blevins Date: Wed, 23 Sep 2015 14:37:51 +0100 Subject: Added test to verify InstallVersionLib available from DefaultEnvironment. --- test/LINK/VersionedLib.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/LINK/VersionedLib.py b/test/LINK/VersionedLib.py index 599c8aa..3f4a912 100644 --- a/test/LINK/VersionedLib.py +++ b/test/LINK/VersionedLib.py @@ -228,6 +228,12 @@ env.Program('testapp1.c', LIBS = mylib, LIBPATH='.') env.Program('testapp2.c', LIBS = ['test'], LIBPATH='.') instnode = env.InstallVersionedLib("#/installtest",mylib) env.Default(instnode) + +# Extra test to ensure that InstallVersionedLib can be called from the DefaultEnvironment +# Ensures orthogonality where InstallVersionedLib wasn't previously available: SCons gave NameError. +instnode = InstallVersionedLib("defaultenv-installtest",mylib) +Default(instnode) + """ % libversion) test.write('test.c', test_c_src) @@ -240,6 +246,7 @@ env.Default(instnode) test.must_exist([ f]) for f in instfiles: test.must_exist(['installtest', f]) + test.must_exist(['defaultenv-installtest', f]) wrong_symlinks = [] for (linkname,expected) in symlinks: @@ -268,6 +275,7 @@ env.Default(instnode) for f in instfiles: test.must_not_exist(['installtest', f]) + test.must_not_exist(['defaultenv-installtest', f]) test.pass_test() -- cgit v0.12 From 336f967488b7f51a7b073a8808075dd2080a0580 Mon Sep 17 00:00:00 2001 From: William Blevins Date: Tue, 22 Sep 2015 21:15:53 +0100 Subject: Added InstallVersionedLib to default environment init for orthogonality with other Install[As] methods. --- src/engine/SCons/Script/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py index bb7b632..90b1fc3 100644 --- a/src/engine/SCons/Script/__init__.py +++ b/src/engine/SCons/Script/__init__.py @@ -318,6 +318,7 @@ GlobalDefaultEnvironmentFunctions = [ 'Ignore', 'Install', 'InstallAs', + 'InstallVersionedLib', 'Literal', 'Local', 'ParseDepends', -- cgit v0.12 From 366627b426a8b90e0c1fc0ffaf51f31dbdf76de1 Mon Sep 17 00:00:00 2001 From: William Blevins Date: Wed, 23 Sep 2015 00:01:24 +0100 Subject: Updated CHANGES.txt for adding InstallVersionedLib to DefaultEnvironment context. --- src/CHANGES.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 802ca5e..5f54668 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -6,6 +6,10 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER + From William Blevins: + - InstallVersionedLib now available in the DefaultEnvironment context. + - Improves orthogonality of use cases between different Install functions. + From Paweł Tomulik: - Reimplemented versioning for shared libraries, with the following effects - Fixed tigris issues #3001, #3006. -- cgit v0.12 From 1d5c456aa0d3d34b4cf46350ae3eb5b7a0150234 Mon Sep 17 00:00:00 2001 From: Florian Miedniak Date: Wed, 23 Sep 2015 22:52:03 +0200 Subject: Corrected indentation --- src/engine/SCons/Node/FS.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 7461710..4e78852 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -2185,8 +2185,8 @@ class Dir(Base): excludes = [] excludeList = SCons.Util.flatten(exclude) for x in excludeList: - r = self.glob(x, ondisk, source, strings) - excludes.extend(r) + r = self.glob(x, ondisk, source, strings) + excludes.extend(r) result = filter(lambda x: not any(fnmatch.fnmatch(str(x), str(e)) for e in SCons.Util.flatten(excludes)), result) return sorted(result, key=lambda a: str(a)) -- cgit v0.12 From 337a0ab2a7ee2f12cec0975b44e66a78c8be7bae Mon Sep 17 00:00:00 2001 From: Florian Miedniak Date: Wed, 23 Sep 2015 22:52:23 +0200 Subject: added some blurb --- src/CHANGES.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 5f54668..f23d847 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -6,6 +6,9 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER + From Florian Miedniak: + - Fixed tigris issue #3011: Glob() excludes didn't work when used with VariantDir(duplicate=0) + From William Blevins: - InstallVersionedLib now available in the DefaultEnvironment context. - Improves orthogonality of use cases between different Install functions. -- cgit v0.12 From 9efc846a1dbd96a07f1141497015129543a0274b Mon Sep 17 00:00:00 2001 From: William Blevins Date: Wed, 23 Sep 2015 22:59:56 +0100 Subject: Updated SHLIBVERSION documentation to reflect PR-247. --- src/engine/SCons/Tool/__init__.xml | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/engine/SCons/Tool/__init__.xml b/src/engine/SCons/Tool/__init__.xml index 7f19bfc..358ff1e 100644 --- a/src/engine/SCons/Tool/__init__.xml +++ b/src/engine/SCons/Tool/__init__.xml @@ -200,22 +200,20 @@ For maximum portability, use the &b-LoadableModule; builder for the latter. When the &cv-link-SHLIBVERSION; 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. +are needed. env.SharedLibrary(target = 'bar', source = ['bar.c', 'foo.o'], SHLIBVERSION='1.5.2') - -This builder may create multiple links to the library. On a POSIX system, -for the shared library libbar.so.2.3.1, the links created would be -libbar.so and libbar.so.2; on a Darwin (OSX) system -the library would be libbar.2.3.1.dylib and the link would be -libbar.dylib. +On a POSIX system, versions with a single token create exactly one symlink: +libbar.so.6 would have symlinks libbar.so only. +On a POSIX system, versions with two or more +tokens create exactly two symlinks: libbar.so.2.3.1 would have symlinks +libbar.so and libbar.so.2; on a Darwin (OSX) system the library would be +libbar.2.3.1.dylib and the link would be libbar.dylib. @@ -490,10 +488,8 @@ 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. +that are needed. &cv-link-LDMODULEVERSION; versions should exist in the same +format as &cv-link-SHLIBVERSION. @@ -521,9 +517,9 @@ When this construction variable is defined, a versioned shared library 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. +that are needed. &cv-link-SHLIBVERSION; versions should exist as alpha-numeric, +decimal-delimited values as defined by the regular expression "\w+[\.\w+]*". +Example &cv-link-SHLIBVERSION; values include '1', '1.2.3', and '1.2.gitaa412c8b'. -- cgit v0.12