#! /bin/bash

# Compiles software necessary for eMoviX

echo "

This script will compile software necessary for eMoviX. 
It needs the unpacked sources in /home/movix/work, you can get them with
'download-sources; unpack-sources'.
This can take a couple of hours even on a fast computer!

Press CTRL+C now if you don't want to start now.
"

# Constants and setup
targetname=emovix
workdir=/home/movix/work
configdir=$workdir/config
sourcedir=$workdir/source
targetdir=$workdir/target/$targetname

# ------------- No need to change anything below ------------
# Work begins here

compileKernel=y
compileAlsa=y
compileBusybox=y
compileLirc=y
compileDevfsd=n
compileEm8300=y
compileAalib=y
compileMplayer=y
compilePerl=n
compileSdl=y
compileTvout=y
compileOnly=0
optimizeSize=n
disableWin=n
withDvd=n
remoteType=any	# default lirc remote type
while getopts ":hkKaAbBcClLdDeEmMpPsStTr:xXv:Wz" opt; do
	case $opt in

		# help
		h )	echo "Usage:
  -h      this help

  -k -K   compile/don't compile the kernel (default: compile)
  -a -A   compile/don't compile ALSA (default: compile)
  -b -B   compile/don't compile busybox (default: compile)
  -c -C   compile/don't compile aalib (default: compile)
  -l -L   compile/don't compile LIRC (default: compile)
  -d -D   compile/don't compile devfsd (default: don't compile)
  -e -E   compile/don't compile EM8300/DXR (default: compile)
  -m -M   compile/don't compile MPlayer (default: compile)
  -p -P   compile/don't compile perl (default: don't compile)
  -s -S   compile/don't compile SDL (default: compile)
  -t -T   compile/don't compile TV out utilities (default: compile)

  -x      always 'make clean' to be sure that everything gets recompiled

  -r type LIRC remote type (e.g. hauppauge, any, none etc.)

  -X      use the bundled DVD library of MPlayer (if legal in your country)
  -v foo  leave out MPlayer feature(s), e.g. 
                    -v aa,sdl,dxr,cdparanoia,lirc,freetype,vorbis
  -W      disable Windows/Real/QT DLL support
  -z      optimize MPlayer for size instead of speed
   		"
		exit

		;;
		# compile the kernel
		k ) 	compileKernel=y
			compileOnly=k
		;;
		# don't compile the kernel
		K )	compileKernel=n
		;;

		# compile ALSA
		a )	compileAlsa=y
			compileOnly=a
		;;
		# don't compile ALSA
		A )	compileAlsa=n
		;;

		# compile busybox
		b )	compileBusybox=y
			compileOnly=b
		;;
		# don't compile busybox
		B )	compileBusybox=n
		;;

		# compile aalib
		c )	compileAalib=y
			compileOnly=c
		;;
		# don't compile aalib
		C )	compileAalib=n
		;;

		# compile LIRC
		l )	compileLirc=y
			compileOnly=l
		;;
		# don't compile LIRC
		L )	compileLirc=n
		;;

		# compile devfsd
		d )	compileDevfsd=y
			compileOnly=d
		;;
		# don't compile devfsd
		D )	compileDevfsd=n
		;;

		# compile EM8300
		e )	compileEm8300=y
			compileOnly=e
		;;
		# don't compile EM8300
		E )	compileEm8300=n
		;;

		# compile MPlayer
		m )	compileMplayer=y
			compileOnly=m
		;;
		# don't compile MPlayer
		M )	compileMplayer=n
		;;

		# compile perl
		p )	compilePerl=y
			compileOnly=p
		;;
		# don't compile perl
		P )	compilePerl=n
		;;

		# compile SDL
		s )	compileSdl=y
			compileOnly=s
		;;
		# don't compile SDL
		S )	compileSdl=n
		;;

		# compile TV-out stuff
		t )	compileTvout=y
			compileOnly=t
		;;
		# don't compile TV-out stuff
		T )	compileTvout=n
		;;

		# leave out modules
		v )	withoutModules="$OPTARG"
		;;

		# disable Win32/Real/QT DLL support
		W )	disableWin=y
		;;

		# make clean always
		x )	makeClean=y
		;;

		# use MPlayer's bundled DVD library
		X )	withDvd=y
		;;

		# optimize MPlayer for size instead of speed
		z )	optimizeSize=y
		;;

		# Remote type for the LIRC module compilation
		r )	remoteType="$OPTARG"
		;;
	esac
	#shift
