From 07edeadc326a4af1ed867f8b8cf649f18fc01df9 Mon Sep 17 00:00:00 2001 From: Alex Arslan Date: Mon, 18 Jun 2018 10:12:18 -0700 Subject: [PATCH] Fix executable and more library RPATHs on FreeBSD (#27627) First of all, we need to add libgfortran, libgcc_s, and libquadmath to `JL_PRIVATE_LIBS-0` instead of `JL_LIBS`. This ensures that they get installed into `lib/julia`, where our dependencies are supposed to live, instead of `lib`, where only libjulia should live. Now we need to call `fixup-rpath.sh` on more directories. Currently we're only calling it on `lib`, but we also need to call it on `lib/julia` and even on `bin`, because FreeBSD seems to load libraries based on the executable's RPATH rather than libjulia's RPATH. AND, speaking of the executable's RPATH, we need to make sure we have `lib/julia` in there; currently we only have `lib`. So in an isolated environment outside of the build directory, Julia won't be able to load any of its dependencies, which is bad. This is accomplished with a simple adjustment in `Make.inc`. To make sure that our dependencies can find each other properly, we need to add `RPATH_ESCAPED_ORIGIN` to `LDFLAGS` in `CONFIGURE_COMMON`. That way, every dependency that uses `configure` will get its RPATH set appropriately. --- Make.inc | 3 +++ Makefile | 34 ++++++++++++++++++++++++++-------- contrib/fixup-rpath.sh | 10 ++++++---- deps/tools/common.mk | 2 +- 4 files changed, 36 insertions(+), 13 deletions(-) diff --git a/Make.inc b/Make.inc index e8f2ec5fdfe37..730c63550c754 100644 --- a/Make.inc +++ b/Make.inc @@ -958,6 +958,9 @@ else ifeq ($(OS), Darwin) RPATH_LIB := -Wl,-rpath,'@loader_path/julia/' -Wl,-rpath,'@loader_path/' else RPATH := -Wl,-rpath,'$$ORIGIN/$(build_libdir_rel)' -Wl,-rpath-link,$(build_shlibdir) -Wl,-z,origin +ifeq ($(OS), FreeBSD) + RPATH += -Wl,-rpath,'$$ORIGIN/$(build_private_libdir_rel)' +endif RPATH_ORIGIN := -Wl,-rpath,'$$ORIGIN' -Wl,-z,origin RPATH_ESCAPED_ORIGIN := -Wl,-rpath,'\$$\$$ORIGIN' -Wl,-z,origin RPATH_LIB := -Wl,-rpath,'$$ORIGIN/julia' -Wl,-rpath,'$$ORIGIN' -Wl,-z,origin diff --git a/Makefile b/Makefile index 33079548ad3a5..bf9b14a57803d 100644 --- a/Makefile +++ b/Makefile @@ -248,17 +248,22 @@ endif endif endif +# On FreeBSD, /lib/libgcc_s.so.1 is incompatible with Fortran; to use Fortran on FreeBSD, +# we need to link to the libgcc_s that ships with the same GCC version used by libgfortran. +# To work around this, we copy the GCC libraries we need, namely libgfortran, libgcc_s, +# and libquadmath, into our build library directory, $(build_libdir). We also add them to +# JL_PRIVATE_LIBS-0 so that they know where they need to live at install time. ifeq ($(OS),FreeBSD) define std_so -julia-deps: | $$(build_libdir)/lib$(1).so -$$(build_libdir)/lib$(1).so: | $$(build_libdir) - $$(INSTALL_M) $$(GCCPATH)/lib$(1).so* $$(build_libdir) -JL_LIBS += $(1) +julia-deps: | $$(build_libdir)/$(1).so +$$(build_libdir)/$(1).so: | $$(build_libdir) + $$(INSTALL_M) $$(GCCPATH)/$(1).so* $$(build_libdir) +JL_PRIVATE_LIBS-0 += $(1) endef -$(eval $(call std_so,gfortran)) -$(eval $(call std_so,gcc_s)) -$(eval $(call std_so,quadmath)) +$(eval $(call std_so,libgfortran)) +$(eval $(call std_so,libgcc_s)) +$(eval $(call std_so,libquadmath)) endif # FreeBSD ifeq ($(OS),WINNT) @@ -381,6 +386,15 @@ endif # On FreeBSD, remove the build's libdir from each library's RPATH ifeq ($(OS),FreeBSD) $(JULIAHOME)/contrib/fixup-rpath.sh $(build_depsbindir)/patchelf $(DESTDIR)$(libdir) $(build_libdir) + $(JULIAHOME)/contrib/fixup-rpath.sh $(build_depsbindir)/patchelf $(DESTDIR)$(private_libdir) $(build_libdir) + $(JULIAHOME)/contrib/fixup-rpath.sh $(build_depsbindir)/patchelf $(DESTDIR)$(bindir) $(build_libdir) + # Set libgfortran's RPATH to ORIGIN instead of GCCPATH. It's only libgfortran that + # needs to be fixed here, as libgcc_s and libquadmath don't have RPATHs set. If we + # don't set libgfortran's RPATH, it won't be able to find its friends on systems + # that don't have the exact GCC port installed used for the build. + for lib in $(DESTDIR)$(private_libdir)/libgfortran*$(SHLIB_EXT)*; do \ + $(build_depsbindir)/patchelf --set-rpath '$$ORIGIN' $$lib; \ + done endif mkdir -p $(DESTDIR)$(sysconfdir) @@ -409,7 +423,11 @@ ifneq ($(DESTDIR),) endif @$(MAKE) -C $(BUILDROOT) -f $(JULIAHOME)/Makefile install cp $(JULIAHOME)/LICENSE.md $(BUILDROOT)/julia-$(JULIA_COMMIT) -ifneq ($(OS), WINNT) + # Run fixup-libgfortran on all platforms but Windows and FreeBSD. On FreeBSD we + # pull in the GCC libraries earlier and use them for the build to make sure we + # don't inadvertently link to /lib/libgcc_s.so.1, which is incompatible with + # libgfortran. +ifeq (,$(findstring $(OS),FreeBSD WINNT)) -$(CUSTOM_LD_LIBRARY_PATH) PATH=$(PATH):$(build_depsbindir) $(JULIAHOME)/contrib/fixup-libgfortran.sh $(DESTDIR)$(private_libdir) endif ifeq ($(OS), Linux) diff --git a/contrib/fixup-rpath.sh b/contrib/fixup-rpath.sh index 342cf42e9a73c..10e0790724667 100755 --- a/contrib/fixup-rpath.sh +++ b/contrib/fixup-rpath.sh @@ -1,17 +1,17 @@ #!/bin/sh -# Usage: fixup-rpath.sh +# Usage: fixup-rpath.sh if [ $# -ne 3 ]; then echo "Incorrect number of arguments: Expected 3, got $#" - echo "Usage: fixup-rpath.sh " + echo "Usage: fixup-rpath.sh " exit 1 fi patchelf="$1" -install_libdir="$2" +executable_dir="$2" build_libdir="$3" -for lib in ${install_libdir}/*.so*; do +for lib in $(find ${executable_dir} -type f -perm -111); do # First get the current RPATH rpath="$(${patchelf} --print-rpath ${lib})" @@ -25,6 +25,8 @@ for lib in ${install_libdir}/*.so*; do # Drop the trailing : new_rpath="${new_rpath%?}" + echo " Setting RPATH for ${lib} to '${new_rpath}'" + # Now set the new RPATH ${patchelf} --set-rpath "${new_rpath}" ${lib} done diff --git a/deps/tools/common.mk b/deps/tools/common.mk index dadfce9df7ff2..a2d019d8c1e3e 100644 --- a/deps/tools/common.mk +++ b/deps/tools/common.mk @@ -13,7 +13,7 @@ ifneq ($(USEMSVC), 1) CONFIGURE_COMMON += LDFLAGS="$(LDFLAGS) -Wl,--stack,8388608" endif else -CONFIGURE_COMMON += LDFLAGS="$(LDFLAGS)" +CONFIGURE_COMMON += LDFLAGS="$(LDFLAGS) $(RPATH_ESCAPED_ORIGIN)" endif CONFIGURE_COMMON += F77="$(FC)" CC="$(CC)" CXX="$(CXX)" LD="$(LD)"