Merge pull request #658 from davydden/metis_parmetis_darwin

metis/parmetis/oce/boost: correct install_name on Darwin via a global tool
This commit is contained in:
Todd Gamblin 2016-03-27 16:10:05 -07:00
commit 8b45d6f84f
6 changed files with 76 additions and 27 deletions

View file

@ -27,9 +27,10 @@
'force_remove', 'join_path', 'ancestor', 'can_access', 'filter_file', 'force_remove', 'join_path', 'ancestor', 'can_access', 'filter_file',
'FileFilter', 'change_sed_delimiter', 'is_exe', 'force_symlink', 'FileFilter', 'change_sed_delimiter', 'is_exe', 'force_symlink',
'set_executable', 'copy_mode', 'unset_executable_mode', 'set_executable', 'copy_mode', 'unset_executable_mode',
'remove_dead_links', 'remove_linked_tree'] 'remove_dead_links', 'remove_linked_tree', 'fix_darwin_install_name']
import os import os
import glob
import sys import sys
import re import re
import shutil import shutil
@ -38,6 +39,7 @@
import getpass import getpass
from contextlib import contextmanager, closing from contextlib import contextmanager, closing
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
import subprocess
import llnl.util.tty as tty import llnl.util.tty as tty
from spack.util.compression import ALLOWED_ARCHIVE_TYPES from spack.util.compression import ALLOWED_ARCHIVE_TYPES
@ -392,3 +394,29 @@ def remove_linked_tree(path):
os.unlink(path) os.unlink(path)
else: else:
shutil.rmtree(path, True) shutil.rmtree(path, True)
def fix_darwin_install_name(path):
"""
Fix install name of dynamic libraries on Darwin to have full path.
There are two parts of this task:
(i) use install_name('-id',...) to change install name of a single lib;
(ii) use install_name('-change',...) to change the cross linking between libs.
The function assumes that all libraries are in one folder and currently won't
follow subfolders.
Args:
path: directory in which .dylib files are alocated
"""
libs = glob.glob(join_path(path,"*.dylib"))
for lib in libs:
# fix install name first:
subprocess.Popen(["install_name_tool", "-id",lib,lib], stdout=subprocess.PIPE).communicate()[0]
long_deps = subprocess.Popen(["otool", "-L",lib], stdout=subprocess.PIPE).communicate()[0].split('\n')
deps = [dep.partition(' ')[0][1::] for dep in long_deps[2:-1]]
# fix all dependencies:
for dep in deps:
for loc in libs:
if dep == os.path.basename(loc):
subprocess.Popen(["install_name_tool", "-change",dep,loc,lib], stdout=subprocess.PIPE).communicate()[0]
break

View file