done

# If one program is selected for compilation, unset the others
test "$compileOnly" != "0" && test "$compileOnly" != "k" && compileKernel=n
test "$compileOnly" != "0" && test "$compileOnly" != "a" && compileAlsa=n
test "$compileOnly" != "0" && test "$compileOnly" != "b" && compileBusybox=n
test "$compileOnly" != "0" && test "$compileOnly" != "c" && compileAalib=n
test "$compileOnly" != "0" && test "$compileOnly" != "l" && compileLirc=n
test "$compileOnly" != "0" && test "$compileOnly" != "d" && compileDevfsd=n
test "$compileOnly" != "0" && test "$compileOnly" != "e" && compileEm8300=n
test "$compileOnly" != "0" && test "$compileOnly" != "m" && compileMplayer=n
test "$compileOnly" != "0" && test "$compileOnly" != "p" && compilePerl=n
test "$compileOnly" != "0" && test "$compileOnly" != "s" && compileSdl=n
test "$compileOnly" != "0" && test "$compileOnly" != "t" && compileTvout=n

for line in "k-Kernel-the kernel" \
		a-Alsa-ALSA \
		b-Busybox-busybox \
		c-Aalib-aalib \
		"l-Lirc-LIRC (remote type: $remoteType)" \
		d-Devfsd-devfsd \
		"e-Em8300-EM8300/DXR" \
		m-Mplayer-MPlayer \
		s-Sdl-SDL \
		"t-Tvout-TV out utilities"; do
	
	code=`echo "$line" | perl -pwe 's/^(.)-(.+)-(.+)$/$1/'`
	ucode=`echo $code | tr a-z A-Z`

	varname=`echo "$line" | perl -pwe 's/^(.)-(.+)-(.+)$/$2/'`
	text=`echo "$line" | perl -pwe 's/^(.)-(.+)-(.+)$/$3/'`

	varvalue=`set | grep "^compile$varname=" | sed 's/^.*=//'`

	if [ "$varvalue" == "y" ]; then
		echo "Will compile $text, use -$ucode to disable"
	else
		echo "Won't compile $text, use -$code to enable"
	fi
	
done

# Give the user some time 
sleep 4

pushd $sourcedir

# Check if compiler environment variables are set explicitly
if [ "X$CC" != "X" ]; then
	SETCC="CC=$CC"
	# As the compiler was possibly changed, make sure we recompile everything
	makeClean=y
else
	SETCC=""
fi

if [ "X$CPP" != "X" ]; then
	SETCPP="CPP=$CPP"
	# As the compiler was possibly changed, make sure we recompile everything
	makeClean=y
else
	SETCPP=""
fi

mkdir -p $targetdir/lib/modules $targetdir/usr/bin $targetdir/usr/sbin

