summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMichael Kuhn <suraia@ikkoku.de>2017-11-07 01:21:46 +0100
committerChristoph Junghans <christoph.junghans@gmail.com>2017-11-06 17:21:46 -0700
commitca73103dac47dc2cdfff51c146205611a72bb401 (patch)
treebbe0dc903bd44ca26384b7fe89a79afbbe970d65 /lib
parent54bb28ccb080c396f7947c6bf294b67f55b8b629 (diff)
downloadspack-ca73103dac47dc2cdfff51c146205611a72bb401.tar.gz
spack-ca73103dac47dc2cdfff51c146205611a72bb401.tar.bz2
spack-ca73103dac47dc2cdfff51c146205611a72bb401.tar.xz
spack-ca73103dac47dc2cdfff51c146205611a72bb401.zip
Introduce static_to_shared_library function (#6092)
The static_to_shared_library function takes an existing static library and produces a shared library based on it.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/build_environment.py98
-rw-r--r--lib/spack/spack/test/build_environment.py99
2 files changed, 197 insertions, 0 deletions
diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py
index 0a9bd22de7..f1cf0d5049 100644
--- a/lib/spack/spack/build_environment.py
+++ b/lib/spack/spack/build_environment.py
@@ -373,6 +373,104 @@ def set_module_variables_for_package(pkg, module):
# Platform-specific library suffix.
m.dso_suffix = dso_suffix
+ def static_to_shared_library(static_lib, shared_lib=None, **kwargs):
+ compiler_path = kwargs.get('compiler', m.spack_cc)
+ compiler = Executable(compiler_path)
+
+ return _static_to_shared_library(pkg.spec.architecture, compiler,
+ static_lib, shared_lib, **kwargs)
+
+ m.static_to_shared_library = static_to_shared_library
+
+
+def _static_to_shared_library(arch, compiler, static_lib, shared_lib=None,
+ **kwargs):
+ """
+ Converts a static library to a shared library. The static library has to
+ be built with PIC for the conversion to work.
+
+ Parameters:
+ static_lib (str): Path to the static library.
+ shared_lib (str): Path to the shared library. Default is to derive
+ from the static library's path.
+
+ Keyword arguments:
+ compiler (str): Path to the compiler. Default is spack_cc.
+ compiler_output: Where to print compiler output to.
+ arguments (str list): Additional arguments for the compiler.
+ version (str): Library version. Default is unspecified.
+ compat_version (str): Library compatibility version. Default is
+ version.
+ """
+ compiler_output = kwargs.get('compiler_output', None)
+ arguments = kwargs.get('arguments', [])
+ version = kwargs.get('version', None)
+ compat_version = kwargs.get('compat_version', version)
+
+ if not shared_lib:
+ shared_lib = '{0}.{1}'.format(os.path.splitext(static_lib)[0],
+ dso_suffix)
+
+ compiler_args = []
+
+ # TODO: Compiler arguments should not be hardcoded but provided by
+ # the different compiler classes.
+ if 'linux' in arch:
+ soname = os.path.basename(shared_lib)
+
+ if compat_version:
+ soname += '.{0}'.format(compat_version)
+
+ compiler_args = [
+ '-shared',
+ '-Wl,-soname,{0}'.format(soname),
+ '-Wl,--whole-archive',
+ static_lib,
+ '-Wl,--no-whole-archive'
+ ]
+ elif 'darwin' in arch:
+ install_name = shared_lib
+
+ if compat_version:
+ install_name += '.{0}'.format(compat_version)
+
+ compiler_args = [
+ '-dynamiclib',
+ '-install_name {0}'.format(install_name),
+ '-Wl,-force_load,{0}'.format(static_lib)
+ ]
+
+ if compat_version:
+ compiler_args.append('-compatibility_version {0}'.format(
+ compat_version))
+
+ if version:
+ compiler_args.append('-current_version {0}'.format(version))
+
+ if len(arguments) > 0:
+ compiler_args.extend(arguments)
+
+ shared_lib_base = shared_lib
+
+ if version:
+ shared_lib += '.{0}'.format(version)
+ elif compat_version:
+ shared_lib += '.{0}'.format(compat_version)
+
+ compiler_args.extend(['-o', shared_lib])
+
+ # Create symlinks for version and compat_version
+ shared_lib_link = os.path.basename(shared_lib)
+
+ if version or compat_version:
+ os.symlink(shared_lib_link, shared_lib_base)
+
+ if compat_version and compat_version != version:
+ os.symlink(shared_lib_link, '{0}.{1}'.format(shared_lib_base,
+ compat_version))
+
+ return compiler(*compiler_args, output=compiler_output)
+
def get_rpath_deps(pkg):
"""Return immediate or transitive RPATHs depending on the package."""
diff --git a/lib/spack/spack/test/build_environment.py b/lib/spack/spack/test/build_environment.py
new file mode 100644
index 0000000000..37664aa35e
--- /dev/null
+++ b/lib/spack/spack/test/build_environment.py
@@ -0,0 +1,99 @@
+##############################################################################
+# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
+# Produced at the Lawrence Livermore National Laboratory.
+#
+# This file is part of Spack.
+# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
+# LLNL-CODE-647188
+#
+# For details, see https://github.com/spack/spack
+# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License (as
+# published by the Free Software Foundation) version 2.1, February 1999.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
+# conditions of the GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##############################################################################
+import os
+import pytest
+
+import spack
+from llnl.util.filesystem import join_path
+from spack.build_environment import dso_suffix, _static_to_shared_library
+from spack.util.executable import Executable
+
+
+@pytest.fixture
+def build_environment():
+ cc = Executable(join_path(spack.build_env_path, "cc"))
+ cxx = Executable(join_path(spack.build_env_path, "c++"))
+ fc = Executable(join_path(spack.build_env_path, "fc"))
+
+ realcc = "/bin/mycc"
+ prefix = "/spack-test-prefix"
+
+ os.environ['SPACK_CC'] = realcc
+ os.environ['SPACK_CXX'] = realcc
+ os.environ['SPACK_FC'] = realcc
+
+ os.environ['SPACK_PREFIX'] = prefix
+ os.environ['SPACK_ENV_PATH'] = "test"
+ os.environ['SPACK_DEBUG_LOG_DIR'] = "."
+ os.environ['SPACK_DEBUG_LOG_ID'] = "foo-hashabc"
+ os.environ['SPACK_COMPILER_SPEC'] = "gcc@4.4.7"
+ os.environ['SPACK_SHORT_SPEC'] = (
+ "foo@1.2 arch=linux-rhel6-x86_64 /hashabc")
+
+ os.environ['SPACK_CC_RPATH_ARG'] = "-Wl,-rpath,"
+ os.environ['SPACK_CXX_RPATH_ARG'] = "-Wl,-rpath,"
+ os.environ['SPACK_F77_RPATH_ARG'] = "-Wl,-rpath,"
+ os.environ['SPACK_FC_RPATH_ARG'] = "-Wl,-rpath,"
+
+ if 'SPACK_DEPENDENCIES' in os.environ:
+ del os.environ['SPACK_DEPENDENCIES']
+
+ yield {'cc': cc, 'cxx': cxx, 'fc': fc}
+
+ for name in ('SPACK_CC', 'SPACK_CXX', 'SPACK_FC', 'SPACK_PREFIX',
+ 'SPACK_ENV_PATH', 'SPACK_DEBUG_LOG_DIR',
+ 'SPACK_COMPILER_SPEC', 'SPACK_SHORT_SPEC',
+ 'SPACK_CC_RPATH_ARG', 'SPACK_CXX_RPATH_ARG',
+ 'SPACK_F77_RPATH_ARG', 'SPACK_FC_RPATH_ARG'):
+ del os.environ[name]
+
+
+def test_static_to_shared_library(build_environment):
+ os.environ['SPACK_TEST_COMMAND'] = 'dump-args'
+
+ expected = {
+ 'linux': ('/bin/mycc -Wl,-rpath,/spack-test-prefix/lib'
+ ' -Wl,-rpath,/spack-test-prefix/lib64 -shared'
+ ' -Wl,-soname,{2} -Wl,--whole-archive {0}'
+ ' -Wl,--no-whole-archive -o {1}'),
+ 'darwin': ('/bin/mycc -Wl,-rpath,/spack-test-prefix/lib'
+ ' -Wl,-rpath,/spack-test-prefix/lib64 -dynamiclib'
+ ' -install_name {1} -Wl,-force_load,{0} -o {1}')
+ }
+
+ static_lib = '/spack/libfoo.a'
+
+ for arch in ('linux', 'darwin'):
+ for shared_lib in (None, '/spack/libbar.so'):
+ output = _static_to_shared_library(arch, build_environment['cc'],
+ static_lib, shared_lib,
+ compiler_output=str).strip()
+
+ if not shared_lib:
+ shared_lib = '{0}.{1}'.format(
+ os.path.splitext(static_lib)[0], dso_suffix)
+
+ assert output == expected[arch].format(
+ static_lib, shared_lib, os.path.basename(shared_lib))