#!/bin/sh


# Use the following on the Symmetry
#!/usr/att/bin/sh

#
# Toplevel PCN compiler driver.
#


#
# These variables will be changed by sed during the installation
#
DEFAULT_TARGET_CONFIG="sun4"
INSTALL_BASE_DIR="/usr/local/pcn_2.0"
G_EXPR="/bin/expr"
G_RM="/bin/rm"


#
# Run a shell command, exiting if the command fails. Note that if you
# execute the function inside of a loop that uses the positional
# parameters, you must save the parameters since there is only set of
# them and the function call overwrites them. Blech.
#
# First argument is the command to be executed.
#
# If there are two arguments, the second is the name of the file
# to which stdout is redirected.
#
# If there are three arguments, the second is the name of the file
# from which stdin is redirected, and the third is the name of the file
# to which stdout is redirected.
#
# If the command fails, invoke exit_program with the exit status of
# the failing command.
#
run_command ()
{
    
    if [ $verbose_flag -ne 0 ]; then
	if [ $# -eq 1 ]; then
	    echo "$1"
	elif [ $# -eq 2 ]; then
	    echo "$1 > $2"
	elif [ $# -eq 3 ]; then
	    echo "$1 < $2 > $3"
	fi
    fi
    if [ $dryrun_flag -eq 0 ]; then
	if [ $# -eq 1 ]; then
	    $1
	elif [ $# -eq 2 ]; then
	    $1 > $2
	elif [ $# -eq 3 ]; then
	    $1 < $2 > $3
	fi

	exit_status=$?
	if [ $exit_status -ne 0 ]; then
#	    echo "$pgm: The following command failed with exit status $exit_status:" 1>&2
#	    
#	    if [ $# -eq 1 ]; then
#		echo "$1" 1>&2
#	    elif [ $# -eq 2 ]; then
#		echo "$1 > $2" 1>&2
#	    elif [ $# -eq 3 ]; then
#		echo "$1 < $2 > $3" 1>&2
#	    fi

	    exit_program $exit_status
	fi
    fi
}

exit_program ()
{
    exit_code=$1
    if [ ${save_intermediate_files-0} -eq 0 ]; then
	if [ "x$generated_cpp_files" != "x" ]; then
	    run_command "$G_RM -f $generated_cpp_files"
	fi
	if [ "x$generated_o_files" != "x" ]; then
	    run_command "$G_RM -f $generated_o_files"
	fi
	if [ "x$generated_pam_files" != "x" ]; then
	    run_command "$G_RM -f $generated_pam_files"
	fi
	if [ "x$generated_c_files" != "x" ]; then
	    run_command "$G_RM -f $generated_c_files"
	fi
    fi

    if [ "x$currently_compiling" != "x" ]; then
	$G_RM -f $currently_compiling
	echo "Removing $currently_compiling"
    fi

    exit $exit_code
}

interrupt ()
{
    echo ""
    echo "Interrupted... cleaning up"

    exit_program 0
}

pgm="pcncomp"

#usage="Usage string\n\
#needed here"
print_help ()
{
    cat << ENDOFHELP
Usage: pcncomp <args>
Where <args> is:
    *.c			C source file to compile
    *.f			Fortran source file to compile
    *.F			Fortran source file with CPP directives to compile
    *.pcn		PCN source file to compile
    *.ptn		PTN source file to compile
    *.o			Foreign object file to link
    *.pam		PCN object file to link
    *.a			Foreign object library to link
    -o <file>		Output file name
    -l<libbase>		A foreign object library to link.  The
			library path will be searched for 
			lib<libbase>.a.
    -L<path>		Add <path> to the list of paths to search
			for a foreign object library when a
			-l flag is encountered.
    -pl<libbase>	PCN and/or foreign object library to link.  The
			PCN library path will be searched for
			lib<libbase>.pam and lib<libbase>_<arch>.a,
			where <arch> is the target architecture. 
			(similar to -l, but for .pam libraries)
    -pL<path>		Add <path> to the list of paths to search
			for a PCN library when a -pl flag 
			is encountered.
			(similar to -L, but for .pam libraries)
    -c			Stop after compiling to a .o or .pam file.
			Do not link.
    -E			Stop after running CPP.
    -pcnt		Stop after the PCN linker generates a
			pcnt (temporary PCN link) file.
    -oc <file>		The name of the pcnt file. (see the -pcnt flag)
    -target <target>	Cross compile to the specified <target>.
    -I<path>		Add <path> to the list of paths searched
			by CPP for #include's.
			(Passed directly to CPP)
    -D<def>		Add this definition during CPP.
			(Passed directly to CPP)
    -U<def>		Remove this definition during CPP.
			(Passed directly to CPP)
    -dumpafter <stage>	Dump intermediate PCN compiled code after <stage>,
			where <stage> is one of:
				all	All stages
				load	After CPP
				user	After user tranformations
					(see the -apply flag)
				vt	After the VT tranformations
				lint	After lint
				basic	After all (basic) transformations
					(This is what you will see when
					 using PDB -- the PCN debugger.)
				demassage  After the code demassager
				encode	After the encoder (i.e. PAM code)
    -fortran		Use Fortran compile when linking
			(Use this when linking in Fortran object code.)
    -g			Compile and link for debugging, including 
			linking with PDB version of the runtime system.
    -pdb		Same as -g
    -link_all		Have the PCN linker link all PCN procedures, instead
			of just those that are called.  This is useful
			if you plan on using dynamic linking during a
			debug cycle.
    -profile		Link with the profiling version of the runtime
			system.  This is necessary to use Gauge or Upshot.
			(This flag can be used in conjunction with -g.)
    -gauge		Same as -profile
    -upshot		Same as -profile
    -nmp <module>	Turn off Gauge profiling capability for <module>.
			If <module> ends in a * such as "prefix_*", then
			all modules with the prefix will have profiling
			capability disabled.
			By default, the following modules will not be
			profiled: vt_* vts boot co_run co_msg
    -no_nmp		Enable Gauge profiling on all modules, including the
			ones that are disabled by default.
    -mm <module>	Set the default main module to be <module>.
    -mp <procedure>	Set the default main procedure to be <procedure>.
    -bm <module>	Set the default boot module to be <module>.
			(This is usually not used by an end user.)
    -bp <procedure>	Set the default boot procedure to be <procedure>.
			(This is usually not used by an end user.)
    -module <name>	Use <name> as the module name of the PCN files that
			are being compiled, instead of the base name
			of the file.
    -u <procedure>	If <procedure> is of the form <mod>:<proc>, then
			this will cause this PCN procedure to be linked in.
			If <procedure> is just a procedure name (without
			a colon in it), this will cause this foreign
			procedure to be linked in.
    -noflags		Do not pass any of the standard (configuration 
			defined) flags to the C or Fortran compiler.
			You should use subsequent -cflags and/or 
			-fflags arguments to pass any flags you want
			to the compilers.
    -cflags <string>	Add <string> to the command line that will be
			passed to all calls to the C compiler.
    -fflags <string>	Add <string> to the command line that will be
			passed to all calls to the Fortran compiler.
    -link_flags <string> Add <string> to the command line that will be
			passed to the C or Fortran compiler when doing
			the final link.
    -n <nodes>		Set the default number of nodes in the executable.
    -heap_size <cells>	Set the default heap size in the executable.
    -heap_inc_proximity <cells>	Set the default heap increment proximity
				in the executable.
    -heap_increment <cells>	Set the default heap increment in the
				executable.
    -heap_free_after_gc <cells>	Set the default heap free after gc value in
				the executable.
    -heap_lowat <cells>	Set the default heap low water mark in the executable.
    -heap_hiwat <cells>	Set the default heap high water mark in the executable.
    -gc_slack <cells>	Set the default heap gc slack value in the executable.
    -irt_size <cells>	Set the default IRT (Incoming Reference Table) size
			in the executable.  This is only used on machines
			that do not support virtual memory.
    -irt_increment <cells>	Set the default IRT increment size in the
				executable.
    -gsq_interval <cells>	Set the default global suspension queue
				reschedule interval in the executable.  This
				specifies how frequently processes on the
				global suspension queue are rescheduled for
				attempted execution.
    -banner <string>	Set <string> to be the banner displayed by
			the runtime system.
    -dg_*_level <level>	Set the linker debugging level, where * is one of:
				g_driver, n_driver, files, proc, table,
				calls, write, code
			(This is usually not used by an end user.)
    -trace <level>	Pass this PTN debugging trace level to PCN compiler.
			(This is usually not used by an end user.)
    -apply <mod>:<proc>	Apply the PTN transformation <mod>:<proc> to
			PCN code as the first transformation stage
			of the PCN compiler.  This is useful in conjuction
			with -load when doing compiler development.
			(This is usually not used by an end user.)
    -load <module>	Dynamically load the listed <module> into the
			compile when running it.
			(This is usually not used by an end user.)
    -novt		Do not run the VT transformations of the PCN compiler.
			(This is usually not used by an end user.)
    -nolint		Do not run lint when compiling PCN code.
			(This is usually not used by an end user.)
    -dont_load_std_pams	Do not link in the the standard set of pam files.
			(This is usually not used by an end user.)
    -save_intermediate_files	Do not remove intermediate files that
				are produced during the compile.
				(This is usually not used by an end user.)
    -nomain		Do not link in the runtime system main() procedure.
			Instead, the user must provide their own.
			(This is usually not used by an end user.)
    -build <path>	Path to the build tree for this architecture.
			(This is usually not used by an end user.)
    -toplevel <path>	Path to the top level of the distribution source.
			(This is usually not used by an end user.)
    -exec_suffix <string>	Suffix to add to all PCN executables when
				invoking them.
			(This is usually not used by an end user.)
    -lib_suffix <string>	Suffix to add to all PCN libraries when
				accessing them.
			(This is usually not used by an end user.)
    -v			Run in verbose mode
    -dryrun		Do a dryrun -- print out everything that will
			happen, but don't actually do anything.
    -h			Print this help screen
ENDOFHELP
}

target_config=$DEFAULT_TARGET_CONFIG

c_file_ctr=0
fortran_file_ctr=0
pcn_file_ctr=0
ptn_file_ctr=0
need_pcn_link=0

pam_load_flag=""
pcncomp_runtime_args="-pcn"
pcnlink_runtime_args="-pcn"

source_files=""
o_files=""
pam_files=""
generated_o_files=""
generated_pam_files=""
generated_cpp_files=""
save_intermediate_files=0

libraries=""
pam_libraries="__dummy_arg_"
default_pam_libraries="-plsys -plstdio -plvt -plrun -plboot"
no_module_profile="-nmp vt_* -nmp vts -nmp boot -nmp co_run -nmp co_msg"

output_filename=""
custom_output_filename=""

cpp_flags=""
pcn_compile_args=""
pcn_link_args=""

user_cflags=""
user_fflags=""
user_link_flags=""

no_flags=0
verbose_flag=0
dryrun_flag=0
pdb_flag=0
profile_flag=0
build_path=""
toplevel_path=""
stop_after_cpp_flag=0
stop_after_compile_flag=0
stop_after_pcnt_flag=0

exec_suffix=""
lib_suffix=""

compile_type="c"

trap interrupt 1 2 15

while [ $# -gt 0 ]
do
    arg=$1
    shift

    case $arg in
        *.c)
	    source_files="$source_files $arg" 
	    c_file_ctr=`$G_EXPR $c_file_ctr + 1`
	    ;;
            
        *.f|*.F)
	    source_files="$source_files $arg" 
	    fortran_file_ctr=`$G_EXPR $fortran_file_ctr + 1`
	    ;;
            
        *.pcn)
	    source_files="$source_files $arg" 
	    pcn_file_ctr=`$G_EXPR $pcn_file_ctr + 1`
	    need_pcn_link=1
	    ;;
            
	*.ptn)    
	    source_files="$source_files $arg" 
	    ptn_file_ctr=`$G_EXPR $ptn_file_ctr + 1`
	    need_pcn_link=1
	    ;;

	*.o)
	    source_files="$source_files $arg" 
	    ;;

	*.pam)
	    source_files="$source_files $arg"
	    need_pcn_link=1
	    ;;

	-pl*|-PL*)
	    pam_libraries="$pam_libraries $arg"
	    source_files="$source_files $arg"
	    ;;

	-nmp)
	    if [ $# -eq 0 ]; then
		echo "$pgm: $arg flag expects a module name" 2>&1
		exit_program 1
	    fi
	    no_module_profile="$no_module_profile $arg $1"
	    shift
	    ;;

	-no_nmp)
	    no_module_profile=""
	    ;;

	-o)
	    if [ $# -eq 0 ]; then
		echo "$pgm: $arg flag expects a filename" 2>&1
		exit_program 1
	    fi
	    output_filename=$1
	    shift
	    ;;

	-trace|-apply|-dumpafter|-module)
	    if [ $# -eq 0 ]; then
		echo "$pgm: $arg flag expects an argument" 2>&1
		exit_program 1
	    fi
	    pcn_compile_args="$pcn_compile_args $arg $1"
	    shift
	    ;;

	-novt|-nolint|-noxforms)
	    pcn_compile_args="$pcn_compile_args $arg"
	    ;;

	-load)
	    if [ $# -eq 0 ]; then
		echo "$pgm: $arg flag expects an argument" 2>&1
		exit_program 1
	    fi
	    if [ "x$pam_load_flag" = "x" ]; then
		pam_load_flag=$1
	    else
		pam_load_flag="${pam_load_flag}:$1"
	    fi
	    shift
	    ;;

	-u|-bm|-bp|-mm|-mp|-banner|-n|-heap_size|-heap_inc_proximity| \
	-heap_increment|-heap_free_after_gc|-heap_lowat|-heap_hiwat| \
	-gc_slack|-irt_size|-irt_increment|-gsq_interval|-dg_*_level)
	    if [ $# -eq 0 ]; then
		echo "$pgm: $arg flag expects an argument" 2>&1
		exit_program 1
	    fi
	    pcn_link_args="$pcn_link_args $arg $1"
	    shift
	    ;;

	-link_all)
	    pcn_link_args="$pcn_link_args $arg"
	    ;;

	-dont_load_std_pams)
	    default_pam_libraries=""
	    ;;

	-save_intermediate_files)
	    save_intermediate_files=1
	    ;;

	-nomain)
	    no_main_flag=1
	    ;;

	-oc)
	    if [ $# -eq 0 ]; then
		echo "$pgm: $arg flag expects a filename" 2>&1
		exit_program 1
	    fi
	    custom_output_filename=$1
	    shift
	    ;;

	-v)
	    verbose_flag=1
	    pcn_link_args="$pcn_link_args $arg"
	    pcn_compile_args="$pcn_compile_args $arg"
	    ;;

	-dryrun)
	    dryrun_flag=1
	    verbose_flag=1
	    ;;

	-fortran)
	    compile_type="fortran"
	    ;;

	-pdb|-g)
	    pdb_flag=1
	    pcn_link_args="$pcn_link_args $arg"
	    ;;

	-profile|-gauge|-upshot)
	    profile_flag=1
	    pcn_link_args="$pcn_link_args -profile"
	    ;;

	-build)
	    if [ $# -eq 0 ]; then
		echo "$pgm: $arg flag expects a filename" 2>&1
		exit_program 1
	    fi
	    build_path=$1
	    shift
	    ;;

	-toplevel)
	    if [ $# -eq 0 ]; then
		echo "$pgm: $arg flag expects a filename" 2>&1
		exit_program 1
	    fi
	    toplevel_path=$1
	    shift
	    ;;

	-exec_suffix)
	    if [ $# -eq 0 ]; then
		echo "$pgm: $arg flag expects a filename" 2>&1
		exit_program 1
	    fi
	    exec_suffix=$1
	    shift
	    ;;

	-lib_suffix)
	    if [ $# -eq 0 ]; then
		echo "$pgm: $arg flag expects a filename" 2>&1
		exit_program 1
	    fi
	    lib_suffix=$1
	    shift
	    ;;

	-E)
	    stop_after_cpp_flag=1
	    cpp_flags="$cpp_flags $arg"
	    ;;

	-c)
	    stop_after_compile_flag=1
	    ;;

	-pcnt)
	    stop_after_pcnt_flag=1
	    ;;

	-I*|-D*|-U*)
	    cpp_flags="$cpp_flags $arg"
	    ;;

	-noflags)
	    no_flags=1
	    ;;

	-cflags)
	    if [ $# -eq 0 ]; then
		echo "$pgm: $arg flag expects an argument" 2>&1
		exit_program 1
	    fi
	    user_cflags="$user_cflags $1"
	    shift
	    ;;

	-fflags)
	    if [ $# -eq 0 ]; then
		echo "$pgm: $arg flag expects an argument" 2>&1
		exit_program 1
	    fi
	    user_fflags="$user_fflags $1"
	    shift
	    ;;

	-link_flags)
	    if [ $# -eq 0 ]; then
		echo "$pgm: $arg flag expects an argument" 2>&1
		exit_program 1
	    fi
	    user_link_flags="$user_link_flags $1"
	    shift
	    ;;

	-target)
	    if [ $# -eq 0 ]; then
		echo "$pgm: $arg flag expects an argument" 2>&1
		exit_program 1
	    fi
	    target_config=$1
	    shift
	    ;;

	-h)
	    print_help
	    exit_program 0
	    ;;

	*.a|-l*|-L*)
	    source_files="$source_files $arg"
	    libraries="$libraries $arg"
	    ;;

	*)
	    echo "Unknown argument $arg"
	    echo "Run pcncomp -h for help on the arguments"
	    exit_program 1
	    ;;

    esac

