#!/bin/sh
# check-each-file
# Used to narrow down a miscompilation to one .o file from a list. Please read
# the usage procedure, below, for command-line syntax (or run it with --help).
# This script depends on the llvm-native-gcc script.

if [ x$1 = x--make-linker-script ]
then
	program=$2
	linker=./link-$program
	echo "Building $program with llvm-native-gcc"
	rm -f $program
	gmake -e $program CC=llvm-native-gcc CXX=llvm-native-gxx
	echo "Erasing $program and re-linking it" 
	rm -f $program
	echo "rm -f $program" > $linker
	gmake -n $program >> $linker
	chmod 755 $linker
	echo "Linker script created in $linker; testing it out"
	output=`./$linker 2>&1`
	case "$output" in
		*undefined*reference*__main*) 
			echo "$program appears to need a dummy __main function; adding one"
			echo "void __main () { }" > __main.c
			gcc -c __main.c
			echo "Done; rebuilding $linker"
			echo "rm -f $program" > $linker
			gmake -n $program 2>&1 | sed '/gcc/s/$/__main.o/' >> $linker
			./$linker > /dev/null 2>&1
			if [ ! -x $program ]
			then
				echo "WARNING: linker script didn't work"
			fi
			;;
		*)
			if [ ! -x $program ]
			then
				echo "WARNING: linker script didn't work"
			fi
			;;
	esac
	echo "Linker script created in $linker; please check it manually"
	exit 0
fi

checkfiles="$1"
program="$2"
linker="$3"
checker="$4"

usage () {
	myname=`basename $0`
	echo "$myname --make-linker-script PROGRAM"
	echo "$myname OBJECTS-FILE PROGRAM LINKER CHECKER"
	echo ""
	echo "OBJECTS-FILE is a text file containing the names of all the .o files"
	echo "PROGRAM is the name of the executable under test"
	echo "(there must also exist a Makefile in the current directory which"
	echo "has PROGRAM as a target)"
	echo "LINKER is the script that builds PROGRAM; try --make-linker-script" 
	echo "to automatically generate it"
	echo "CHECKER is the script that exits 0 if PROGRAM is ok, 1 if it is not OK"
	echo "(LINKER and CHECKER must be in your PATH, or you should specify ./)"
	echo ""
	echo "Bugs to <gaeke@uiuc.edu>."
	exit 1
}

if [ x$1 = x--help ]
then
	usage
fi

if [ -z "$checkfiles" ]
then
	echo "ERROR: Must specify name of file w/ list of objects as 1st arg."
	echo "(got \"$checkfiles\")"
	usage
fi
if [ ! -f "$checkfiles" ]
then
	echo "ERROR: $checkfiles not found"
	usage
fi
if [ -z "$program" ]
then
	echo "ERROR: Must specify name of program as 2nd arg."
	usage
fi
if [ -z "$linker" ]
then
	echo "ERROR: Must specify name of link script as 3rd arg."
	usage
fi
if [ ! -x "$linker" ]
then
	echo "ERROR: $linker not found or not executable"
	echo "You may wish to try: $0 --make-linker-script $program"
	usage
fi
if [ -z "$checker" ]
then
	echo "ERROR: Must specify name of $program check script as 3rd arg."
	usage
fi
if [ ! -x "$checker" ]
then
	echo "ERROR: $checker not found or not executable"
	usage
fi

files=`cat $checkfiles`
echo "Recompiling everything with llvm-native-gcc"
for f in $files
do
	rm -f $f
	gmake $f CC=llvm-native-gcc CXX=llvm-native-gxx
done
rm -f $program
$linker
if $checker
then
	echo "Sorry, I can't help you, $program is OK when compiled with llvm-native-gcc"
	exit 1
fi
for f in $files
do
	echo Trying to compile $f with native gcc and rebuild $program
	mv ${f} ${f}__OLD__
	gmake ${f} CC=gcc > /dev/null 2>&1
	$linker
	echo Checking validity of new $program
	if $checker
	then
		echo Program is OK
		okfiles="$okfiles $f"
	else
		echo Program is not OK
		notokfiles="$notokfiles $f"
	fi
	mv ${f}__OLD__ ${f}
done
echo ""
echo "Program is OK when these files are recompiled with native gcc: "
echo "$okfiles"
echo ""
echo "Program is not OK when these files are recompiled with native gcc: "
echo "$notokfiles"
echo ""
exit 0