darshan-gen-cc.pl.in 6.18 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
#!/usr/bin/perl -w
#
#  (C) 2009 by Argonne National Laboratory.
#      See COPYRIGHT in top-level directory.
#

# takes a standard mpicc script as an argument and tried to generate a
# darshan-enabled mpicc script to mimic it's behavior

use Getopt::Long;
use English;

13 14 15 16
$CP_WRAPPERS="@CP_WRAPPERS@";
$DARSHAN_LIB_PATH="@darshan_lib_path@";
$CP_ZLIB_LINK_FLAGS="@__CP_ZLIB_LINK_FLAGS@";

17 18
my $input_file = "";
my $output_file = "";
19
my $trim_exe_path = 0;
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44

process_args();

# run original mpicc with -show argument to capture command line for
# compilation and linking
my $compile_cmd = `$input_file -show -c foo.c`;
if (!($compile_cmd))
{
    printf STDERR "Error: failed to invoke $input_file with -show\n";
    exit(1);
}

my $link_cmd = `$input_file -show foo.o -o foo`;
if (!($link_cmd))
{
    printf STDERR "Error: failed to invoke $input_file with -show\n";
    exit(1);
}

# check command lines for accuracy
if(!($compile_cmd =~ /-c foo.c/) || !($link_cmd =~ /foo.o -o foo/))
{
    printf STDERR "Error: faulty output from $input_file with -show.\n";
    exit(1);
}
45 46
chomp($compile_cmd);
chomp($link_cmd);
47

48 49 50 51 52 53 54 55 56 57 58 59 60 61
#
# Incomprehensible re to eat the leading path of the compiler command
# and only give the basename.
#
# /cmd -> cmd
# cmd -> cmd
# /x/y/x/z/cmd -> cmd
#
if ($trim_exe_path)
{
    $compile_cmd =~ s/\/*([^\/ ]+\/)*//;
    $link_cmd =~ s/\/*([^\/ ]+\/)*//;
}

62 63
open (OUTPUT, ">$output_file") || die("Error opening output file: $!");

64
# substitute arguments and darshan options into commands
65 66
$base_link_cmd = $link_cmd;
$base_link_cmd =~ s/foo.o -o foo/"\$\{allargs\[\@\]\}"/g;
67
$link_cmd =~ s/foo.o -o foo/"\$\{newallargs\[\@\]\}" -L$DARSHAN_LIB_PATH $CP_ZLIB_LINK_FLAGS -ldarshan-mpi-io -lz $CP_WRAPPERS/g;
68
$link_cmd =~ s/$/ -L$DARSHAN_LIB_PATH -ldarshan-posix/g;
69
$compile_cmd =~ s/-c foo.c/"\$\{allargs\[\@\]\}"/g;
70

71 72 73 74
# create link cmd with noshrargs variable
$link_cmd_no_shared = $base_link_cmd;
$link_cmd_no_shared =~ s/allargs/noshrargs/;

75
print OUTPUT<<'EOF';
Philip Carns's avatar
Philip Carns committed
76
#!/bin/bash
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
#
# Auto-generated mpicc script from darshan-gen-cc.pl
#
#
# Internal variables
# Show is set to echo to cause the compilation command to be echoed instead 
# of executed.
Show=

linking=yes
allargs=("$@")
argno=0
for arg in "$@" ; do
    # Set addarg to no if this arg should be ignored by the C compiler
    addarg=yes
    case "$arg" in 
 	# ----------------------------------------------------------------
	# Compiler options that affect whether we are linking or no
    -c|-S|-E|-M|-MM)
    # The compiler links by default
    linking=no
    ;;
    -show)
    addarg=no
    Show=echo
    ;;
    esac
    if [ $addarg = no ] ; then
	unset allargs[$argno]
    fi
    # Some versions of bash do not accept ((argno++))
    argno=`expr $argno + 1`
done
if [ "$linking" = yes ] ; then
    if [ -n "$C_LINKPATH_SHL" ] ; then
	# prepend the path for the shared libraries to the library list
	mpilibs="$C_LINKPATH_SHL$libdir $mpilibs"
    fi
115
EOF
116
print OUTPUT<<"EOF";
117 118 119 120 121 122 123 124
    # Trial run to generate a symbol listing.  We only enable Darshan if:
    # a) MPI is used
    # b) PMPI is _not_ used
    #
    # We want Darshan to get out of the way if the user is doing a runtime
    # test in configure (in which case MPI objects break the executable) or
    # if the user is using another PMPI based tool