if [ "$compileKernel" = "y" ]; then
	# -------------- Patch the kernel ------------------------
	echo "Applying kernel patches..."
	for patch in kernel-patches/*; do
		if [ -e "$patch" ]; then
		# this is a real file (and not the * from an empty dir)
			if [ -e "$patch.did" ]; then
			# Patch already applied
				echo "$patch was already applied"
			else
				# Normalize the kernel directory in patches
				# (it is frequently given with a version number)
				#ssed -i 's!^+++ linux-[^/]*/!+++ linux/!' "$patch"
				
				cd linux
				patch -p1 < "../$patch" || exit 1
				cd ..
				touch "$patch.did"
			fi
		fi
	done

	# This is dumb but it works
	rm -f kernel-patches/*.did.did

	# -------------- Compile the kernel ------------------------
	pushd linux
	cp $configdir/kernelConfig.$targetname .config
	# We use the supplied kernelConfig.emovix file. If the unpacked kernel is newer,
	# make oldconfig will just ask for the new options.
	make oldconfig || exit 1
	
	# Add the name of this software to the kernel name
	#perl -pw -i.bak -e "s/^EXTRAVERSION.+$/EXTRAVERSION = $targetname/" Makefile
	
	make $SETCC $SETCPP dep || exit 1
	test "X$makeClean" = "Xy" && make clean #|| exit 1
	make $SETCC $SETCPP bzImage || exit 1
	make $SETCC $SETCPP modules || exit 1
	make $SETCC $SETCPP modules_install INSTALL_MOD_PATH=$targetdir || exit 1
	cp arch/i386/boot/bzImage $targetdir/vmlinuz

	# Let's hope that this will give us the correct module dir... (probably the highest version number)
	kernelver=`ls $targetdir/lib/modules/ | egrep "^[0-9.]+($targetname)?$" | sort | tail -1`
	moddir="$targetdir/lib/modules/$kernelver"

	popd


	# --------------- Compile the bootsplash utilities --------------
	if ! [ -e splashutils/splashutilsPatch.did ]; then
		patch -p0 < $configdir/splashutilsPatch
		touch splashutils/splashutilsPatch.did
	fi
	pushd splashutils
	test "X$makeClean" = "Xy" && make clean
	make $SETCC $SETCPP all || exit 1
	cp fbresolution getkey progress splash $targetdir/usr/sbin
	cp fbtruetype/fbtruetype $targetdir/usr/sbin

	popd
fi

# Let's hope that this will give us the correct module dir... (probably the highest version number)
kernelver=`ls $targetdir/lib/modules/ | egrep "^[0-9.]+($targetname)?$" | sort | tail -1`
moddir="$targetdir/lib/modules/$kernelver"

# --------------- ALSA -----------------------------------
if [ "$compileAlsa" = "y" ]; then
	# ------ drivers -----------
	pushd alsa
	test "X$makeClean" = "Xy" && make clean
	cp $configdir/alsaConfig.$targetname .
	# Insert the correct kernel module directory into the ALSA mod-install path
	#perl -pw -i.ori -e "s:--with-moddir=[a-zA-Z0-9._/-]+:--with-moddir=$moddir/misc:" alsaConfig.$targetname
	sh alsaConfig.$targetname

	make || exit 1
	
	make prefix=$targetdir/alsa moddir=$moddir/kernel/drivers/sound install-modules || exit 1

	# Remove modules that are unnecessary or even contraproductive
	rm $moddir/kernel/drivers/sound/snd-bt87x.o
	
	popd

	# ------ lib -----------
	pushd alsa-lib
	test "X$makeClean" = "Xy" && make clean
	CFLAGS="-Os" ./configure 

	make || exit 1
	make prefix=$targetdir/alsa exec_prefix=$targetdir/alsa install || exit 1
	strip $targetdir/alsa/lib/libasound.so
	popd

	# ------ utils -----------
	pushd alsa-utils
	test "X$makeClean" = "Xy" && make clean
	CFLAGS="-Os" ./configure --with-alsa-inc-prefix=$targetdir/alsa/include 

	# Optimize for size, not speed
	perl -pw -i.ori -e 's/^ -O[0-9] / -Os /' Makefile

	make || exit 1
	make prefix=$targetdir/alsa install || exit 1
	strip $targetdir/alsa/bin/* $targetdir/alsa/sbin/*
	popd
fi

# --------------- LIRC -----------------------------------
if [ "$compileLirc" = "y" ]; then
	pushd lirc
	test "X$makeClean" = "Xy" && make clean

	./configure --with-kerneldir=$sourcedir/linux --with-moduledir=$moddir/misc --sysconfdir=/etc --with-driver=$remoteType --without-x
	# Alter makefiles so they don't try to create the device node
	find . -name Makefile | xargs perl -pw -i.ori -e 's!/bin/mknod!/bin/echo!'      
	# Alter makefiles for compilation with -Os and without debugging symbols
	find . -name Makefile | xargs perl -pw -i.ori -e 's!CFLAGS *= *-O2 -g!CFLAGS = -Os!'      
	make || exit 1

	# Compile and install some kernel modules
	for kernelmod in lirc_bt829 lirc_gpio lirc_i2c lirc_dev; do
		pushd drivers/$kernelmod
		test "X$makeClean" = "Xy" && make clean
		make || exit 1
		make install  || exit 1
		popd
	done

	make prefix=$targetdir/lirc sysconfdir=$targetdir/lirc/etc install || exit 1
	strip $targetdir/lirc/bin/* $targetdir/lirc/sbin/* $targetdir/lirc/lib/liblirc_client*.so

	# Another compilation round for the serial kernel module
	./configure --with-kerneldir=$sourcedir/linux --with-moduledir=$moddir/misc --sysconfdir=/etc --with-driver=serial --without-x
	# Alter makefiles so they don't try to create the device node
	find . -name Makefile | xargs perl -pw -i.ori -e 's!/bin/mknod!/bin/echo!'      
	# Alter makefiles for compilation with -Os and without debugging symbols
	find . -name Makefile | xargs perl -pw -i.ori -e 's!CFLAGS *= *-O2 -g!CFLAGS = -Os!'      
	pushd drivers/lirc_serial
	make || exit 1
	make install  || exit 1
	popd

	# Another compilation round for the sir kernel module
	./configure --with-kerneldir=$sourcedir/linux --with-moduledir=$moddir/misc --sysconfdir=/etc --with-driver=sir --without-x
	# Alter makefiles so they don't try to create the device node
	find . -name Makefile | xargs perl -pw -i.ori -e 's!/bin/mknod!/bin/echo!'      
	# Alter makefiles for compilation with -Os and without debugging symbols
	find . -name Makefile | xargs perl -pw -i.ori -e 's!CFLAGS *= *-O2 -g!CFLAGS = -Os!'      
	pushd drivers/lirc_sir
	make || exit 1
	make install  || exit 1
	popd

	popd
fi

# --------------- DXR -----------------------------------
if [ "$compileEm8300" = "y" ]; then
	pushd em8300
	test "X$makeClean" = "Xy" && make clean
	test "X$makeClean" = "Xy" && rm -f config.cache
	./configure --with-kerneldir=$sourcedir/linux --with-moduledir=$moddir/misc --without-x --without-gtk --disable-gtk --with-gtk-config=no --disable-gtktest
	# Alter makefiles so they don't try to uninstall headers from the wrong place
	find . -name Makefile | xargs perl -pw -i.ori -e 's!( |\t)/usr/include!\$\{prefix\}/include!'      
	# Alter makefiles for compilation without -g but with -Os
	find . -name Makefile | xargs perl -pw -i.ori -e 's! -g *-O2 ! -Os !'
	make || exit 1
	echo "make ready"
	make prefix=$targetdir/em8300 install || exit 1
	echo "make install ready"
	strip $targetdir/em8300/bin/* $targetdir/em8300/lib/*.so

	# Separate building of kernel modules
	pushd modules
	# Write the kernel location into the makefile
	perl -pw -i.ori -e \
		"s!^KERNEL_LOCATION.+\$!KERNEL_LOCATION=$sourcedir/linux!" \
		Makefile
	make
	cp -v em8300.o adv717x.o bt865.o $moddir/kernel/drivers/video

	popd
	# modules

	popd
fi

# --------------- Busybox -----------------------------------
if [ "$compileBusybox" = "y" ]; then
	pushd busybox
	test "X$makeClean" = "Xy" && make clean
	cp $configdir/busyboxConfig.$targetname .config
	make $SETCC $SETCPP dep || exit 1
	make $SETCC $SETCPP || exit 1
	make PREFIX=$targetdir/busybox install || exit 1
	popd
fi

# --------------- AAlib -----------------------------------
if [ "$compileAalib" = "y" ]; then
	pushd aalib
	test "X$makeClean" = "Xy" && make clean
	CFLAGS="-Os" ./configure --with-x11-driver=no --with-slang-driver=no \
		--without-gpm || exit 1
	make || exit 1
	make prefix=$targetdir/aalib install || exit 1
	strip $targetdir/aalib/lib/libaa*
	popd
fi

# --------------- SDL -----------------------------------
if [ "$compileSdl" = "y" ]; then
	pushd sdl

	test "X$makeClean" = "Xy" && make clean
	# make clean seems to forget config.cache
	test "X$makeClean" = "Xy" && rm -f config.cache

	cp $configdir/sdlConfig.$targetname .
	CFLAGS=-Os sh sdlConfig.$targetname

	#Need to apply patches?
	if [ -e $configdir/sdlPatch1 ]; then
		cp $configdir/sdlPatch? .
		for patch in sdlPatch? ; do
			if [ -e $patch.did ]; then
				echo "Patch $patch already applied."
			else
				echo "Applying patch $patch..."
				patch -p1 < $patch || exit 1
				touch $patch.did
			fi
		done
	fi

	make || exit 1
	make prefix=$targetdir/sdl install || exit 1
	strip $targetdir/sdl/lib/*.so

	# Insert the real directory into the sdl-config script
	perl -pw -i.ori \
		-e "s#^prefix=/usr/local#prefix=$targetdir/sdl#" \
		$targetdir/sdl/bin/sdl-config

	popd
fi

# --------------- perl -----------------------------------
if [ "$compilePerl" = "y" ]; then
	pushd perl
	test "X$makeClean" = "Xy" && make clean
	cp $configdir/perlConfig.$targetname config.sh
	sh Configure -des || exit 1
	make || exit 1
	make install || exit 1
	popd
fi

if [ "$compileTvout" = "y" ]; then
	# --------------- Matroxset -----------------------------------
	pushd matroxset
	test "X$makeClean" = "Xy" && make clean
	#currently, this doesn't work, so we leave the precompiled binary
	#make $SETCC $SETCPP CFLAGS="-Os -W -Wall" || exit 1
	strip matroxset
	cp matroxset $targetdir/usr/bin
	popd

	# --------------- ATItvout -----------------------------------
	pushd atitvout
	test "X$makeClean" = "Xy" && make clean
	perl -pw -i.ori -e 's/ -O2 / -Os /' Makefile
	make $SETCC $SETCPP || exit 1
	make strip || exit 1
	cp atitvout $targetdir/usr/bin
	popd

	# --------------- s3switch -----------------------------------
	pushd s3switch
	test "X$makeClean" = "Xy" && make clean
	make CC="gcc -Os" || exit 1
	strip s3switch
	cp s3switch $targetdir/usr/bin
	popd

	# --------------- nvtv -----------------------------------
	pushd nvtv
	test "X$makeClean" = "Xy" && make clean
	./configure --with-x=no --with-gtk=no --with-wx=no
	make CFLAGS=-Os || exit 1
	make prefix=$targetdir/nvtv install || exit 1
	strip $targetdir/nvtv/bin/*
	popd

	# --------------- EPIA kernel module and tv out ----------
	pushd epiafb
	test "X$makeClean" = "Xy" && make clean
	make $SETCC $SETCPP INCLUDES="-I$sourcedir/linux/include" || exit 1
	cp epiafb.o $moddir/kernel/drivers/video/
	popd

	pushd epiatvout
	test "X$makeClean" = "Xy" && make clean
	make $SETCC $SETCPP || exit 1
	strip tvout
	mv tvout $targetdir/usr/bin/epiatvout
	popd
fi

# --------------- devfsd -----------------------------------
if [ "$compileDevfsd" = "y" ]; then
	pushd devfsd
	test "X$makeClean" = "Xy" && make clean
	make $SETCC $SETCPP KERNEL_DIR=$sourcedir/linux || exit 1
	strip devfsd
	make install PREFIX=$targetdir/devfsd || exit 1
	popd
fi

# --------------- and finally mplayer --------------------------
if [ "$compileMplayer" = "y" ]; then
	pushd mplayer

	# First, some directories with stuff that isn't necessary for
	# eMoviX are moved into zipfiles so they don't get compiled.
	# libfame, libmp1e are for encoding.
	# opendivx is for divx.com codec integration.
	for lib in libfame libmp1e opendivx; do
		if [ -d $lib ]; then
			zip -qrm9 $lib.zip $lib/
		fi
	done

	if [ "$withDvd" = "y" ]; then
	# Use mplayer's bundled DVD library
		if [ -e libmpdvdkit2.zip ]; then
		# the directory is zipped (previous run without -X)
			unzip -q libmpdvdkit2.zip
			rm libmpdvdkit2.zip
		fi
	else
		# MPlayer shouldn't compile the bundled dvd reading software because that
		# could get us in legal trouble. So move the dvd directory to a zip file.
		if [ -d libmpdvdkit2 ]; then
			zip -rmq9 libmpdvdkit2.zip libmpdvdkit2/
		fi
	fi

	#Need to apply patches?
	if [ -e $configdir/mplayerPatch1 ]; then

		cp $configdir/mplayerPatch* .
		# Ignore patches with a version number, they were symlinked anyway.
		rm -f mplayerPatch*.[0-9]*

		for patch in mplayerPatch* ; do
			if [ -e $patch.did ]; then
				echo "Patch $patch already applied."
			else
				echo "Applying patch $patch..."
				patch -p1 < $patch || exit 1
				touch $patch.did
			fi
		done
	fi
	rm -f *.did.did

	cp $configdir/mplayerConfig.$targetname .

	if [ "$disableWin" = "y" ]; then
		echo "Disabling Windows support..."
		perl -pw -i.ori -e \
			's/enable-(dshow|win32|qtx(-codecs)?|real)/disable-$1/g' \
			mplayerConfig.$targetname
		perl -pw -i.ori -e \
			's/--with-win32libdir=[^ ]+//' \
			mplayerConfig.$targetname
	fi

	if [ "X$withoutModules" != "X" ]; then
		vomodules=`echo -n "$withoutModules" | sed "s/,/ /g"`
		for vomod in $vomodules; do
			echo "Disabling $vomod support..."
			perl -pw -i.ori -e \
				"s/enable-$vomod/disable-$vomod/g" \
				mplayerConfig.$targetname
		done
	fi
	
	test "X$makeClean" = "Xy" && make clean

	sh mplayerConfig.$targetname $targetdir || exit 1
	if [ "$optimizeSize" = "y" ]; then
		# Change -O4 to -Os in config.mak
		perl -pw -i.ori -e 's/^(OPTFLAGS *=.*)-O4/$1-Os/' config.mak
	fi
	make || exit 1
	make DESTDIR=$targetdir/mplayer install || exit 1
	cp TVout/matroxtv $targetdir/usr/bin

	# Separately compile the mga_vid kernel module. Errors (that could 
	# happen if the kernel source is not available) are ignored because 
	# not everybody needs mga_vid.
	cd drivers
	test "X$makeClean" = "Xy" && make clean
	perl -pw -i.ori -e 's/^[ 	]depmod -a/	echo depmod -a/' Makefile
	make KERNEL_INCLUDES=$sourcedir/linux/include
	make MDIR=$moddir/kernel/drivers/video/matrox install

	popd
fi

# one last popd
popd
