#!/bin/sh
#
#  Link libmonitor_wrap.a and callback functions into an application
#  statically by editing the compile line.
#
#  Usage: monitor-link [options] compiler file ...
#
#     -h, --help
#     -i, --insert  <file.o>
#     -u, --undefined  <symbol>
#     -v, --verbose
#     -w, --wrap  <symbol>
#
#  where <file.o> is an object file containing definitions of the
#  callback functions (may be used multiple times), and <symbol> is a
#  symbol name passed to the linker (may be used multiple times).
#
#  A monitor client should provide a script for linking its own code
#  and monitor's functions into an application, possibly using this
#  script as a starting point.
#
#  This script is in the public domain.
#
#  $Id$
#

prefix="/usr"
exec_prefix="/usr"
libdir="/usr/lib64"
libmonitor="${libdir}/libmonitor_wrap.a"
monitor_wrap_names="main exit _exit dlopen dlclose fork vfork system execl execlp execle execv execvp execve MPI_Init MPI_Init_thread MPI_Finalize MPI_Comm_rank mpi_init mpi_init_thread mpi_finalize mpi_comm_rank mpi_init_ mpi_init_thread_ mpi_finalize_ mpi_comm_rank_ mpi_init__ mpi_init_thread__ mpi_finalize__ mpi_comm_rank__ pthread_create pthread_exit sigwait sigwaitinfo sigtimedwait signal sigaction sigprocmask pthread_sigmask"

# Space-separated list of object files to add.
insert_files=

# Space-separated list of extra symbol names to wrap.
wrap_names=

# Space-separated list of symbol names to force undefined.
undef_names=

# Space-separated list of extra library names, eg: "-ldl -lm".
library_names=

die()
{
    echo "$0: error: $*" 1>&2
    exit 1
}

usage()
{
    cat <<EOF
Usage: $0 [options] compiler file ...

   -h, --help
   -i, --insert  <file.o>
   -u, --undefined  <symbol>
   -v, --verbose
   -w, --wrap  <symbol>

where <file.o> is an object file containing definitions of the
callback functions (may be used multiple times), and <symbol> is a
symbol name passed to the linker (may be used multiple times).

EOF
    exit 0
}

#
# Our options come first.
#
verbose=no
while test "x$1" != x
do
    case "$1" in
	-h | --help )
	    usage
	    ;;

	-i | --insert )
	    test "x$2" != x || die "missing argument: $*"
	    insert_files="${insert_files} $2"
	    shift ; shift
	    ;;

	-u | --undefined )
	    test "x$2" != x || die "missing argument: $*"
	    undef_names="${undef_names} $2"
	    shift ; shift
	    ;;

	-v | --verbose )
	    verbose=yes
	    shift
	    ;;

	-w | --wrap )
	    test "x$2" != x || die "missing argument: $*"
	    wrap_names="${wrap_names} $2"
	    shift ; shift
	    ;;

	-- )
	    shift
	    break
	    ;;

	-* )
	    die "unknown option: $1"
	    ;;

	* )
	    break
	    ;;
    esac
done

#
# Must have a compiler command and at least one argument.
#
test "x$2" != x || usage
command="$1"
shift

#
# Duplicate the -l<lib> arguments.
#
appl_libs=
for lib in "$@"
do
    case "$lib" in
	-l?* ) appl_libs="$appl_libs $lib" ;;
    esac
done

wrap_args=
for name in $monitor_wrap_names $wrap_names
do
    wrap_args="${wrap_args} -Wl,--wrap=${name}"
done

undef_args=
for name in $undef_names
do
    undef_args="${undef_args} -Wl,--undefined=__wrap_${name}"
done

mon_args="${insert_files} ${libmonitor} ${appl_libs} ${library_names}"
if test "$verbose" = yes ; then
    echo "new command line: " $command $wrap_args $undef_args "$@" $mon_args
fi

exec $command $wrap_args $undef_args "$@" $mon_args