done    

#
# Consistency checks
#

source_file_ctr=`$G_EXPR $c_file_ctr + $fortran_file_ctr + $pcn_file_ctr + $ptn_file_ctr`

if [ $source_file_ctr -gt 1 -a "x$output_filename" != "x" -a \
	\( $stop_after_compile_flag -ne 0 -o $stop_after_cpp_flag -ne 0 \) ]
then
    echo "$pgm: the -o flag is only valid if there is a single source file"
    exit_program 1
fi


#
# If "-target default" was used, then reset the target_config
#
if [ "$target_config" = "default" ]; then
    target_config=$DEFAULT_TARGET_CONFIG
fi


#
# Load the target-specific configuration file
#

if [ "x$build_path" = "x" ]; then

    target_config_dir="$INSTALL_BASE_DIR/lib/$target_config.cf"

    . "$INSTALL_BASE_DIR/lib/constants"
    . "$target_config_dir/config"
    . "$INSTALL_BASE_DIR/lib/install_vars"

else

    target_config_dir="$toplevel_path/configs/$target_config.cf"

    . "$toplevel_path/support/constants"
    . "$target_config_dir/config"
    . "$toplevel_path/support/install_vars"

fi

if [ $verbose_flag -ne 0 ]; then
    echo "PCN compiler version ${G_VERSION_STR}"
