#!/bin/sh
#
#  Copyright (c) 2008, 2009, 2010, 2011
#    Jonathan Schleifer <js@webkeks.org>
#
#  All rights reserved.
#
#  This file is part of ObjFW. It may be distributed under the terms of the
#  Q Public License 1.0, which can be found in the file LICENSE.QPL included in
#  the packaging of this file.
#
#  Alternatively, it may be distributed under the terms of the GNU General
#  Public License, either version 2 or 3, which can be found in the file
#  LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
#  file.
#

if test x"$(basename $0)" != x"objfw-compile"; then
	OBJFW_CONFIG="$(basename $0 | sed 's/-objfw-compile$//')-objfw-config"
else
	OBJFW_CONFIG="objfw-config"
fi

if ! which $OBJFW_CONFIG 2>&1 >/dev/null; then
	echo "You need to have ObjFW and $OBJFW_CONFIG installed!"
	exit 1
fi

CPPFLAGS="$CPPFLAGS $($OBJFW_CONFIG --cppflags)"
OBJC="$($OBJFW_CONFIG --objc)"
OBJCFLAGS="$OBJCFLAGS $($OBJFW_CONFIG --objcflags)"
LIBS="$LIBS $($OBJFW_CONFIG --libs)"
LDFLAGS="$LDFLAGS $($OBJFW_CONFIG --ldflags --rpath)"

if test x"$1" = "x"; then
	echo "Syntax: objfw-compile -o outname source1.m source2.m ..."
	exit 1
fi

status_compiling() {
	printf "\033[K\033[0;33mCompiling \033[1;33m$1\033[0;33m...\033[0m\r"
}
status_compiled() {
	printf "\033[K\033[0;32mSuccessfully compiled \033[1;32m$1\033[0;32m."
	printf "\033[0m\n"
}
status_compile_failed() {
	printf "\033[K\033[0;31mFailed to compile \033[1;31m$1\033[0;31m!"
	printf "\033[0m\n"
	exit $2
}
status_linking() {
	printf "\033[K\033[0;33mLinking \033[1;33m$1\033[0;33m...\033[0m\r"
}
status_linked() {
	printf "\033[K\033[0;32mSuccessfully linked \033[1;32m$1\033[0;32m."
	printf "\033[0m\n"
}
status_link_failed() {
	printf "\033[K\033[0;31mFailed to link \033[1;31m$1\033[0;31m!"
	printf "\033[0m\n"
	exit $2
}

srcs=""
out=""
objs=""
link="no"
link_stdcpp="no"
lib="no"
out_prefix=""
out_suffix=""

while test x"$1" != "x"; do
	case "$1" in
		-o|--out)
			shift
			out="$1"
			;;
		--lib)
			if test x"$plugin" = x"yes"; then
				echo "You can't use --lib and --plugin!"
				exit 1
			fi

			shift

			if ! echo "$1" | grep "^[0-9]\+\.[0-9]\+" >/dev/null
			then
				echo "$1 is not a valid library version!"
				exit 1
			fi

			export LIB_MAJOR="${1%.*}"
			export LIB_MINOR="${1#*.}"

			lib="yes"
			OBJCFLAGS="$OBJCFLAGS $($OBJFW_CONFIG --lib-cflags)"
			out_prefix="$($OBJFW_CONFIG --lib-prefix)"
			out_suffix="$($OBJFW_CONFIG --lib-suffix)"
			;;
		-D)
			shift
			CPPFLAGS="$CPPFLAGS -D$1"
			;;
		-D*)
			CPPFLAGS="$CPPFLAGS $1"
			;;
		-framework)
			shift
			LIBS="$LIBS -framework $1"
			;;
		-g*)
			OBJCFLAGS="$OBJCFLAGS $1"
			;;
		-I)
			shift
			CPPFLAGS="$CPPFLAGS -I$1"
			;;
		-I*)
			CPPFLAGS="$CPPFLAGS $1"
			;;
		-l)
			shift
			LIBS="$LIBS -l$1"
			;;
		-l*)
			LIBS="$LIBS $1"
			;;
		-L)
			shift
			LIBS="$LIBS -L$1"
			;;
		-L*)
			LIBS="$LIBS $1"
			;;
		-O*)
			OBJCFLAGS="$OBJCFLAGS $1"
			;;
		--plugin)
			if test x"$lib" = x"yes"; then
				echo "You can't use --lib and --plugin!"
				exit 1
			fi

			plugin="yes"
			OBJCFLAGS="$OBJCFLAGS $($OBJFW_CONFIG --plugin-cflags)"
			LDFLAGS="$LDFLAGS $($OBJFW_CONFIG --plugin-ldflags)"
			out_suffix="$($OBJFW_CONFIG --plugin-suffix)"
			;;
		-Wl,*)
			LDFLAGS="$LDFLAGS $1"
			;;
		-W*)
			OBJCFLAGS="$OBJCFLAGS $1"
			;;
		-*)
			echo "Unknown option: $1"
			exit 1
			;;
		*.m)
			srcs="$srcs $1"
			;;
		*.mm)
			srcs="$srcs $1"
			link_stdcpp="yes"
			;;
		*)
			echo "Only .m and .mm files can be compiled!" 1>&2
			exit 1
			;;
	esac

	shift
done

if test x"$out" = x""; then
	echo "No output name specified! Use -o or --out!"
	exit 1
fi

for i in $srcs; do
	case $i in
		*.m)
			if test x"$lib" = x"yes"; then
				obj="${i%.m}.lib.o"
			elif test x"$plugin" = x"yes"; then
				obj="${i%.m}.plugin.o"
			else
				obj="${i%.m}.o"
			fi
			;;
		*.mm)
			if test x"$lib" = x"yes"; then
				obj="${i%.mm}.lib.o"
			elif test x"$plugin" = x"yes"; then
				obj="${i%.mm}.plugin.o"
			else
				obj="${i%.mm}.o"
			fi
			;;
	esac
	objs="$objs $obj"
	build="no"
	deps=$($OBJC -E -M $CPPFLAGS $i | sed 's/.*: //' | sed 's/\\//g')

	if test -f "$obj"; then
		for dep in $deps; do
			test "$dep" -nt $obj && build="yes"
		done
	else
		build="yes"
	fi

	if test x"$build" = x"yes"; then
		link="yes"
		status_compiling $i
		$OBJC $CPPFLAGS $OBJCFLAGS -c -o $obj $i || \
			status_compile_failed $i $?
		status_compiled $i
	fi
done

test x"$lib" = x"no" -a x"$plugin" = x"no" && \
	out_suffix="$($OBJFW_CONFIG --prog-suffix)"

test x"$link_stdcpp" = x"yes" && LIBS="$LIBS -lstdc++"

if test x"$lib" = x"yes"; then
	export LIB="$out_prefix$out$out_suffix"
	LDFLAGS="$LDFLAGS $($OBJFW_CONFIG --lib-ldflags)"
fi

if test ! -f "$out_prefix$out$out_suffix" -o x"$link" = x"yes"; then
	status_linking $out_prefix$out$out_suffix
	$OBJC -o $out_prefix$out$out_suffix $objs $LIBS $LDFLAGS || \
		status_link_failed $out $?
	status_linked $out_prefix$out$out_suffix
fi
