From 5758e27903c4e584b08ad2d69fa80884894e140e Mon Sep 17 00:00:00 2001 From: Robert Managan Date: Tue, 18 Dec 2012 15:08:45 -0800 Subject: removed versioned library support from Install and put it in InstallVersionedLib --- src/CHANGES.txt | 4 +- src/engine/SCons/Tool/__init__.py | 8 +-- src/engine/SCons/Tool/install.py | 102 +++++++++++++++++++++++++++++++++++++- src/engine/SCons/Tool/install.xml | 10 +++- src/engine/SCons/Tool/link.py | 4 +- test/LINK/VersionedLib.py | 2 +- 6 files changed, 118 insertions(+), 12 deletions(-) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 994cc71..ea257d4 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -53,8 +53,8 @@ RELEASE 2.X.X - so biber is called automatically if biblatex requires it. - Add SHLIBVERSION as an option that tells SharedLibrary to build a versioned shared library and create the required symlinks. - Update Install to create the required symlinks when installing - a versioned shared library. + Add builder InstallVersionedLib to create the required symlinks + installing a versioned shared library. RELEASE 2.2.0 - Mon, 05 Aug 2012 15:37:48 +0000 diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py index 4f46cd8..83c2fb5 100644 --- a/src/engine/SCons/Tool/__init__.py +++ b/src/engine/SCons/Tool/__init__.py @@ -246,6 +246,7 @@ def VersionShLibLinkNames(version, libname, env): 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': @@ -639,13 +640,16 @@ class ToolInitializer(object): # the ToolInitializer class. def Initializers(env): - ToolInitializer(env, ['install'], ['_InternalInstall', '_InternalInstallAs']) + ToolInitializer(env, ['install'], ['_InternalInstall', '_InternalInstallAs', '_InternalInstallVersionedLib']) def Install(self, *args, **kw): return self._InternalInstall(*args, **kw) def InstallAs(self, *args, **kw): return self._InternalInstallAs(*args, **kw) + def InstallVersionedLib(self, *args, **kw): + return self._InternalInstallVersionedLib(*args, **kw) env.AddMethod(Install) env.AddMethod(InstallAs) + env.AddMethod(InstallVersionedLib) def FindTool(tools, env): for tool in tools: @@ -792,5 +796,3 @@ def tool_list(platform, env): # End: # vim: set expandtab tabstop=4 shiftwidth=4: - - diff --git a/src/engine/SCons/Tool/install.py b/src/engine/SCons/Tool/install.py index eb50405..9aa9d46 100644 --- a/src/engine/SCons/Tool/install.py +++ b/src/engine/SCons/Tool/install.py @@ -119,6 +119,23 @@ def copyFunc(dest, source, env): shutil.copy2(source, dest) st = os.stat(source) os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) + + return 0 + +# +# Functions doing the actual work of the InstallVersionedLib Builder. +# +def copyFuncVersionedLib(dest, source, env): + """Install a versioned library into a destination by copying, + (including copying permission/mode bits) and then creating + required symlinks.""" + + if os.path.isdir(source): + raise SCons.Errors.UserError("cannot install directory `%s' as a version library" % str(source) ) + else: + 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) return 0 @@ -202,6 +219,22 @@ def installFunc(target, source, env): return 0 +def installFuncVersionedLib(target, source, env): + """Install a versioned library into a target using the function specified + as the INSTALLVERSIONEDLIB construction variable.""" + try: + install = env['INSTALLVERSIONEDLIB'] + except KeyError: + raise SCons.Errors.UserError('Missing INSTALLVERSIONEDLIB construction variable.') + + assert len(target)==len(source), \ + "Installing source %s into target %s: target and source lists must have same length."%(list(map(str, source)), list(map(str, target))) + for t,s in zip(target,source): + if install(t.get_path(),s.get_path(),env): + return 1 + + return 0 + def stringFunc(target, source, env): installstr = env.get('INSTALLSTR') if installstr: @@ -223,6 +256,17 @@ def add_targets_to_INSTALLED_FILES(target, source, env): scons call will be collected. """ global _INSTALLED_FILES, _UNIQUE_INSTALLED_FILES + _INSTALLED_FILES.extend(target) + + _UNIQUE_INSTALLED_FILES = None + return (target, source) + +def add_versioned_targets_to_INSTALLED_FILES(target, source, env): + """ an emitter that adds all target files to the list stored in the + _INSTALLED_FILES global variable. This way all installed files of one + scons call will be collected. + """ + global _INSTALLED_FILES, _UNIQUE_INSTALLED_FILES Verbose = False _INSTALLED_FILES.extend(target) @@ -260,8 +304,9 @@ class DESTDIR_factory(object): # # The Builder Definition # -install_action = SCons.Action.Action(installFunc, stringFunc) -installas_action = SCons.Action.Action(installFunc, stringFunc) +install_action = SCons.Action.Action(installFunc, stringFunc) +installas_action = SCons.Action.Action(installFunc, stringFunc) +installVerLib_action = SCons.Action.Action(installFuncVersionedLib, stringFunc) BaseInstallBuilder = None @@ -302,6 +347,37 @@ def InstallAsBuilderWrapper(env, target=None, source=None, **kw): result.extend(BaseInstallBuilder(env, tgt, src, **kw)) return result +BaseVersionedInstallBuilder = None + +def InstallVersionedBuilderWrapper(env, target=None, source=None, dir=None, **kw): + if target and dir: + import SCons.Errors + raise SCons.Errors.UserError("Both target and dir defined for Install(), only one may be defined.") + if not dir: + dir=target + + import SCons.Script + install_sandbox = SCons.Script.GetOption('install_sandbox') + if install_sandbox: + target_factory = DESTDIR_factory(env, install_sandbox) + else: + target_factory = env.fs + + try: + dnodes = env.arg2nodes(dir, target_factory.Dir) + except TypeError: + raise SCons.Errors.UserError("Target `%s' of Install() is a file, but should be a directory. Perhaps you have the Install() arguments backwards?" % str(dir)) + sources = env.arg2nodes(source, env.fs.Entry) + tgt = [] + for dnode in dnodes: + for src in sources: + # Prepend './' so the lookup doesn't interpret an initial + # '#' on the file name portion as meaning the Node should + # be relative to the top-level SConstruct directory. + target = env.fs.Entry('.'+os.sep+src.name, dnode) + tgt.extend(BaseVersionedInstallBuilder(env, target, src, **kw)) + return tgt + added = None def generate(env): @@ -332,8 +408,25 @@ def generate(env): emitter = [ add_targets_to_INSTALLED_FILES, ], name = 'InstallBuilder') + global BaseVersionedInstallBuilder + if BaseVersionedInstallBuilder is None: + install_sandbox = GetOption('install_sandbox') + if install_sandbox: + target_factory = DESTDIR_factory(env, install_sandbox) + else: + target_factory = env.fs + + BaseVersionedInstallBuilder = SCons.Builder.Builder( + action = installVerLib_action, + target_factory = target_factory.Entry, + source_factory = env.fs.Entry, + multi = 1, + emitter = [ add_versioned_targets_to_INSTALLED_FILES, ], + name = 'InstallVersionedBuilder') + env['BUILDERS']['_InternalInstall'] = InstallBuilderWrapper env['BUILDERS']['_InternalInstallAs'] = InstallAsBuilderWrapper + env['BUILDERS']['_InternalInstallVersionedLib'] = InstallVersionedBuilderWrapper # We'd like to initialize this doing something like the following, # but there isn't yet support for a ${SOURCE.type} expansion that @@ -352,6 +445,11 @@ def generate(env): except KeyError: env['INSTALL'] = copyFunc + try: + env['INSTALLVERSIONEDLIB'] + except KeyError: + env['INSTALLVERSIONEDLIB'] = copyFuncVersionedLib + def exists(env): return 1 diff --git a/src/engine/SCons/Tool/install.xml b/src/engine/SCons/Tool/install.xml index b83bb60..d9cb671 100644 --- a/src/engine/SCons/Tool/install.xml +++ b/src/engine/SCons/Tool/install.xml @@ -24,8 +24,7 @@ which must be a directory. The names of the specified source files or directories remain the same within the destination directory. The sources may be given as a string or as a node returned by -a builder. If the source is a versioned shared library -the appropriate symlinks to it will be generated. +a builder. env.Install('/usr/local/bin', source = ['foo', 'bar']) @@ -45,6 +44,13 @@ and source arguments list different numbers of files or directories. + + +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. +The symlinks appropriate to the architecture will be generated. + env.InstallAs(target = '/usr/local/bin/foo', source = 'foo_debug') diff --git a/src/engine/SCons/Tool/link.py b/src/engine/SCons/Tool/link.py index 67d5b19..2ba419e 100644 --- a/src/engine/SCons/Tool/link.py +++ b/src/engine/SCons/Tool/link.py @@ -140,7 +140,7 @@ def generate(env): env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared') env['SHLINKCOM'] = '$SHLINK -o $TARGET $SHLINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' # don't set up the emitter, cause AppendUnique will generate a list - # starting with None + # starting with None :-( env.Append(SHLIBEMITTER = [shlib_emitter]) env['SMARTLINK'] = smart_link env['LINK'] = "$SMARTLINK" @@ -164,7 +164,7 @@ def generate(env): SCons.Tool.createLoadableModuleBuilder(env) env['LDMODULE'] = '$SHLINK' # don't set up the emitter, cause AppendUnique will generate a list - # starting with None + # starting with None :-( env.Append(LDMODULEEMITTER='$SHLIBEMITTER') env['LDMODULEPREFIX'] = '$SHLIBPREFIX' env['LDMODULESUFFIX'] = '$SHLIBSUFFIX' diff --git a/test/LINK/VersionedLib.py b/test/LINK/VersionedLib.py index da0a8c4..34bef2a 100644 --- a/test/LINK/VersionedLib.py +++ b/test/LINK/VersionedLib.py @@ -41,7 +41,7 @@ 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']) -instnode = env.Install("#/installtest",mylib) +instnode = env.InstallVersionedLib("#/installtest",mylib) env.Default(instnode) """) -- cgit v0.12