fi

#
# Compile each source file. We do the CPP pass on pcn and ptn files
# ourselves instead of having the PCN compiler do it.
#

if [ $no_flags -eq 0 ]; then
    if [ $pdb_flag -eq 0 ]; then
        cflags=$G_OPT_CFLAGS
        fflags=$G_OPT_FFLAGS
    else
        cflags=$G_DEBUG_CFLAGS
        fflags=$G_DEBUG_FFLAGS
    fi
fi

if [ $pdb_flag -ne 0 ]; then
    cpp_flags="$cpp_flags -DPDB"
fi

if [ $profile_flag -ne 0 ]; then
    cpp_flags="$cpp_flags -DPCN_PROFILE"
fi

cpp_flags="$cpp_flags $G_DEFS -D${G_ARCH} -DPCN_ARCH=\"${G_ARCH}\""

if [ "x$build_path" = "x" ]; then
    cpp_flags="$cpp_flags -I$INSTALL_INC_DIR"
else
    cpp_flags="$cpp_flags -I$build_path/src/include -I."
fi

#
# Always pass the CPP flags to the C compiler
#
cflags="$cflags $cpp_flags"

cflags="$cflags $user_cflags"
fflags="$fflags $user_fflags"

if [ "x$pam_load_flag" = "x" ]; then
    pcncomp_compiler_name="$G_COMPILER_NAME";
