Skip to content

Commit

Permalink
Introduce static_to_shared_library function
Browse files Browse the repository at this point in the history
The static_to_shared_library function takes an existing static library
and produces a shared library based on it.
  • Loading branch information
michaelkuhn committed Nov 6, 2017
1 parent 31c5467 commit 88bd0a7
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 73 deletions.
98 changes: 98 additions & 0 deletions lib/spack/spack/build_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down
99 changes: 99 additions & 0 deletions lib/spack/spack/test/build_environment.py
Original file line number Diff line number Diff line change
@@ -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))
64 changes: 0 additions & 64 deletions var/spack/repos/builtin/packages/lua/liblua-shared.patch

This file was deleted.

13 changes: 4 additions & 9 deletions var/spack/repos/builtin/packages/lua/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,6 @@ class Lua(Package):
destination="luarocks",
placement='luarocks')

# Based on patches from Arch Linux and Homebrew:
# https://git.archlinux.org/svntogit/packages.git/tree/trunk/liblua.so.patch?h=packages/lua
# https://github.com/Homebrew/homebrew-core/blob/master/Formula/lua.rb
patch('liblua-shared.patch')

def install(self, spec, prefix):
if spec.satisfies("platform=darwin"):
target = 'macosx'
Expand All @@ -76,8 +71,6 @@ def install(self, spec, prefix):
spec['ncurses'].prefix.lib),
'MYLIBS=-lncursesw',
'CC=%s -std=gnu99' % spack_cc,
'LUA_DSO=liblua.%s' % (
dso_suffix),
target)
make('INSTALL_TOP=%s' % prefix,
'MYCFLAGS=%s' % (
Expand All @@ -87,10 +80,12 @@ def install(self, spec, prefix):
spec['ncurses'].prefix.lib),
'MYLIBS=-lncursesw',
'CC=%s -std=gnu99' % spack_cc,
'LUA_DSO=liblua.%s' % (
dso_suffix),
'install')

static_to_shared_library(join_path(prefix.lib, 'liblua.a'),
arguments=['-lm'], version=self.version,
compat_version=self.version.up_to(2))

with working_dir(os.path.join('luarocks', 'luarocks')):
configure('--prefix=' + prefix, '--with-lua=' + prefix)
make('build')
Expand Down

0 comments on commit 88bd0a7

Please sign in to comment.