125 126
    # if allargs includes any libraries, then we need to get 
    # -ldarshan-mpi-io in there first
127 128 129 130
    argno=0;
    once=0;
    newallargs=\("\$\{allargs\[\@\]\}"\);
    for arg in "\$\{newallargs\[\@\]\}"; do
131
        res=`expr match "\$arg" "-l"`;
132 133 134 135 136 137 138 139 140 141
        if [ \$res -gt 0 -a \$once -lt 1 ]; then
            newallargs[\$argno]=-ldarshan-mpi-io
            argno=`expr \$argno + 1`
            newallargs[\$argno]=\$arg;
            once=1;
        else
            newallargs[\$argno]=\$arg;
        fi
        argno=`expr \$argno + 1`
    done
142

143 144 145 146 147 148
    used_darshan=0

    # create a temporary file
    tmpfile=`mktemp`
    # generate a map of the symbol names
    # don't use -shared for this step
149 150 151 152 153 154 155 156 157 158
    argno=0
    noshrargs=\("\$\{allargs\[\@\]\}");
    for arg in "\$\{noshrargs\[\@\]\}"; do
        if [ "\$arg" = "-shared" ]; then
            unset noshrarg[\$argno];
        fi
        argno=`expr \$argno + 1`
    done
    $link_cmd_no_shared -Wl,-Map,\$tmpfile \$LDFLAGS -o /dev/null >& /dev/null

159 160 161
    # is MPI in there?
    grep MPI \$tmpfile >& /dev/null
    rc_mpi=\$?
162 163
    # is PMPI being used for any init, finalize, or mpi-io calls?
    grep -E \\(PMPI_File_\\)\\|\\(PMPI_Init\\)\\|\\(PMPI_Finalize\\) \$tmpfile | grep -v -E \\(mpich.cnk.a\\|mpich.a\\) |grep \\(PMPI >& /dev/null
164 165 166 167 168 169 170 171 172
    rc_pmpi=\$?
    rm \$tmpfile >& /dev/null

    # disable darshan if the executable is not an MPI program (this feature
    # mainly allows runtime configure tests to work
    if [ \$rc_mpi -eq 0 ] ; then
        # disable darshan if something else is already using PMPI; we don't
        # want to cause any symbol conflicts
        if [ \$rc_pmpi -ne 0 ] ; then
Philip Carns's avatar
Philip Carns committed
173
            \$Show $link_cmd
174 175 176 177 178 179
            used_darshan=1
        fi
    fi

    # otherwise use the normal command line
    if [ "\$used_darshan" = "0" ] ; then
Philip Carns's avatar
Philip Carns committed
180
        \$Show $base_link_cmd
181 182
    fi
    rc=\$?
183
else
184 185
    \$Show $compile_cmd
    rc=\$?
186 187
fi

188
exit \$rc
189 190 191 192 193 194 195 196 197 198
EOF

close(OUTPUT);

chmod(0755, $output_file); 

exit(0);

sub process_args
{
199
    use vars qw( $opt_help $opt_output $opt_trim);
200 201 202

    Getopt::Long::Configure("no_ignore_case", "bundling");
    GetOptions( "help",
203 204
        "output=s",
        "trim");
205 206 207 208 209 210 211

    if($opt_help)
    {
        print_help();
        exit(0);
    }

212 213 214 215 216
    if($opt_trim)
    {
        $trim_exe_path=1;
    }

217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
    if($opt_output)
    {
        $output_file = $opt_output;
    }
    else
    {
        print_help();
        exit(1);
    }

    # there should only be one remaining argument: the input file 
    if($#ARGV != 0)
    {
        print "Error: invalid arguments.\n";
        print_help();
        exit(1);
    }
    $input_file = $ARGV[0];

    return;
}

sub print_help
{
241
    print<<"EOF";
242 243 244 245 246

Usage: $PROGRAM_NAME <stock mpicc> --output <modified mpicc>

    --help          Prints this help message
    --output        Specifies name of output script
247
    --trim          Trim the compilers path
248 249 250 251 252 253 254 255 256 257

Purpose:

    This script takes an existing mpicc script as input and generates a
    modified version that includes Darshan support.

EOF
    return;
}