else
    pcncomp_compiler_name="${G_COMPILER_NAME}_pdb";
    pcncomp_runtime_args="$pcncomp_runtime_args -load $pam_load_flag"
fi

if [ "x$build_path" = "x" ]; then

    pcncomp="$INSTALL_BIN_DIR/$pcncomp_compiler_name";

else

    pcncomp="$build_path/src/compiler/$pcncomp_compiler_name${exec_suffix}"

fi

pcncomp_flags="$pcn_compile_args"

#
# Tack a -o output_filename flag onto the compile command if we are stopping
# after CPP or the compile. This is valid since we earlier ensured that
# we only have a single source file if we use -o and are stopping after the
# compile or cpp.
#

if [ \( $stop_after_compile_flag -ne 0 -o $stop_after_cpp_flag -ne 0 \) \
    -a "x$output_filename" != "x" ]; then
    output_flag="-o $output_filename"
else
    output_flag=""
fi

pamlib_search_path=""

if [ "x$build_path" = "x" ]; then
    default_pamlib_search_path="$INSTALL_LIB_DIR"
else
    default_pamlib_search_path="$build_path/src/boot \
	$build_path/src/run $build_path/src/vt $build_path/src/stdio \
	$build_path/src/sys $build_path/src/runtime $build_path/src/main"
