#!/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 } global UNAME := $[uname -s] if test $UNAME = "Linux" { global SHLIB_EXT := '"so'" } elif test $UNAME = "Darwin" { global SHLIB_EXT := '"dylib'" } else { echo "WARNING: Could not autodetect platform type ('uname -s' == $UNAME); assuming Linux" > !2 global UNAME := '"Linux'" global SHLIB_EXT := '"so'" } global 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 { global 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. global LIBGFORTRAN_PATH := $[find_shlib $[private_libname $lib] libgfortran] global LIBGCC_PATH := $[find_shlib $[private_libname $lib] libgcc_s] global 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. global LIBGFORTRAN_DIRS := ""$LIBGFORTRAN_DIRS $[dirname $LIBGFORTRAN_PATH]"" global LIBGFORTRAN_DIRS := ""$LIBGFORTRAN_DIRS $[dirname $LIBGCC_PATH]"" global LIBGFORTRAN_DIRS := ""$LIBGFORTRAN_DIRS $[dirname $LIBQUADMATH_PATH]"" # Save the SONAMES global LIBGFORTRAN_SONAMES := ""$LIBGFORTRAN_SONAMES $[basename $LIBGFORTRAN_PATH]"" global LIBGCC_SONAMES := ""$LIBGCC_SONAMES $[basename $LIBGCC_PATH]"" global 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" " " } global LIBGFORTRAN_DIRS := $[uniquify $LIBGFORTRAN_DIRS] global 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 global 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 global soname := $2 if test $UNAME = "Darwin" { global 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 } } } (CommandList children: [ (If arms: [ (if_arm cond: [ (Sentence child: (AndOr children: [ (C {(Lit_Other "[")} {(DQ ($ VSub_Number "$1"))} {(Lit_Other "=") (Lit_Other "=")} {(DQ (--verbose))} {(Lit_Other "]")} ) (C {(Lit_Other "[")} {(DQ ($ VSub_Number "$1"))} {(Lit_Other "=") (Lit_Other "=")} {(DQ (-v))} {(Lit_Other "]")} ) ] op_id: Op_DPipe ) terminator: ) ] action: [ (C {(shift)} {(1)}) (FuncDef name: debug body: (BraceGroup children: [ (Sentence child: (C {(echo)} {(DQ ($ VSub_Star "$*"))}) terminator: ) ] spids: [59] ) spids: [55 58] ) ] spids: [-1 49] ) ] else_action: [ (FuncDef name: debug body: (BraceGroup children: [(Sentence child:(C {(Lit_Other ":")}) terminator:)] spids: [76] ) spids: [72 75] ) ] spids: [70 83] ) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(-z)} {(DQ ($ VSub_Number "$1"))} {(Lit_Other "]")}) terminator: ) ] action: [ (C {(echo)} {(DQ ("Usage: ") ($ VSub_Number "$0") (" "))}) (C {(exit)} {(1)}) ] spids: [-1 99] ) ] spids: [-1 115] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:UNAME) op: Equal rhs: { (DQ (CommandSubPart command_list: (CommandList children:[(C {(uname)} {(-s)})]) left_token: spids: [120 124] ) ) } spids: [118] ) ] spids: [118] ) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Name "$UNAME"))} {(Lit_Other "=")} {(DQ (Linux))} {(Lit_Other "]")} ) terminator: ) ] action: [ (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:SHLIB_EXT) op:Equal rhs:{(DQ (so))} spids:[147])] spids: [147] ) ] spids: [-1 144] ) (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Name "$UNAME"))} {(Lit_Other "=")} {(DQ (Darwin))} {(Lit_Other "]")} ) terminator: ) ] action: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:SHLIB_EXT) op: Equal rhs: {(DQ (dylib))} spids: [172] ) ] spids: [172] ) ] spids: [152 169] ) ] else_action: [ (SimpleCommand words: [ {(echo)} { (DQ ("WARNING: Could not autodetect platform type ('uname -s' == ") ($ VSub_Name "$UNAME") ("); assuming Linux") ) } ] redirects: [(Redir op_id:Redir_GreatAnd fd:-1 arg_word:{(2)} spids:[188])] ) (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:UNAME) op:Equal rhs:{(DQ (Linux))} spids:[192])] spids: [192] ) (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:SHLIB_EXT) op:Equal rhs:{(DQ (so))} spids:[198])] spids: [198] ) ] spids: [177 203] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:private_libdir) op: Equal rhs: {($ VSub_Number "$1")} spids: [206] ) ] spids: [206] ) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(KW_Bang "!")} {(-f)} {(DQ ($ VSub_Name "$private_libdir") (/libarpack.) ($ VSub_Name "$SHLIB_EXT"))} {(Lit_Other "]")} ) terminator: ) ] action: [ (SimpleCommand words: [ {(echo)} { (DQ ("ERROR: Could not open ") ($ VSub_Name "$private_libdir") (/libarpack.) ($ VSub_Name "$SHLIB_EXT") ) } ] redirects: [(Redir op_id:Redir_GreatAnd fd:-1 arg_word:{(2)} spids:[239])] ) (C {(exit)} {(2)}) ] spids: [-1 227] ) ] spids: [-1 247] ) (FuncDef name: find_shlib body: (BraceGroup children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:lib_path) op: Equal rhs: {(DQ ($ VSub_Number "$1"))} spids: [257] ) ] spids: [257] ) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(-f)} {(DQ ($ VSub_Name "$lib_path"))} {(Lit_Other "]")}) terminator: ) ] action: [ (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Name "$UNAME"))} {(Lit_Other "=")} {(DQ (Linux))} {(Lit_Other "]")} ) terminator: ) ] action: [ (Pipeline children: [ (C {(ldd)} {(DQ ($ VSub_Name "$lib_path"))}) (C {(grep)} {($ VSub_Number "$2")}) (C {(cut)} {(-d) (SQ <" ">)} {(-f3)}) (C {(xargs)}) ] negated: False ) ] spids: [-1 296] ) ] else_action: [ (Pipeline children: [ (C {(otool)} {(-L)} {(DQ ($ VSub_Name "$lib_path"))}) (C {(grep)} {($ VSub_Number "$2")}) (C {(cut)} {(-d) (SQ <" ">)} {(-f1)}) (C {(xargs)}) ] negated: False ) ] spids: [327 363] ) ] spids: [-1 276] ) ] spids: [-1 366] ) ] spids: [254] ) spids: [250 253] ) (FuncDef name: private_libname body: (BraceGroup children: [ (C {(echo)} { (DQ ($ VSub_Name "$private_libdir") (/lib) ($ VSub_Number "$1") (.) ($ VSub_Name "$SHLIB_EXT") ) } ) ] spids: [375] ) spids: [371 374] ) (ForEach iter_name: lib iter_words: [{(arpack)} {(lapack)}] do_arg_iter: False body: (DoGroup children: [ (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(-f)} { (DQ ($ VSub_Name "$private_libdir") (/lib) ($ VSub_Name "$lib") (.) ($ VSub_Name "$SHLIB_EXT") ) } {(Lit_Other "]")} ) terminator: ) ] action: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:LIBGFORTRAN_PATH) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (C {(find_shlib)} { (DQ (CommandSubPart command_list: (CommandList children: [ (C {(private_libname)} {($ VSub_Name "$lib")}) ] ) left_token: spids: [441 445] ) ) } {(libgfortran)} ) ] ) left_token: spids: [437 449] ) } spids: [436] ) ] spids: [436] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:LIBGCC_PATH) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (C {(find_shlib)} { (DQ (CommandSubPart command_list: (CommandList children: [ (C {(private_libname)} {($ VSub_Name "$lib")}) ] ) left_token: spids: [457 461] ) ) } {(libgcc_s)} ) ] ) left_token: spids: [453 465] ) } spids: [452] ) ] spids: [452] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:LIBQUADMATH_PATH) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (C {(find_shlib)} { (DQ (CommandSubPart command_list: (CommandList children: [ (C {(private_libname)} {($ VSub_Name "$lib")}) ] ) left_token: spids: [473 477] ) ) } {(libquadmath)} ) ] ) left_token: spids: [469 481] ) } spids: [468] ) ] spids: [468] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:LIBGFORTRAN_DIRS) op: Equal rhs: { (DQ ($ VSub_Name "$LIBGFORTRAN_DIRS") (" ") (CommandSubPart command_list: (CommandList children: [(C {(dirname)} {($ VSub_Name "$LIBGFORTRAN_PATH")})] ) left_token: spids: [497 501] ) ) } spids: [493] ) ] spids: [493] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:LIBGFORTRAN_DIRS) op: Equal rhs: { (DQ ($ VSub_Name "$LIBGFORTRAN_DIRS") (" ") (CommandSubPart command_list: (CommandList children: [(C {(dirname)} {($ VSub_Name "$LIBGCC_PATH")})] ) left_token: spids: [509 513] ) ) } spids: [505] ) ] spids: [505] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:LIBGFORTRAN_DIRS) op: Equal rhs: { (DQ ($ VSub_Name "$LIBGFORTRAN_DIRS") (" ") (CommandSubPart command_list: (CommandList children: [(C {(dirname)} {($ VSub_Name "$LIBQUADMATH_PATH")})] ) left_token: spids: [521 525] ) ) } spids: [517] ) ] spids: [517] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:LIBGFORTRAN_SONAMES) op: Equal rhs: { (DQ ($ VSub_Name "$LIBGFORTRAN_SONAMES") (" ") (CommandSubPart command_list: (CommandList children: [ (C {(basename)} {(DQ ($ VSub_Name "$LIBGFORTRAN_PATH"))}) ] ) left_token: spids: [538 544] ) ) } spids: [534] ) ] spids: [534] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:LIBGCC_SONAMES) op: Equal rhs: { (DQ ($ VSub_Name "$LIBGCC_SONAMES") (" ") (CommandSubPart command_list: (CommandList children: [(C {(basename)} {(DQ ($ VSub_Name "$LIBGCC_PATH"))})] ) left_token: spids: [552 558] ) ) } spids: [548] ) ] spids: [548] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:LIBQUADMATH_SONAMES) op: Equal rhs: { (DQ ($ VSub_Name "$LIBQUADMATH_SONAMES") (" ") (CommandSubPart command_list: (CommandList children: [ (C {(basename)} {(DQ ($ VSub_Name "$LIBQUADMATH_PATH"))}) ] ) left_token: spids: [566 572] ) ) } spids: [562] ) ] spids: [562] ) ] spids: [-1 425] ) ] spids: [-1 576] ) ] spids: [405 578] ) spids: [399 403] ) (FuncDef name: uniquify body: (BraceGroup children: [ (Pipeline children: [ (C {(echo)} {(DQ ($ VSub_Number "$1"))}) (C {(tr)} {(DQ (" "))} {(DQ (EscapedLiteralPart token:))}) (C {(sort)}) (C {(uniq)}) (C {(grep)} {(-v)} {(SQ <"^$">)}) (C {(tr)} {(DQ (EscapedLiteralPart token:))} {(DQ (" "))}) ] negated: False ) ] spids: [588] ) spids: [584 587] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:LIBGFORTRAN_DIRS) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [(C {(uniquify)} {(DQ ($ VSub_Name "$LIBGFORTRAN_DIRS"))})] ) left_token: spids: [643 649] ) } spids: [642] ) ] spids: [642] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:SONAMES) op: Equal rhs: { (DQ (CommandSubPart command_list: (CommandList children: [ (C {(uniquify)} { (DQ ($ VSub_Name "$LIBGFORTRAN_SONAMES") (" ") ($ VSub_Name "$LIBGCC_SONAMES") (" ") ($ VSub_Name "$LIBQUADMATH_SONAMES") ) } ) ] ) left_token: spids: [653 663] ) ) } spids: [651] ) ] spids: [651] ) (C {(debug)} {(DQ ("Discovered traces of libgfortran within ") ($ VSub_Name "$LIBGFORTRAN_DIRS"))}) (C {(debug)} {(DQ ("Got SONAMES of ") ($ VSub_Name "$SONAMES"))}) (ForEach iter_name: soname iter_words: [{($ VSub_Name "$SONAMES")}] do_arg_iter: False body: (DoGroup children: [ (ForEach iter_name: dir iter_words: [{($ VSub_Name "$LIBGFORTRAN_DIRS")}] do_arg_iter: False body: (DoGroup children: [ (If arms: [ (if_arm cond: [ (Sentence child: (AndOr children: [ (C {(Lit_Other "[")} {(KW_Bang "!")} {(-f)} { (DQ ($ VSub_Name "$private_libdir") (/) ($ VSub_Name "$soname")) } {(Lit_Other "]")} ) (C {(Lit_Other "[")} {(-f)} {(DQ ($ VSub_Name "$dir") (/) ($ VSub_Name "$soname"))} {(Lit_Other "]")} ) ] op_id: Op_DAmp ) terminator: ) ] action: [ (C {(cp)} {(-v)} {(DQ ($ VSub_Name "$dir") (/) ($ VSub_Name "$soname"))} {(DQ ($ VSub_Name "$private_libdir"))} ) (C {(chmod)} {(755)} {(DQ ($ VSub_Name "$private_libdir") (/) ($ VSub_Name "$soname"))} ) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Name "$UNAME"))} {(Lit_Other "=")} {(DQ (Darwin))} {(Lit_Other "]")} ) terminator: ) ] action: [ (C {(install_name_tool)} {(-id)} {(DQ ("@rpath/") ($ VSub_Name "$soname"))} {(DQ ($ VSub_Name "$private_libdir") (/) ($ VSub_Name "$soname"))} ) ] spids: [-1 785] ) ] spids: [-1 804] ) ] spids: [-1 739] ) ] spids: [-1 807] ) ] spids: [705 810] ) spids: [701 703] ) ] spids: [693 812] ) spids: [689 691] ) (FuncDef name: change_linkage body: (BraceGroup children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:lib_path) op: Equal rhs: {(DQ ($ VSub_Number "$1"))} spids: [838] ) ] spids: [838] ) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(KW_Bang "!")} {(-f)} {(DQ ($ VSub_Name "$lib_path"))} {(Lit_Other "]")} ) terminator: ) ] action: [ (C {(debug)} {(DQ (" ") ($ VSub_Name "$lib_path") (" doesn't exist, skipping"))}) (ControlFlow token:) ] spids: [-1 864] ) ] spids: [-1 879] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:soname) op: Equal rhs: {(DQ ($ VSub_Number "$2"))} spids: [887] ) ] spids: [887] ) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Name "$UNAME"))} {(Lit_Other "=")} {(DQ (Darwin))} {(Lit_Other "]")} ) terminator: ) ] action: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:old_link) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (C {(find_shlib)} {(DQ ($ VSub_Name "$lib_path"))} {(DQ ($ VSub_Name "$soname"))} ) ] ) left_token: spids: [915 925] ) } spids: [914] ) ] spids: [914] ) (C {(echo)} {(DQ (" ") ($ VSub_Name "$old_link"))}) (C {(install_name_tool)} {(-change)} {(DQ ($ VSub_Name "$old_link"))} {(DQ ("@rpath/") ($ VSub_Name "$soname"))} {(DQ ($ VSub_Name "$lib_path"))} ) ] spids: [-1 911] ) ] else_action: [ (C {(patchelf)} {(--set-rpath)} {(EscapedLiteralPart token:) (ORIGIN)} {(DQ ($ VSub_Name "$lib_path"))} ) ] spids: [954 972] ) ] spids: [831] ) spids: [827 830] ) (ForEach iter_name: lib iter_words: [{(libopenblas)} {(libarpack)} {(libcholmod)} {(liblapack)} {($ VSub_Name "$SONAMES")}] do_arg_iter: False body: (DoGroup children: [ (ForEach iter_name: lib_path iter_words: [{($ VSub_Name "$private_libdir") (/) ($ VSub_Name "$lib") (Lit_Other "*")}] do_arg_iter: False body: (DoGroup children: [ (ForEach iter_name: soname iter_words: [{($ VSub_Name "$SONAMES")}] do_arg_iter: False body: (DoGroup children: [ (C {(debug)} { (DQ ("changing linkage of ") ($ VSub_Name "$lib_path") (" to ") ($ VSub_Name "$soname") ) } ) (C {(change_linkage)} {(DQ ($ VSub_Name "$lib_path"))} {(DQ ($ VSub_Name "$soname"))} ) ] spids: [1048 1072] ) spids: [1044 1046] ) ] spids: [1032 1075] ) spids: [1025 1030] ) ] spids: [1009 1077] ) spids: [997 1007] ) ] )