#!/bin/sh

################################################################################
# Program: osxfixup
#
# Purpose: This script uses install_name_tool to make all references to libraries
#          in a shared library or executable into @executable_path/../lib
#          relative references. This enables the programs to be moved to a
#          computer other than where they were built.
#
# Programmer: Brad Whitlock
# Date: Wed Jan 13 15:41:40 PST 2010
#
# Modifications:
#   Cyrus Harrison, Thu Apr 22 08:53:19 PDT 2010
#   Added link to qt.conf into bundle.app/Contents/Resources to prevent qt
#   from loading plugins from other qt installs.
#
#   Cyrus Harrison, Fri May  7 14:40:18 PDT 2010
#   (changes from Jeremy) Remove search for install names w/ a '/Users/'
#   prefix & instead just skip change of install names w/ a '/usr/lib' prefix.
#
#   Cyrus Harrison, Thu Nov 29 14:27:08 PST 2012
#   dylib case: use otool to check if we are actually dealing with a lib.
#   In some cases py files creep in.
#
#   Brad Whitlock, Tue Jan 29 12:12:26 PST 2013
#   I reordered the function arguments and added support for filtering MPI library
#   paths, which is what you want when using MPI that we package in VisIt.
#
################################################################################

#
# This function runs install_name_tool on a dylib and replaces all instances of 
# /User/*/lib/lib*.dylib with @executable_path/../lib/lib*.dylib to make the dylib
# execute relative.
#
#
# $1 : ON|OFF : Whether we're making MPI libraries executable relative.
# $2 : ON|OFF : The value for rpath_enable.
# $3 : The whole path and name of the dylib file
#
function fixup_dylib
{
    # if $3 is a symlink, return
    rpath_enable="$2"
    if test -h $3 ; then
        echo "Skipping $3 because it is a symlink"
        return 0
    fi
    
    dy_check=$(otool -D $3 | tail -n 1 | grep "is not an object file")
    if [[ $dy_check != "" ]] ; then
        echo "Skipping $3 because it is not a library"
        return 0
    fi

    # Get the name of this library from otool since it might not match quite 
    # what's in $3 because of version number differences.
    thisLibrary=$(otool -D $3 | tail -n 1)
    s=$(echo $thisLibrary | grep ".framework")
    if [[ $s != "" ]] ; then
        framework_prefix=${s/\.framework*/} #remove everything from framework and forward..
        framework_name=${framework_prefix/*\/} #remove all the words before framework (we are now left with framework name)
        framework_suffix=${s/*\.framework\//} #append the rest
        framework_path="${framework_name}.framework/${framework_suffix}"
        # Framework
        if [[ "$rpath_enable" == "ON" ]]; then
            thisLibraryFixed= "@rpath/${framework_path}" #$(echo "$thisLibrary" | sed "s/^\/[A-Za-z0-9_. \/-]*\/lib/@rpath\/lib/g")
        else
            thisLibraryFixed="@executable_path/../lib/${framework_path}" #$(echo "$thisLibrary" | sed "s/^\/[A-Za-z0-9_. \/-]*\/lib/@executable_path\/..\/lib/g")
        fi
        thisLibraryName1=$(echo "$3" | sed "s/^\/[A-Za-z0-9_. \/-]*\.framework//g")  #$(echo "$3" | sed "s/^\/[A-Za-z0-9_. \/-]*\/lib//g")
        thisLibraryName2=$(echo "$thisLibrary" | sed "s/^\/[A-Za-z0-9_. \/-]*\.framework//g") #$(echo "$thisLibrary" | sed "s/^\/[A-Za-z0-9_. \/-]*\/lib//g")
    else
        # Library
        if [[ "$rpath_enable" == "ON" ]]; then
            thisLibraryFixed=$(echo "$thisLibrary" | sed "s/^\/[A-Za-z0-9_. \/-]*\/lib/@rpath\/lib/g")
        else
            thisLibraryFixed=$(echo "$thisLibrary" | sed "s/^\/[A-Za-z0-9_. \/-]*\/lib/@executable_path\/..\/lib\/lib/g")
        fi
        thisLibraryName1=$(echo "$3" | sed "s/^\/[A-Za-z0-9_. \/-]*\/lib/lib/g")
        thisLibraryName2=$(echo "$thisLibrary" | sed "s/^\/[A-Za-z0-9_. \/-]*\/lib/lib/g")
    fi
#    echo "thisLibrary = $thisLibrary"
#    echo "thisLibraryFixed = $thisLibraryFixed"
#    echo "thisLibraryName1 = $thisLibraryName1"
#    echo "thisLibraryName2 = $thisLibraryName2"

    sharedLibs=$(otool -L $3 | grep -v "/usr/lib" | grep -v "/usr/local/lib" | grep -v "/opt/local/lib" | grep -v "/opt/local/Library" | grep -v "$thisLibraryName1" | grep -v "$thisLibraryName2")
    if [[ $1 == "OFF" ]] ; then
        sharedLibs=$(echo "$sharedLibs" | grep -v "libmpi" | grep -v "libopen-rte" | grep -v "libopen-pal")
    fi
#    echo "sharedLibs = $sharedLibs"
    command=""
    for library in $sharedLibs ; do
        s=$(echo $library | fgrep -v "/usr/lib" | fgrep -v "/usr/local/lib" | fgrep -v "/Library/Frameworks/" | fgrep -v "/Network/Library/Frameworks/" | fgrep -v "/System/Library/Frameworks/")
        if [[ $s != "" ]] ; then
            framework=$(echo $library | grep ".framework")
            if [[ $framework != "" ]] ; then
                framework_prefix=${framework/\.framework*/} #remove everything from framework and forward..
                framework_name=${framework_prefix/*\/} #remove all the words before framework (we are now left with framework name)
                framework_suffix=${framework/*\.framework\//} #append the rest
                framework_path="${framework_name}.framework/${framework_suffix}"
                if [[ "$rpath_enable" == "ON" ]]; then
                    newlibrary="@rpath/${framework_path}"
                else
                    newlibrary="@executable_path/../lib/${framework_path}"
                fi
            else
                if [[ "$rpath_enable" == "ON" ]]; then
                    newlibrary=$(echo $library | sed "s/^\/[A-Za-z0-9_. \/-]*\/lib/@rpath\/lib/g")
                else
                    newlibrary=$(echo $library | sed "s/^\/[A-Za-z0-9_. \/-]*\/lib/@executable_path\/..\/lib\/lib/g")
                fi
            fi
#            echo "$library -> $newlibrary"
            command="$command -change $library $newlibrary"
        fi
    done

    echo "Making dylib execute relative: $3"
    if [[ "$command" != "" ]] ; then
        install_name_tool $command $3
        if [[ "$rpath_enable" == "ON" ]]; then
            install_name_tool -add_rpath "@executable_path/../lib/" "$3"
            install_name_tool -add_rpath "/usr/local/lib/" "$3"
            install_name_tool -add_rpath "/usr/lib/" "$3"
        fi
    fi
    install_name_tool -id $thisLibraryFixed $3
    
    return 1
}

#
# Fix up an executable program so that its shared libraries are referenced 
# relative to @executable_path/../lib.
#
# $1 : ON|OFF : Whether we're making MPI libraries executable relative.
# $2 : ON|OFF : The value for rpath_enable.
# $3 : The whole path and name of the application
#
function fixup_exe
{
    rpath_enable="$2"
    # if $3 is a symlink, return
    if test -h $3 ; then
        echo "Skipping $3 because it is a symlink"
        return 0
    fi

    rpath_enable="$2"
    # Get the name of this library from otool since it might not match quite 
    # what's in $3 because of version number differences.
    thisLibrary=$(otool -D $3 | tail -n 1 | sed "s/\://g")
    if [[ "$rpath_enable" == "ON" ]]; then
        thisLibraryFixed=$(echo "$thisLibrary" | sed "s/^\/[A-Za-z0-9_. \/-]*\/bin/@rpath\/bin/g")
    else
        thisLibraryFixed=$(echo "$thisLibrary" | sed "s/^\/[A-Za-z0-9_. \/-]*\/bin/@executable_path\/..\/bin/g")
    fi
#    echo "thisLibrary = $thisLibrary"
#    echo "thisLibraryFixed = $thisLibraryFixed"

    sharedLibs=$(otool -L $3 | grep -v ":" | grep "/")
    if [[ $1 == "OFF" ]] ; then
        sharedLibs=$(echo "$sharedLibs" | grep -v "libmpi" | grep -v "libopen-rte" | grep -v "libopen-pal")
    fi
    command=""
    for library in $sharedLibs ; do
        s=$(echo $library | grep -v "/usr/lib" | grep -v "/usr/local/lib" | grep -v "/usr/X11R6" | grep -v "/opt/local/lib" | grep -v "/opt/local/Library"  | grep -v "/Library/Frameworks/" | grep -v "/Network/Library/Frameworks/" | grep -v "/System/Library/Frameworks/")
        if [[ $s != "" ]] ; then
            framework=$(echo $library | grep ".framework")
            if [[ $framework != "" ]] ; then
                framework_prefix=${framework/\.framework*/} #remove everything from framework and forward..
                framework_name=${framework_prefix/*\/} #remove all the words before framework (we are now left with framework name)
                framework_suffix=${framework/*\.framework\//} #append the rest
                framework_path="${framework_name}.framework/${framework_suffix}"
                if [[ "$rpath_enable" == "ON" ]]; then
                    newlibrary="@rpath/${framework_path}"
                else
                    newlibrary="@executable_path/../lib/${framework_path}"
                fi
            else
                if [[ "$rpath_enable" == "ON" ]]; then
                    newlibrary=$(echo $library | sed "s/^\/[A-Za-z0-9_. \/-]*\/lib/@rpath\/lib/g")
                else
                    newlibrary=$(echo $library | sed "s/^\/[A-Za-z0-9_. \/-]*\/lib/@executable_path\/..\/lib\/lib/g")
                fi
            fi
#            echo "$library -> $newlibrary"
            command="$command -change $library $newlibrary"
        fi
    done

    if [[ "$command" != "" ]] ; then
        echo "Making executable execute relative $3"
        install_name_tool $command $3
        if [[ "$rpath_enable" == "ON" ]]; then
            install_name_tool -add_rpath "@executable_path/../lib/" "$3"
            install_name_tool -add_rpath "/usr/local/lib/" "$3"
            install_name_tool -add_rpath "/usr/lib/" "$3"
        fi
    else
        echo "Skipping $3"
    fi
    return 1
}

#
# Fixes up the application and makes some symlinks that make the bundle work.
#
# $1 : ON|OFF : Whether we're making MPI libraries executable relative.
# $2 : ON|OFF : The value for rpath_enable.
# $3 : The path to the architecture bin directory
# $4 : The undecorated name of the application (e.g. "gui")
#
function fixup_bundle
{
    # First, fixup the program
    fixup_exe $1 $2 "$3/$4.app/Contents/MacOS/$4"

    # Also, add some symlinks that we need
 
    # cd into the destination bin directory.
    pushd . > /dev/null
    cd "$3"

    # Make a link to the actual app down in the bundle.
    ln -s $4.app/Contents/MacOS/$4 .
    
    # cd into the .app bundle
    cd $4.app/Contents
    ln -s ../../../lib .

    # Make a link up to visit
    cd MacOS
    ln -s ../../../../../../bin/visit .

    # Make a link to qt.conf to avoid loading qt plugins
    # from other qt installs.
    if test -d ../Resources ; then
        cd ../Resources
        ln -s ../../../qt.conf .
    fi
    popd > /dev/null
}

# main
if [[ $1 == "-exe" ]] ; then
    fixup_exe "$2" "$3" "$4"
elif [[ $1 == "-bundle" ]] ; then
    fixup_bundle "$2" "$3" "$4" "$5"
else
    fixup_dylib "$2" "$3" "$4"
fi