fi

#
# Loop through the source files. Note that we have put .pam, .o, .a,
# -l, and -L arguments into the source file list as well. This is so that
# we can generate the list of files for the C link step in the correct order.
#
# We tack the list of default pam libs onto the end of the source file list
# so they get passed to both the pcn linker and the final system link.
# 
# Notice we do this even if no pam/pcn/ptn files were passed in on the
# command line. This is so that the default .a files for the various
# default -pl libraries are picked up.
#

source_files="__dummy_arg_ $source_files $default_pam_libraries"

set $source_files

while [ $# -gt 0 ]
do
    source_file=$1
    shift

    case $source_file in

	*.pcn|*.ptn)
	    ptn_flag=""
	    case $source_file in
		*.pcn)
		    file_base=`$G_BASENAME $source_file .pcn`
		    file_ext="pcn"
		    ;;
		*.ptn)
		    file_base=`$G_BASENAME $source_file .ptn`
		    file_ext="ptn"
		    ptn_flag="-ptn "
		    ;;
	    esac
	
	    if [ $stop_after_cpp_flag -ne 0 -a "x$output_filename" != "x" ]
	    then
	        cpp_filename=$output_filename
	    else
	        cpp_filename="/tmp/$file_base.$$.$file_ext"
		generated_cpp_files="$generated_cpp_files $cpp_filename"
	    fi
	
	    if [ $stop_after_compile_flag -ne 0 -a "x$output_filename" != "x" ]
	    then
	        pam_filename=$output_filename
	    else
	        pam_filename="$file_base.pam"
	    fi

	    saved_params="__dummy_arg_ $*"
	    run_command "$G_CPP -DPCN $cpp_flags $source_file" $cpp_filename
	    set $saved_params

	    #
	    # -E functionality:
	    #	if -o not given, cat the generated CPP output to stdout
	    #
	    if [ $stop_after_cpp_flag -ne 0 ]
	    then
		if [ "x$output_filename" = "x" ]; then
		    saved_params="__dummy_arg_ $*"
		    run_command "$G_CAT $cpp_filename"
	    	    set $saved_params
		fi
	    else
		saved_params="__dummy_arg_ $*"
		currently_compiling=$pam_filename
		run_command "$pcncomp $file_base $cpp_filename $pam_filename $source_file $pcncomp_flags $ptn_flag $pcncomp_runtime_args"
		currently_compiling=""
		set $saved_params

		if [ $stop_after_compile_flag -eq 0 ]; then
		    generated_pam_files="$generated_pam_files $pam_filename"
		fi
		pam_files="$pam_files $pam_filename"
	    fi

	    ;;

	*.o|*.a|-l*|-L*)
	    o_files="$o_files $source_file"
	    ;;

	*.pam)
	    pam_files="$pam_files $source_file"
	    ;;

	*.c)
	    if [ "x$output_flag" = "x" ]; then
		o_file=`$G_BASENAME $source_file .c`.o
	    else
		o_file=$output_filename
	    fi

	    saved_params="__dummy_arg_ $*"
	    currently_compiling=$o_file
	    run_command "$G_CC -c $output_flag $cflags $source_file"
	    currently_compiling=""
	    set $saved_params

	    if [ $stop_after_compile_flag -eq 0 ]; then
		generated_o_files="$generated_o_files $o_file"
	    fi
	    o_files="$o_files $o_file"
	    ;;

	*.F)
	    if [ "x$G_FC_RUNS_CPP" = "xyes" ]
	    then
	        if [ "x$output_flag" = "x" ]; then
		    o_file=`$G_BASENAME $source_file .F`.o
	        else
		    o_file=$output_filename
	        fi

	        saved_params="__dummy_arg_ $*"
	        currently_compiling=$o_file
	        run_command "$G_FC -c $output_flag $fflags $source_file"
	        currently_compiling=""
	        set $saved_params

	        if [ $stop_after_compile_flag -eq 0 ]; then
		    generated_o_files="$generated_o_files $o_file"
	        fi
	        o_files="$o_files $o_file"
	    else
	        if [ $stop_after_cpp_flag -ne 0 -a "x$output_filename" != "x" ]
	        then
	            cpp_filename=$output_filename
	        else
		    file_base=`$G_BASENAME $source_file .F`
	            cpp_filename="$file_base.f"
