Skip to content
Snippets Groups Projects
Commit 0200d8d3 authored by Mick Jordan's avatar Mick Jordan
Browse files

more complete handling of rpath'ed libraries

parent 65d50ff9
No related branches found
No related tags found
No related merge requests found
...@@ -49,9 +49,12 @@ all: $(R_LIB) $(BOOTJNI_LIB) ...@@ -49,9 +49,12 @@ all: $(R_LIB) $(BOOTJNI_LIB)
$(R_LIB): objs $(R_LIB): objs
ifeq ($(OS_NAME),Darwin) ifeq ($(OS_NAME),Darwin)
$(DYLIB_LD) $(DYLIB_LDFLAGS) -Wl,-rpath,$(FASTR_LIB_DIR) -o $(R_LIB) $(wildcard lib/*.o) -L$(FASTR_LIB_DIR) -lRblas -lRlapack -lpcre -lz $(VERSION_FLAGS) $(DYLIB_LD) $(DYLIB_LDFLAGS) -Wl,-rpath,@loader_path/ -o $(R_LIB) $(wildcard lib/*.o) -L$(FASTR_LIB_DIR) -lRblas -lRlapack -lpcre -lz $(VERSION_FLAGS)
install_name_tool -change libRblas.dylib @rpath/libRblas.dylib $(R_LIB) install_name_tool -change libRblas.dylib @rpath/libRblas.dylib $(R_LIB)
install_name_tool -change libRlapack.dylib @rpath/libRlapack.dylib $(R_LIB) install_name_tool -change libRlapack.dylib @rpath/libRlapack.dylib $(R_LIB)
install_name_tool -id @rpath/libR.dylib $(R_LIB)
# check if we captured libpcre/libz, rpath those in libR
mx rupdatelib $(FASTR_LIB_DIR)
else else
$(DYLIB_LD) $(DYLIB_LDFLAGS) -Wl,-rpath,$(FASTR_LIB_DIR) -o $(R_LIB) $(wildcard lib/*.o) -L$(FASTR_LIB_DIR) -lRblas -lRlapack -lpcre -lz $(DYLIB_LD) $(DYLIB_LDFLAGS) -Wl,-rpath,$(FASTR_LIB_DIR) -o $(R_LIB) $(wildcard lib/*.o) -L$(FASTR_LIB_DIR) -lRblas -lRlapack -lpcre -lz
endif endif
...@@ -62,6 +65,9 @@ objs: ...@@ -62,6 +65,9 @@ objs:
$(BOOTJNI_LIB): bootobjs $(BOOTJNI_LIB): bootobjs
$(DYLIB_LD) $(DYLIB_LDFLAGS) -o $(BOOTJNI_LIB) src/jniboot/jniboot.o $(VERSION_FLAGS) $(DYLIB_LD) $(DYLIB_LDFLAGS) -o $(BOOTJNI_LIB) src/jniboot/jniboot.o $(VERSION_FLAGS)
ifeq ($(OS_NAME),Darwin)
install_name_tool -id @rpath/libjniboot.dylib $(BOOTJNI_LIB)
endif
bootobjs: bootobjs:
$(MAKE) -C src/jniboot all $(MAKE) -C src/jniboot all
...@@ -70,4 +76,5 @@ clean: ...@@ -70,4 +76,5 @@ clean:
$(MAKE) -C src/common clean $(MAKE) -C src/common clean
$(MAKE) -C src/jni clean $(MAKE) -C src/jni clean
rm -rf $(R_LIB) rm -rf $(R_LIB)
rm -rf $(BOOTJNI_LIB)
...@@ -33,14 +33,14 @@ endif ...@@ -33,14 +33,14 @@ endif
BLAS_TARGET := $(FASTR_LIB_DIR)/libRblas$(DYLIB_EXT) BLAS_TARGET := $(FASTR_LIB_DIR)/libRblas$(DYLIB_EXT)
LAPACK_TARGET := $(FASTR_LIB_DIR)/libRlapack$(DYLIB_EXT) LAPACK_TARGET := $(FASTR_LIB_DIR)/libRlapack$(DYLIB_EXT)
# at a minimum we need to know where libpcre/libz are located, # at a minimum we need to know where libpcre/libz/libgfortran/libquadmath are located,
# to keep the Java side simpler, we (may) copy them to $(FASTR_LIB_DIR) # to keep the Java side simpler, we (may) copy them to $(FASTR_LIB_DIR) unless
# unless they are found in system dirs # they were found in the standard system locations
#PCRE_TARGET := $(FASTR_LIB_DIR)/libpcre$(DYLIB_EXT) OTHER_LIB_TARGETS = pcre z gfortran quadmath gcc_s
#Z_TARGET := $(FASTR_LIB_DIR)/libz$(DYLIB_EXT)
.PHONY: all pcre_target z_target
all: $(FASTR_LIB_DIR) $(BLAS_TARGET) $(LAPACK_TARGET) pcre_target z_target .PHONY: all other_lib_targets
all: $(FASTR_LIB_DIR) $(BLAS_TARGET) $(LAPACK_TARGET) other_lib_targets
$(FASTR_LIB_DIR): $(FASTR_LIB_DIR):
mkdir -p $(FASTR_LIB_DIR) mkdir -p $(FASTR_LIB_DIR)
...@@ -53,20 +53,19 @@ $(LAPACK_TARGET): $(GNUR_HOME)/lib/libRlapack$(DYLIB_EXT) ...@@ -53,20 +53,19 @@ $(LAPACK_TARGET): $(GNUR_HOME)/lib/libRlapack$(DYLIB_EXT)
ifeq ($(OS_NAME),Darwin) ifeq ($(OS_NAME),Darwin)
# libRblas depends on libgfortran, libquadmath # libRblas depends on libgfortran, libquadmath
# libRlapack depends on libgfortran, libquadmath, libRblas, libR # libRlapack depends on libgfortran, libquadmath, libRblas, libR
# use @loader_path to make references relocatable # use @rpath to make references relocatable
install_name_tool -change libRblas.dylib @rpath/libRblas.dylib $(LAPACK_TARGET) install_name_tool -change libRblas.dylib @rpath/libRblas.dylib $(LAPACK_TARGET)
install_name_tool -change libR.dylib @rpath/libR.dylib $(LAPACK_TARGET) install_name_tool -change libR.dylib @rpath/libR.dylib $(LAPACK_TARGET)
install_name_tool -id @rpath/libRblas.dylib $(BLAS_TARGET) install_name_tool -id @rpath/libRblas.dylib $(BLAS_TARGET)
install_name_tool -id @rpath/libRlapack.dylib $(LAPACK_TARGET) install_name_tool -id @rpath/libRlapack.dylib $(LAPACK_TARGET)
endif endif
pcre_target: other_lib_targets:
mx rcopylib pcre $(FASTR_LIB_DIR) for target in $(OTHER_LIB_TARGETS); do \
mx rcopylib $$target $(FASTR_LIB_DIR) || exit 1; \
z_target: done
mx rcopylib z $(FASTR_LIB_DIR)
clean: clean:
rm -f $(BLAS_TARGET) $(LAPACK_TARGET) $(PCRE_TARGET) $(Z_TARGET) rm -f $(BLAS_TARGET) $(LAPACK_TARGET)
rm -f $(foreach target,$(OTHER_LIB_TARGETS),$(wildcard $(FASTR_LIB_DIR)/lib$(target).*))
...@@ -26,6 +26,21 @@ import subprocess ...@@ -26,6 +26,21 @@ import subprocess
import shutil import shutil
import mx import mx
def _darwin_extract_realpath(lib, libpath):
'''
If libpath has a dependency on lib, return the path in the library, else None
'''
try:
output = subprocess.check_output(['otool', '-L', libpath])
lines = output.split('\n')
for line in lines[1:]:
if lib in line:
parts = line.split(' ')
return parts[0].strip()
return None
except subprocess.CalledProcessError:
mx.abort('copylib: otool failed')
def _copylib(lib, libpath, target): def _copylib(lib, libpath, target):
''' '''
Just copying libxxx.so/dylib isn't sufficient as versioning is involved. Just copying libxxx.so/dylib isn't sufficient as versioning is involved.
...@@ -34,15 +49,7 @@ def _copylib(lib, libpath, target): ...@@ -34,15 +49,7 @@ def _copylib(lib, libpath, target):
Unfortunately getting that info is is OS specific. Unfortunately getting that info is is OS specific.
''' '''
if platform.system() == 'Darwin': if platform.system() == 'Darwin':
try: real_libpath = _darwin_extract_realpath(lib, libpath)
output = subprocess.check_output(['otool', '-L', libpath])
lines = output.split('\n')
for line in lines[1:]:
if lib in line:
parts = line.split(' ')
real_libpath = parts[0].strip()
except subprocess.CalledProcessError:
mx.abort('copylib: otool failed')
else: else:
try: try:
output = subprocess.check_output(['objdump', '-p', libpath]) output = subprocess.check_output(['objdump', '-p', libpath])
...@@ -55,10 +62,20 @@ def _copylib(lib, libpath, target): ...@@ -55,10 +62,20 @@ def _copylib(lib, libpath, target):
mx.abort('copylib: otool failed') mx.abort('copylib: otool failed')
# copy both files # copy both files
shutil.copy(real_libpath, target) shutil.copy(real_libpath, target)
libpath_base = os.path.basename(libpath)
os.chdir(target) os.chdir(target)
if os.path.exists(os.path.basename(libpath)): if libpath != real_libpath:
os.remove(os.path.basename(libpath)) # create a symlink
os.symlink(os.path.basename(real_libpath), os.path.basename(libpath)) if os.path.exists(libpath_base):
os.remove(libpath_base)
os.symlink(os.path.basename(real_libpath), libpath_base)
# On Darwin we change the id to use @rpath
if platform.system() == 'Darwin':
try:
subprocess.check_call(['install_name_tool', '-id', '@rpath/' + libpath_base, libpath_base])
except subprocess.CalledProcessError:
mx.abort('copylib: install_name_tool failed')
# TODO @rpath references within the library?
mx.log('copied ' + lib + ' library from ' + libpath + ' to ' + target) mx.log('copied ' + lib + ' library from ' + libpath + ' to ' + target)
def copylib(args): def copylib(args):
...@@ -80,14 +97,55 @@ def copylib(args): ...@@ -80,14 +97,55 @@ def copylib(args):
if os.environ.has_key('PKG_LDFLAGS_OVERRIDE'): if os.environ.has_key('PKG_LDFLAGS_OVERRIDE'):
parts = os.environ['PKG_LDFLAGS_OVERRIDE'].split(' ') parts = os.environ['PKG_LDFLAGS_OVERRIDE'].split(' ')
ext = '.dylib' if platform.system() == 'Darwin' else '.so' ext = '.dylib' if platform.system() == 'Darwin' else '.so'
name = 'lib' + args[0] + ext lib_prefix = 'lib' + args[0]
plain_libpath = lib_prefix + ext
for part in parts: for part in parts:
path = part.strip('"').lstrip('-L') path = part.strip('"').lstrip('-L')
for f in os.listdir(path): for f in os.listdir(path):
if name == f: if f.startswith(lib_prefix):
if os.path.exists(os.path.join(path, plain_libpath)):
f = plain_libpath
target_dir = args[1] target_dir = args[1]
if not os.path.exists(os.path.join(target_dir, name)): if not os.path.exists(os.path.join(target_dir, f)):
_copylib(args[0], os.path.join(path, f), args[1]) _copylib(args[0], os.path.join(path, f), args[1])
return 0 return 0
mx.log(args[0] + ' not found in PKG_LDFLAGS_OVERRIDE, assuming system location') mx.log(args[0] + ' not found in PKG_LDFLAGS_OVERRIDE, assuming system location')
def updatelib(args):
'''
If we captured a library then, on Darwin, we patch up the references
in the target library passed as argument to use @rpath.
args:
0 directory containing library
'''
ignore_list = ['R', 'Rblas', 'Rlapack', 'jniboot']
def ignorelib(name):
for ignore in ignore_list:
x = 'lib' + ignore + '.dylib'
if x == name:
return True
return False
libdir = args[0]
cap_libs = []
libs = []
for lib in os.listdir(libdir):
if not os.path.islink(os.path.join(libdir, lib)):
libs.append(lib)
if ignorelib(lib) or os.path.islink(os.path.join(libdir, lib)):
continue
cap_libs.append(lib)
# for each of the libs, check whether they depend
# on any of the captured libs, @rpath the dependency if so
for lib in libs:
targetlib = os.path.join(libdir, lib)
for cap_lib in cap_libs:
try:
real_libpath = _darwin_extract_realpath(cap_lib, targetlib)
if real_libpath and not '@rpath' in real_libpath:
cmd = ['install_name_tool', '-change', real_libpath, '@rpath/' + cap_lib, targetlib]
subprocess.check_call(cmd)
except subprocess.CalledProcessError:
mx.abort('update: install_name_tool failed')
...@@ -545,6 +545,7 @@ _commands = { ...@@ -545,6 +545,7 @@ _commands = {
'installpkgs' : [mx_fastr_pkgs.installpkgs, '[options]'], 'installpkgs' : [mx_fastr_pkgs.installpkgs, '[options]'],
'mkgramrd': [mx_fastr_mkgramrd.mkgramrd, '[options]'], 'mkgramrd': [mx_fastr_mkgramrd.mkgramrd, '[options]'],
'rcopylib' : [mx_copylib.copylib, '[]'], 'rcopylib' : [mx_copylib.copylib, '[]'],
'rupdatelib' : [mx_copylib.updatelib, '[]'],
} }
mx.update_commands(_fastr_suite, _commands) mx.update_commands(_fastr_suite, _commands)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment