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)
$(R_LIB): objs
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 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
$(DYLIB_LD) $(DYLIB_LDFLAGS) -Wl,-rpath,$(FASTR_LIB_DIR) -o $(R_LIB) $(wildcard lib/*.o) -L$(FASTR_LIB_DIR) -lRblas -lRlapack -lpcre -lz
endif
......@@ -62,6 +65,9 @@ objs:
$(BOOTJNI_LIB): bootobjs
$(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:
$(MAKE) -C src/jniboot all
......@@ -70,4 +76,5 @@ clean:
$(MAKE) -C src/common clean
$(MAKE) -C src/jni clean
rm -rf $(R_LIB)
rm -rf $(BOOTJNI_LIB)
......@@ -33,14 +33,14 @@ endif
BLAS_TARGET := $(FASTR_LIB_DIR)/libRblas$(DYLIB_EXT)
LAPACK_TARGET := $(FASTR_LIB_DIR)/libRlapack$(DYLIB_EXT)
# at a minimum we need to know where libpcre/libz are located,
# to keep the Java side simpler, we (may) copy them to $(FASTR_LIB_DIR)
# unless they are found in system dirs
#PCRE_TARGET := $(FASTR_LIB_DIR)/libpcre$(DYLIB_EXT)
#Z_TARGET := $(FASTR_LIB_DIR)/libz$(DYLIB_EXT)
.PHONY: all pcre_target z_target
# 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) unless
# they were found in the standard system locations
OTHER_LIB_TARGETS = pcre z gfortran quadmath gcc_s
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):
mkdir -p $(FASTR_LIB_DIR)
......@@ -53,20 +53,19 @@ $(LAPACK_TARGET): $(GNUR_HOME)/lib/libRlapack$(DYLIB_EXT)
ifeq ($(OS_NAME),Darwin)
# libRblas depends on libgfortran, libquadmath
# 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 libR.dylib @rpath/libR.dylib $(LAPACK_TARGET)
install_name_tool -id @rpath/libRblas.dylib $(BLAS_TARGET)
install_name_tool -id @rpath/libRlapack.dylib $(LAPACK_TARGET)
endif
pcre_target:
mx rcopylib pcre $(FASTR_LIB_DIR)
z_target:
mx rcopylib z $(FASTR_LIB_DIR)
other_lib_targets:
for target in $(OTHER_LIB_TARGETS); do \
mx rcopylib $$target $(FASTR_LIB_DIR) || exit 1; \
done
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
import shutil
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):
'''
Just copying libxxx.so/dylib isn't sufficient as versioning is involved.
......@@ -34,15 +49,7 @@ def _copylib(lib, libpath, target):
Unfortunately getting that info is is OS specific.
'''
if platform.system() == 'Darwin':
try:
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')
real_libpath = _darwin_extract_realpath(lib, libpath)
else:
try:
output = subprocess.check_output(['objdump', '-p', libpath])
......@@ -55,10 +62,20 @@ def _copylib(lib, libpath, target):
mx.abort('copylib: otool failed')
# copy both files
shutil.copy(real_libpath, target)
libpath_base = os.path.basename(libpath)
os.chdir(target)
if os.path.exists(os.path.basename(libpath)):
os.remove(os.path.basename(libpath))
os.symlink(os.path.basename(real_libpath), os.path.basename(libpath))
if libpath != real_libpath:
# create a symlink
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)
def copylib(args):
......@@ -80,14 +97,55 @@ def copylib(args):
if os.environ.has_key('PKG_LDFLAGS_OVERRIDE'):
parts = os.environ['PKG_LDFLAGS_OVERRIDE'].split(' ')
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:
path = part.strip('"').lstrip('-L')
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]
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])
return 0
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 = {
'installpkgs' : [mx_fastr_pkgs.installpkgs, '[options]'],
'mkgramrd': [mx_fastr_mkgramrd.mkgramrd, '[options]'],
'rcopylib' : [mx_copylib.copylib, '[]'],
'rupdatelib' : [mx_copylib.updatelib, '[]'],
}
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