#!/usr/bin/perl -w # # (C) 2009 by Argonne National Laboratory. # See COPYRIGHT in top-level directory. # # takes a standard mpicxx script as an argument and tried to generate a # darshan-enabled mpicxx script to mimic it's behavior use Getopt::Long; use English; $CP_WRAPPERS="@CP_WRAPPERS@"; $DARSHAN_LIB_PATH="@darshan_lib_path@"; $CP_ZLIB_LINK_FLAGS="@__CP_ZLIB_LINK_FLAGS@"; my $input_file = ""; my $output_file = ""; 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); } chomp($compile_cmd); chomp($link_cmd); # # 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/\/*([^\/ ]+\/)*//; } open (OUTPUT, ">$output_file") || die("Error opening output file: $!"); # substitute arguments and darshan options into commands $base_link_cmd = $link_cmd; $base_link_cmd =~ s/foo.o -o foo/"\$\{allargs\[\@\]\}"/g; $link_cmd =~ s/foo.o -o foo/"\$\{newallargs\[\@\]\}" -L$DARSHAN_LIB_PATH $CP_ZLIB_LINK_FLAGS -ldarshan-mpi-io -lz $CP_WRAPPERS/g; $link_cmd =~ s/$/ -L$DARSHAN_LIB_PATH -ldarshan-posix/g; $compile_cmd =~ s/-c foo.c/"\$\{allargs\[\@\]\}"/g; # create link cmd with noshrargs variable $link_cmd_no_shared = $base_link_cmd; $link_cmd_no_shared =~ s/allargs/noshrargs/; print OUTPUT<<'EOF'; #!/bin/bash # # 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 EOF print OUTPUT<<"EOF"; # 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 # if allargs includes any libraries, then we need to get # -ldarshan-mpi-io in there first argno=0; once=0; newallargs=\("\$\{allargs\[\@\]\}"\); for arg in "\$\{newallargs\[\@\]\}"; do res=`expr match "\$arg" "-l"`; 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 used_darshan=0 # create a temporary file tmpfile=`mktemp` # generate a map of the symbol names # don't use -shared for this step 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 # is MPI in there? grep MPI \$tmpfile >& /dev/null rc_mpi=\$? # 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 rc_pmpi=\$? # normal or cnk libraries? grep -E mpich\\.cnk\\.a \$tmpfile >& /dev/null rc_cnk_check=\$? if [ \$rc_cnk_check -eq 0 ] ; then argno=0 for arg in "\$\{newallargs\[\@\]\}"; do if [ "\$arg" = "-lcxxmpich" ]; then newallargs[\$argno]=-lcxxmpich.cnk; fi argno=`expr \$argno + 1` done fi 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 \$Show $link_cmd used_darshan=1 fi fi # otherwise use the normal command line if [ "\$used_darshan" = "0" ] ; then \$Show $base_link_cmd fi rc=\$? else \$Show $compile_cmd rc=\$? fi exit \$rc EOF close(OUTPUT); chmod(0755, $output_file); exit(0); sub process_args { use vars qw( $opt_help $opt_output $opt_trim ); Getopt::Long::Configure("no_ignore_case", "bundling"); GetOptions( "help", "output=s", "trim"); if($opt_help) { print_help(); exit(0); } if($opt_trim) { $trim_exe_path=1; } 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 { print<<"EOF"; Usage: $PROGRAM_NAME --output --help Prints this help message --output Specifies name of output script --trim Trim the compilers path Purpose: This script takes an existing mpicxx script as input and generates a modified version that includes Darshan support. EOF return; }