#	            cpp_filename="/tmp/$file_base.$$.f"
		    generated_cpp_files="$generated_cpp_files $cpp_filename"
	        fi

	        if [ "x$output_flag" = "x" ]; then
		    o_file=`$G_BASENAME $source_file .F`.o
	        else
		    o_file=$output_filename
	        fi

	        saved_params="__dummy_arg_ $*"
	        run_command "$G_CPP -P $cpp_flags $source_file" $cpp_filename
	        set $saved_params

	        #
	        # -E functionality:
	        #	if -o not given, cat the generated CPP output to stdout
	        #
	        if [ $stop_after_cpp_flag -ne 0 ]
	        then
		    if [ "x$output_filename" = "x" ]; then
		        saved_params="__dummy_arg_ $*"
		        run_command "$G_CAT $cpp_filename"
	    	        set $saved_params
		    fi
	        else
	            saved_params="__dummy_arg_ $*"
	            currently_compiling=$o_file
	            run_command "$G_FC -c $output_flag $fflags $cpp_filename -o $o_file"
	            currently_compiling=""
	            set $saved_params

	            if [ $stop_after_compile_flag -eq 0 ]; then
		        generated_o_files="$generated_o_files $o_file"
	            fi
	            o_files="$o_files $o_file"
	        fi
            fi
	    ;;

	*.f)
	    if [ "x$output_flag" = "x" ]; then
		o_file=`$G_BASENAME $source_file .f`.o
	    else
		o_file=$output_filename
	    fi

	    saved_params="__dummy_arg_ $*"
	    currently_compiling=$o_file
	    run_command "$G_FC -c $output_flag $fflags $source_file"
	    currently_compiling=""
	    set $saved_params

	    if [ $stop_after_compile_flag -eq 0 ]; then
		generated_o_files="$generated_o_files $o_file"
	    fi
	    o_files="$o_files $o_file"
	    ;;

	-pl*)
	    if [ $stop_after_compile_flag -eq 0 ]; then
		libname=`expr $source_file : '-pl\(.*\)'`
		saved_params="__dummy_arg_ $*"
		#
		# Place INSTALL_LIB_DIR on the end so that user
		# -PL options take precedence.
		#
		set $pamlib_search_path $default_pamlib_search_path
		pam_libname="lib$libname${lib_suffix}.pam"
		obj_libname="lib${libname}${lib_suffix}_${target_config}.a"
		pamlib_found=0
		objlib_found=0
		while [ $# -gt 0 -a $pamlib_found -eq 0 -a $objlib_found -eq 0 ]
		do

		    if [ $pamlib_found -eq 0 -a -f "$1/$pam_libname" ]; then
			pamlib_found=1
			pam_files="$pam_files $1/$pam_libname"
		    fi

		    if [ $objlib_found -eq 0 -a -f "$1/$obj_libname" ]; then
			objlib_found=1
			libraries="$libraries $1/$obj_libname"
			o_files="$o_files $1/$obj_libname"
		    fi
		    shift
		done
	
		if [ $pamlib_found -eq 0 -a $objlib_found -eq 0 ]; then
		    echo "$pgm: Could find neither pam nor object library for $source_file"
		    if [ "x$build_path" = "x" ]; then
			exit_program 1
		    fi
		fi
		
		set $saved_params
	    fi
	    ;;

	-PL*)
	    dirname=`expr $source_file : '-PL\(.*\)'`
	    pamlib_search_path="$pamlib_search_path $dirname"
	    ;;

	__dummy_arg_)
	    ;;
	*)
	    echo "Got default '$source_file'"
	    ;;

    esac