@ -1,5 +1,6 @@
from spack import * from spack import *
import spack import spack
import sys
class Boost(Package): class Boost(Package):
"""Boost provides free peer-reviewed portable C++ source """Boost provides free peer-reviewed portable C++ source
@ -45,34 +46,34 @@ class Boost(Package):
version('1.34.1', '2d938467e8a448a2c9763e0a9f8ca7e5') version('1.34.1', '2d938467e8a448a2c9763e0a9f8ca7e5')
version('1.34.0', 'ed5b9291ffad776f8757a916e1726ad0') version('1.34.0', 'ed5b9291ffad776f8757a916e1726ad0')
default_install_libs = set(['atomic', default_install_libs = set(['atomic',
'chrono', 'chrono',
'date_time', 'date_time',
'filesystem', 'filesystem',
'graph', 'graph',
'iostreams', 'iostreams',
'locale', 'locale',
'log', 'log',
'math', 'math',
'program_options', 'program_options',
'random', 'random',
'regex', 'regex',
'serialization', 'serialization',
'signals', 'signals',
'system', 'system',
'test', 'test',
'thread', 'thread',
'wave']) 'wave'])
# mpi/python are not installed by default because they pull in many # mpi/python are not installed by default because they pull in many
# dependencies and/or because there is a great deal of customization # dependencies and/or because there is a great deal of customization
# possible (and it would be difficult to choose sensible defaults) # possible (and it would be difficult to choose sensible defaults)
default_noinstall_libs = set(['mpi', 'python']) default_noinstall_libs = set(['mpi', 'python'])
all_libs = default_install_libs | default_noinstall_libs all_libs = default_install_libs | default_noinstall_libs
for lib in all_libs: for lib in all_libs:
variant(lib, default=(lib not in default_noinstall_libs), variant(lib, default=(lib not in default_noinstall_libs),
description="Compile with {0} library".format(lib)) description="Compile with {0} library".format(lib))
variant('debug', default=False, description='Switch to the debug version of Boost') variant('debug', default=False, description='Switch to the debug version of Boost')
@ -124,9 +125,9 @@ def determine_bootstrap_options(self, spec, withLibs, options):
with open('user-config.jam', 'w') as f: with open('user-config.jam', 'w') as f:
compiler_wrapper = join_path(spack.build_env_path, 'c++') compiler_wrapper = join_path(spack.build_env_path, 'c++')
f.write("using {0} : : {1} ;\n".format(boostToolsetId, f.write("using {0} : : {1} ;\n".format(boostToolsetId,
compiler_wrapper)) compiler_wrapper))
if '+mpi' in spec: if '+mpi' in spec:
f.write('using mpi : %s ;\n' % f.write('using mpi : %s ;\n' %
join_path(spec['mpi'].prefix.bin, 'mpicxx')) join_path(spec['mpi'].prefix.bin, 'mpicxx'))
@ -155,7 +156,7 @@ def determine_b2_options(self, spec, options):
linkTypes = ['static'] linkTypes = ['static']
if '+shared' in spec: if '+shared' in spec:
linkTypes.append('shared') linkTypes.append('shared')
threadingOpts = [] threadingOpts = []
if '+multithreaded' in spec: if '+multithreaded' in spec:
threadingOpts.append('multi') threadingOpts.append('multi')
@ -163,12 +164,12 @@ def determine_b2_options(self, spec, options):
threadingOpts.append('single') threadingOpts.append('single')
if not threadingOpts: if not threadingOpts:
raise RuntimeError("At least one of {singlethreaded, multithreaded} must be enabled") raise RuntimeError("At least one of {singlethreaded, multithreaded} must be enabled")
options.extend([ options.extend([
'toolset=%s' % self.determine_toolset(spec), 'toolset=%s' % self.determine_toolset(spec),
'link=%s' % ','.join(linkTypes), 'link=%s' % ','.join(linkTypes),
'--layout=tagged']) '--layout=tagged'])
return threadingOpts return threadingOpts
def install(self, spec, prefix): def install(self, spec, prefix):
@ -177,14 +178,14 @@ def install(self, spec, prefix):
if "+{0}".format(lib) in spec: if "+{0}".format(lib) in spec:
withLibs.append(lib) withLibs.append(lib)
if not withLibs: if not withLibs:
# if no libraries are specified for compilation, then you dont have # if no libraries are specified for compilation, then you dont have
# to configure/build anything, just copy over to the prefix directory. # to configure/build anything, just copy over to the prefix directory.
src = join_path(self.stage.source_path, 'boost') src = join_path(self.stage.source_path, 'boost')
mkdirp(join_path(prefix, 'include')) mkdirp(join_path(prefix, 'include'))
dst = join_path(prefix, 'include', 'boost') dst = join_path(prefix, 'include', 'boost')
install_tree(src, dst) install_tree(src, dst)
return return
# to make Boost find the user-config.jam # to make Boost find the user-config.jam
env['BOOST_BUILD_PATH'] = './' env['BOOST_BUILD_PATH'] = './'
@ -207,4 +208,7 @@ def install(self, spec, prefix):
# Boost.MPI if the threading options are not separated. # Boost.MPI if the threading options are not separated.
for threadingOpt in threadingOpts: for threadingOpt in threadingOpts:
b2('install', 'threading=%s' % threadingOpt, *b2_options) b2('install', 'threading=%s' % threadingOpt, *b2_options)
# The shared libraries are not installed correctly on Darwin; correct this
if (sys.platform == 'darwin') and ('+shared' in spec):
fix_darwin_install_name(prefix.lib)

View file

@ -24,7 +24,7 @@
############################################################################## ##############################################################################
from spack import * from spack import *
import glob import glob,sys
class Metis(Package): class Metis(Package):
""" """
@ -90,3 +90,7 @@ def install(self, spec, prefix):
fs = glob.glob(join_path(source_directory,'GKlib',"*.h")) fs = glob.glob(join_path(source_directory,'GKlib',"*.h"))
for f in fs: for f in fs:
install(f, GKlib_dist) install(f, GKlib_dist)
# The shared library is not installed correctly on Darwin; correct this
if (sys.platform == 'darwin') and ('+shared' in spec):
fix_darwin_install_name(prefix.lib)

View file

@ -41,6 +41,11 @@ def install(self, spec, prefix):
make() make()
make("install") make("install")
# The shared libraries are not installed correctly on Darwin; correct this
if (sys.platform == 'darwin') and ('+shared' in spec):
fix_darwin_install_name(prefix.lib)
def setup_dependent_package(self, module, dependent_spec): def setup_dependent_package(self, module, dependent_spec):
spec = self.spec spec = self.spec
lib_dsuffix = '.dylib' if sys.platform == 'darwin' else '.so' lib_dsuffix = '.dylib' if sys.platform == 'darwin' else '.so'

View file

@ -1,5 +1,5 @@
from spack import * from spack import *
import platform import platform, sys
class Oce(Package): class Oce(Package):
""" """
@ -45,3 +45,7 @@ def install(self, spec, prefix):
cmake('.', *options) cmake('.', *options)
make("install/strip") make("install/strip")
# The shared libraries are not installed correctly on Darwin; correct this
if (sys.platform == 'darwin'):
fix_darwin_install_name(prefix.lib)

View file

@ -24,7 +24,7 @@
############################################################################## ##############################################################################
from spack import * from spack import *
import sys
class Parmetis(Package): class Parmetis(Package):
""" """
@ -83,3 +83,7 @@ def install(self, spec, prefix):
cmake(source_directory, *options) cmake(source_directory, *options)
make() make()
make("install") make("install")
# The shared library is not installed correctly on Darwin; correct this
if (sys.platform == 'darwin') and ('+shared' in spec):
fix_darwin_install_name(prefix.lib)