#!/bin/sh # This file is a part of Julia. License is MIT: https://julialang.org/license # Run as: fixup-libgfortran.sh [--verbose] <$private_libdir> # If we're invoked with "--verbose", create a `debug` function that prints stuff out if test $1 == "--verbose" || test $1 == "-v" { shift 1 proc debug { echo "$ifsjoin(Argv)"; } } else { proc debug { :; } } if test -z $1 { echo "Usage: $0 " exit 1 } setglobal UNAME = $[uname -s] if test $UNAME = "Linux" { setglobal SHLIB_EXT = '"so'" } elif test $UNAME = "Darwin" { setglobal SHLIB_EXT = '"dylib'" } else { echo "WARNING: Could not autodetect platform type ('uname -s' == $UNAME); assuming Linux" > !2 setglobal UNAME = '"Linux'" setglobal SHLIB_EXT = '"so'" } setglobal private_libdir = $1 if test ! -f "$private_libdir/libarpack.$SHLIB_EXT" { echo "ERROR: Could not open $private_libdir/libarpack.$SHLIB_EXT" > !2 exit 2 } proc find_shlib { setglobal lib_path = $1 if test -f $lib_path { if test $UNAME = "Linux" { ldd $lib_path | grep $2 | cut -d' ' -f3 | xargs } else { # $UNAME is "Darwin", we only have two options, see above otool -L $lib_path | grep $2 | cut -d' ' -f1 | xargs } } } proc private_libname { echo "$private_libdir/lib$1.$SHLIB_EXT" } # First, discover all the places where libgfortran/libgcc is, as well as their true SONAMES for lib in [arpack lapack] { if test -f "$private_libdir/lib$lib.$SHLIB_EXT" { # Find the paths to the libraries we're interested in. These are almost # always within the same directory, but we like to be general. setglobal LIBGFORTRAN_PATH = $[find_shlib $[private_libname $lib] libgfortran] setglobal LIBGCC_PATH = $[find_shlib $[private_libname $lib] libgcc_s] setglobal LIBQUADMATH_PATH = $[find_shlib $[private_libname $lib] libquadmath] # Take the directories, add them onto LIBGFORTRAN_DIRS, which we use to # search for these libraries in the future. setglobal LIBGFORTRAN_DIRS = ""$LIBGFORTRAN_DIRS $[dirname $LIBGFORTRAN_PATH]"" setglobal LIBGFORTRAN_DIRS = ""$LIBGFORTRAN_DIRS $[dirname $LIBGCC_PATH]"" setglobal LIBGFORTRAN_DIRS = ""$LIBGFORTRAN_DIRS $[dirname $LIBQUADMATH_PATH]"" # Save the SONAMES setglobal LIBGFORTRAN_SONAMES = ""$LIBGFORTRAN_SONAMES $[basename $LIBGFORTRAN_PATH]"" setglobal LIBGCC_SONAMES = ""$LIBGCC_SONAMES $[basename $LIBGCC_PATH]"" setglobal LIBQUADMATH_SONAMES = ""$LIBQUADMATH_SONAMES $[basename $LIBQUADMATH_PATH]"" } } # Take in a list of space-separated tokens, return a deduplicated list of the same proc uniquify { echo $1 | tr " " "\n" | sort | uniq | grep -v '^$' | tr "\n" " " } setglobal LIBGFORTRAN_DIRS = $[uniquify $LIBGFORTRAN_DIRS] setglobal SONAMES = $[uniquify "$LIBGFORTRAN_SONAMES $LIBGCC_SONAMES $LIBQUADMATH_SONAMES] debug "Discovered traces of libgfortran within $LIBGFORTRAN_DIRS" debug "Got SONAMES of $SONAMES" # Copy the SONAMEs we identified above into our private_libdir for soname in [$SONAMES] { for dir in [$LIBGFORTRAN_DIRS] { if test ! -f "$private_libdir/$soname" && test -f "$dir/$soname" { cp -v "$dir/$soname" $private_libdir chmod 755 "$private_libdir/$soname" if test $UNAME = "Darwin" { install_name_tool -id "@rpath/$soname" "$private_libdir/$soname" } } } } # On OSX, we need to change the old link (which is usually a full path) # to point to `@rpath/${soname}` explicitly, so we use `find_shlib()` # to dynamically find the full path we want to change. On Linux, we # don't care about full paths, we just set the rpath to `$ORIGIN`. proc change_linkage { # This is the path of the library we want to edit setglobal lib_path = $1 # If it doesn't exist, exit quietly if test ! -f $lib_path { debug " $lib_path doesn't exist, skipping" return } # This is the soname of the dependency we want to swap out setglobal soname = $2 if test $UNAME = "Darwin" { setglobal old_link = $[find_shlib $lib_path $soname] echo " $old_link" install_name_tool -change $old_link "@rpath/$soname" $lib_path } else { # $UNAME is "Linux", we only have two options, see above patchelf --set-rpath '$'ORIGIN $lib_path } } # For every library that remotely touches libgfortran stuff (the libraries we # have copied in ourselves as well as arpack, etc...) we must # update the linkage to point to @rpath (on OSX) or $ORIGIN (on Linux) so # that direct links to the old libgfortran directories are instead directed # to the proper location, which is our $private_libdir. for lib in [libopenblas libarpack libcholmod liblapack $SONAMES] { # Grab every incarnation of that library that exists within $private_libdir # (e.g. "libopenblas.so", and "libopenblas.so.0", etc...) for lib_path in [$private_libdir/$lib*] { # Iterate over dependency names that need to be changed for soname in [$SONAMES] { debug "changing linkage of $lib_path to $soname" change_linkage $lib_path $soname } } }