done

if [ $stop_after_compile_flag -ne 0 -o $stop_after_cpp_flag -ne 0 ]; then
    exit_program 0
fi

if [ $need_pcn_link -ne 0 ]; then
   
    #
    # Determine the name of the pcnt file
    #
    
    pcn_link_args="$pcn_link_args $no_module_profile"

    if [ "x$custom_output_filename" != "x" ]; then
        pcnt_filename=$custom_output_filename
    elif [ $stop_after_pcnt_flag -ne 0 -a "x$output_filename" != "x" ]; then
        pcnt_filename=$output_filename
    else
        pcnt_filename="/tmp/pcnt_$$.c"
	generated_c_files="$generated_c_files $pcnt_filename"
    fi
    
    if [ `$G_EXPR $pcnt_filename : '.*\.c$'` -eq 0 ]; then
        pcnt_filename="$pcnt_filename.c"
    fi

    if [ "x$build_path" = "x" ]; then
	pcnlink="$INSTALL_BIN_DIR/$G_LINKER_NAME"
    else
	pcnlink="$build_path/src/linker/$G_LINKER_NAME${exec_suffix}"
    fi

    if [ "x$G_STRIP_TRAILING_UNDERSCORE" = "xyes" ]; then
        pcn_link_args="$pcn_link_args -stu"
    fi

    currently_compiling=$pcnt_filename
    run_command "$pcnlink $pcnt_filename $pcn_link_args $pam_files $pcnlink_runtime_args"
    currently_compiling=""

    if [ $stop_after_pcnt_flag -ne 0 ]; then
	exit_program 0
    fi

    #
    # Now compile the pcnt file
    #
    
    run_command "$G_CC -c $cflags $pcnt_filename"
    
    pcnt_ofile=`basename $pcnt_filename .c`.o
    o_files="$pcnt_ofile $o_files"
    generated_o_files="$generated_o_files $pcnt_ofile"
fi    

#
# And link everything.
#

runtime_lib="libpcn";

if [ $profile_flag -eq 0 ]; then
    runtime_lib="${runtime_lib}_np"
else
    runtime_lib="${runtime_lib}_p"
fi

if [ $pdb_flag -eq 0 ]; then
    runtime_lib="${runtime_lib}_nd"
else
    runtime_lib="${runtime_lib}_d"
fi

runtime_lib="${runtime_lib}${lib_suffix}_${target_config}.a";

if [ $compile_type = "c" ]; then
    main_lib="libcmain${lib_suffix}_${target_config}.a"
elif [ $compile_type = "fortran" ]; then
    main_lib="libfmain${lib_suffix}_${target_config}.a"
else
    echo "Invalid compile type '$compile_type'" 1>&2
    exit_program 1
fi

set $pamlib_search_path $default_pamlib_search_path

runtime_lib_pathname=""
main_lib_pathname=""

while [ $# -gt 0 ]
do
    if [ "x$runtime_lib_pathname" = "x" -a -f "$1/$runtime_lib" ]; then
	runtime_lib_pathname="$1/$runtime_lib"
    fi

    if [ "x$main_lib_pathname" = "x" -a -f "$1/$main_lib" ]; then
	main_lib_pathname="$1/$main_lib"
    fi
    shift
done

if [ "x$runtime_lib_pathname" = "x" ]; then
    echo "$pgm: Cannot find runtime library $runtime_lib" 1>&2
#    exit_program 1
fi

if [ "x$main_lib_pathname" = "x" ]; then
    echo "$pgm: Cannot find main library $main_lib" 1>&2
#    exit_program 1
fi

o_files="$o_files $runtime_lib_pathname $main_lib_pathname"

if [ "x$output_filename" = "x" ]; then
    output_filename="a.out"
fi

if [ $compile_type = "c" ]; then

    run_command "$G_CC -o $output_filename $cflags $G_LDFLAGS $user_link_flags $o_files $G_CLIBS "

elif [ $compile_type = "fortran" ]; then

    run_command "$G_FC -o $output_filename $fflags $G_LDFLAGS $user_link_flags $o_files $G_FLIBS"

else
    echo "Unknown compile type '$compile_type'" 1>&2
    exit_program 1
fi

exit_program 0
