#!/usr/bin/make -f

DEB_TAR_SRCDIR := .

MINGW_HOST := i686-w64-mingw32
FLEXDLL_DIR := flexdll
OCAML_DIR := ocaml-3.12.1
FINDLIB_DIR := findlib-1.2.5+debian
OTHER_LIBS := win32unix str num dynlink bigarray systhreads win32graph
INSTALL_PATH := $(CURDIR)/debian/mingw-ocaml
DEB_STRIP_EXCLUDE := $(MINGW_HOST)

include /usr/share/cdbs/1/rules/tarball.mk
include /usr/share/cdbs/1/rules/debhelper.mk
include /usr/share/cdbs/1/rules/patchsys-quilt.mk

stamp-build-flexdll:
	cd $(DEB_BUILDDIR)/$(FLEXDLL_DIR) && make TOOLCHAIN=mingw MINCC=$(MINGW_HOST)-gcc \
	                                         CC=$(MINGW_HOST)-gcc flexlink.exe build_mingw
	cd $(DEB_BUILDDIR)/$(FLEXDLL_DIR) && cp flexlink.exe flexlink
	touch stamp-build-flexdll

stamp-build-ocamlcore:
	# Build native ocamlrun and ocamlc which contain the
	# filename-win32-dirsep patch.
	#
	# Note that we must build a 32 bit compiler, even on 64 bit build
	# architectures, because this compiler will try to do strength
	# reduction optimizations using its internal int type, and that must
	# match Windows' int type.  (That's what -cc and -host are for).
	cd $(DEB_BUILDDIR)/$(OCAML_DIR) && ./configure \
	  -prefix /usr/$(MINGW_HOST) \
	  -bindir /usr/$(MINGW_HOST)/bin \
	  -libdir /usr/$(MINGW_HOST)/lib/ocaml \
	  -no-tk \
	  -cc "gcc -m32" -host $(MINGW_HOST) -x11lib /usr/lib -verbose
	cd $(DEB_BUILDDIR)/$(OCAML_DIR) && make world
	# Now move the working ocamlrun, ocamlc into the boot/ directory,
	# overwriting the binary versions which ship with the compiler with
	# ones that contain the filename-win32-dirsep patch.
	cd $(DEB_BUILDDIR)/$(OCAML_DIR) && make coreboot
	touch stamp-build-ocamlcore

stamp-patch-mingw-include:
	# Now patch utils/clflags.ml to hardcode mingw-specific include.
	patch -p0 < debian/patches/hardcode_mingw_include.patch
	touch stamp-patch-mingw-include

stamp-prepare-cross-build: stamp-patch-mingw-include
	# Replace the compiler configuration (config/{s.h,m.h,Makefile})
	# with ones as they would be on a 32 bit Windows system.
	cp -f $(DEB_BUILDDIR)/$(OCAML_DIR)/config/m-nt.h $(DEB_BUILDDIR)/$(OCAML_DIR)/config/m.h
	cp -f $(DEB_BUILDDIR)/$(OCAML_DIR)/config/s-nt.h $(DEB_BUILDDIR)/$(OCAML_DIR)/config/s.h
	# config/Makefile is a custom one which we supply.
	rm -f $(DEB_BUILDDIR)/$(OCAML_DIR)/config/Makefile
	sed \
	  -e "s,@prefix@,/usr/$(MINGW_HOST),g" \
	  -e "s,@bindir@,/usr/$(MINGW_HOST)/bin,g" \
	  -e "s,@libdir@,/usr/$(MINGW_HOST)/lib/ocaml,g" \
	  -e "s,@otherlibraries@,$(OTHER_LIBS),g" \
	  -e "s,@flexdir@,$(CURDIR)/$(DEB_BUILDDIR)/$(FLEXDLL_DIR),g" \
	  < debian/Makefile-mingw.in > $(DEB_BUILDDIR)/$(OCAML_DIR)/config/Makefile
	# We're going to build in otherlibs/win32unix and otherlibs/win32graph
	# directories, but since they would normally only be built under
	# Windows, they only have the Makefile.nt files.  Just symlink
	# Makefile -> Makefile.nt for these cases.
	for d in $(DEB_BUILDDIR)/$(OCAML_DIR)/otherlibs/win32unix \
	         $(DEB_BUILDDIR)/$(OCAML_DIR)/otherlibs/win32graph \
		 $(DEB_BUILDDIR)/$(OCAML_DIR)/otherlibs/bigarray \
		 $(DEB_BUILDDIR)/$(OCAML_DIR)/otherlibs/systhreads; do \
 	  ln -sf Makefile.nt $$d/Makefile; \
	done
	# Now clean the temporary files from the previous build.  This
	# will also cause asmcomp/arch.ml (etc) to be linked to the 32 bit
	# i386 versions, essentially causing ocamlopt to use the Win/i386 code
	# generator.
	cd $(DEB_BUILDDIR)/$(OCAML_DIR) && make partialclean
	# We need to remove any .o object for make sure they are
	# recompiled later..
	cd $(DEB_BUILDDIR)/$(OCAML_DIR) && rm byterun/*.o
	touch stamp-prepare-cross-build

stamp-build-mingw-ocaml:
	# Just rebuild some small bits that we need for the following
	# 'make opt' to work.  Note that 'make all' fails here.
	cd $(DEB_BUILDDIR)/$(OCAML_DIR) && make -C byterun libcamlrun.a
	cd $(DEB_BUILDDIR)/$(OCAML_DIR) && make ocaml ocamlc
	cd $(DEB_BUILDDIR)/$(OCAML_DIR) && make -C stdlib
	cd $(DEB_BUILDDIR)/$(OCAML_DIR) && make -C tools ocamlmklib
	# Build ocamlopt
	cd $(DEB_BUILDDIR)/$(OCAML_DIR) && PATH=$(CURDIR)/$(DEB_BUILDDIR)/$(FLEXDLL_DIR):$(PATH) \
	                                   make opt
	# Now build otherlibs for ocamlopt
	cd $(DEB_BUILDDIR)/$(OCAML_DIR) && \
	for i in $(OTHER_LIBS); do \
	  make -C otherlibs/$$i clean; \
	  PATH=$(CURDIR)/$(DEB_BUILDDIR)/$(FLEXDLL_DIR):$(PATH) \
	    make -C otherlibs/$$i all; \
	  PATH=$(CURDIR)/$(DEB_BUILDDIR)/$(FLEXDLL_DIR):$(PATH) \
	    make -C otherlibs/$$i allopt; \
	done
	touch stamp-build-mingw-ocaml

stamp-build-findlib:
	cd $(DEB_BUILDDIR)/$(FINDLIB_DIR)/tools/extract_args && make
	$(DEB_BUILDDIR)/$(FINDLIB_DIR)/tools/extract_args/extract_args \
	  -o $(DEB_BUILDDIR)/$(FINDLIB_DIR)/src/findlib/ocaml_args.ml \
	  $(INSTALL_PATH)/usr/bin/$(MINGW_HOST)-ocamlc \
	  $(INSTALL_PATH)/usr/bin/$(MINGW_HOST)-ocamlcp \
	  $(INSTALL_PATH)/usr/bin/$(MINGW_HOST)-ocamlmktop \
	  $(INSTALL_PATH)/usr/bin/$(MINGW_HOST)-ocamlopt \
	  $(INSTALL_PATH)/usr/bin/$(MINGW_HOST)-ocamldep 
	cd $(DEB_BUILDDIR)/$(FINDLIB_DIR) && ./configure \
	  -config /etc/$(MINGW_HOST)-ocamlfind.conf \
	  -bindir /usr/$(MINGW_HOST)/bin \
	  -sitelib /usr/$(MINGW_HOST)/lib/ocaml \
	  -mandir /usr/share/man \
	  -with-toolbox
	cd $(DEB_BUILDDIR)/$(FINDLIB_DIR) && make all
	cd $(DEB_BUILDDIR)/$(FINDLIB_DIR) && make opt
	touch stamp-build-findlib

build/mingw-ocaml:: stamp-build-flexdll \
		      stamp-build-ocamlcore \
		      stamp-prepare-cross-build \
		      stamp-build-mingw-ocaml \
		      $(INSTALL_PATH)/usr/bin/$(MINGW_HOST)-ocamlopt \
		      stamp-build-findlib

$(INSTALL_PATH)/usr/bin/$(MINGW_HOST)-ocamlopt:
	mkdir -p $(INSTALL_PATH)/usr/$(MINGW_HOST)/lib/ocaml/threads
	mkdir -p $(INSTALL_PATH)/usr/$(MINGW_HOST)/lib/ocaml/stublibs
	mkdir -p $(INSTALL_PATH)/usr/$(MINGW_HOST)/bin
	mkdir -p $(INSTALL_PATH)/usr/bin
	cd $(DEB_BUILDDIR)/$(OCAML_DIR) && make BINDIR=$(INSTALL_PATH)/usr/$(MINGW_HOST)/bin \
	                                        LIBDIR=$(INSTALL_PATH)/usr/$(MINGW_HOST)/lib/ocaml \
	                                        -C byterun install
	cd $(DEB_BUILDDIR)/$(OCAML_DIR) && make BINDIR=$(INSTALL_PATH)/usr/$(MINGW_HOST)/bin \
	                                        LIBDIR=$(INSTALL_PATH)/usr/$(MINGW_HOST)/lib/ocaml \
	                                        -C stdlib install
	cd $(DEB_BUILDDIR)/$(OCAML_DIR) && \
	for i in $(OTHER_LIBS); do \
	  make BINDIR=$(INSTALL_PATH)/usr/$(MINGW_HOST)/bin \
	       LIBDIR=$(INSTALL_PATH)/usr/$(MINGW_HOST)/lib/ocaml \
	       -C otherlibs/$$i install; \
	done
	cd $(DEB_BUILDDIR)/$(OCAML_DIR) && make BINDIR=$(INSTALL_PATH)/usr/$(MINGW_HOST)/bin \
	                                        LIBDIR=$(INSTALL_PATH)/usr/$(MINGW_HOST)/lib/ocaml \
	                                        -C tools install
	cd $(DEB_BUILDDIR)/$(OCAML_DIR) && make BINDIR=$(INSTALL_PATH)/usr/$(MINGW_HOST)/bin \
	                                        LIBDIR=$(INSTALL_PATH)/usr/$(MINGW_HOST)/lib/ocaml \
	                        installopt
	cd $(DEB_BUILDDIR)/$(OCAML_DIR) && install -m 0755 ocamlc $(INSTALL_PATH)/usr/$(MINGW_HOST)/bin
	cd $(DEB_BUILDDIR)/$(OCAML_DIR) && cp \
	  toplevel/topstart.cmo \
	  typing/outcometree.cmi typing/outcometree.mli \
	  toplevel/toploop.cmi toplevel/toploop.mli \
	  toplevel/topdirs.cmi toplevel/topdirs.mli \
 	  toplevel/topmain.cmi toplevel/topmain.mli \
	  $(INSTALL_PATH)/usr/$(MINGW_HOST)/lib/ocaml
	# Rename all the binaries to target-binary
	for f in ocamlc ocamlcp ocamlrun ocamldep ocamlmklib ocamlmktop ocamlopt ocamlprof; do \
	  mv $(INSTALL_PATH)/usr/$(MINGW_HOST)/bin/$$f $(INSTALL_PATH)/usr/bin/$(MINGW_HOST)-$$f; \
	done

install/mingw-ocaml::
	# Install findlib
	# Create this dir to please install..
	mkdir -p $(INSTALL_PATH)/usr/lib/ocaml
	cd $(DEB_BUILDDIR)/$(FINDLIB_DIR) && make install \
						prefix=$(INSTALL_PATH) 
	# Remove documentation which is already available
	# in the Debian native package.
	rm -r $(INSTALL_PATH)/usr/share/man
	# Symlink manuals for the cross-compiler binaries.
	for f in ocamlc ocamlcp ocamldep ocamlrun ocamlmklib ocamlmktop ocamlopt ocamlprof; do \
	  dh_link usr/share/man/man1/$$f.1.gz usr/share/man/man1/$(MINGW_HOST)-$$f.1.gz ; \
	done
	# Remove ocamlfind binary - we will use the native version.
	rm $(INSTALL_PATH)/usr/$(MINGW_HOST)/bin/ocamlfind
	# Remove findlib & num-top libs: if anything uses these we can
	# add them back later.
	rm -r $(INSTALL_PATH)/usr/$(MINGW_HOST)/lib/ocaml/findlib
	rm -r $(INSTALL_PATH)/usr/$(MINGW_HOST)/lib/ocaml/num-top
	# XXX topfind gets installed as %{_libdir}/ocaml - not sure why
	# but delete it anyway.
	rm -rf $(INSTALL_PATH)/usr/lib/ocaml
	# Override /etc/%{_mingw_target}-ocamlfind.conf with our
	# own version.
	rm $(INSTALL_PATH)/etc/$(MINGW_HOST)-ocamlfind.conf
	sed \
	  -e "s,@libdir@,/usr/$(MINGW_HOST)/lib,g" \
	  -e 's,@target@,$(MINGW_HOST),g' \
	  < debian/ocamlfind.conf.in \
	  > $(INSTALL_PATH)/etc/$(MINGW_HOST)-ocamlfind.conf
	# Install flexlink binary
	mkdir -p $(INSTALL_PATH)/usr/$(MINGW_HOST)/lib/ocaml/flexdll
	cd $(DEB_BUILDDIR)/$(FLEXDLL_DIR) && install -m 0755 flexlink.exe flexdll_mingw.o flexdll_initer_mingw.o \
	                                                     $(INSTALL_PATH)/usr/$(MINGW_HOST)/lib/ocaml/flexdll
	dh_link usr/$(MINGW_HOST)/lib/ocaml/flexdll/flexlink.exe usr/bin/flexlink
	# We choose which object we strip since this is not trivial here..
	strip --remove-section=.comment --remove-section=.note \
	  $(INSTALL_PATH)/usr/$(MINGW_HOST)/lib/ocaml/flexdll/flexlink.exe
	# Now we remove empty dirs..
	find $(INSTALL_PATH) -type d -empty -delete
	# Nothing in /usr/$(MINGW_HOST)/lib/ocaml should 'a priori' be executable except flexlink.exe..
	find $(INSTALL_PATH)/usr/$(MINGW_HOST)/lib/ocaml -type f -executable | grep -v flexlink.exe | while read i; do \
	    chmod -x $$i; done
	# Now make all script with #!/usr/bin/ocamlrun executables
	grep -r -l '#!/usr/$(MINGW_HOST)/bin/ocamlrun' $(INSTALL_PATH) | while read i; do \
	  sed -e 's|#!/usr/$(MINGW_HOST)/bin/ocamlrun|#!/usr/bin/$(MINGW_HOST)-ocamlrun|' -i $$i; \
	  chmod +x $$i; done
	# Remove rm -rf $(INSTALL_PATH)/usr/$(MINGW_HOST)/bin: all binaries should be prefixed and living in /usr/bin..
	rm -rf $(INSTALL_PATH)/usr/$(MINGW_HOST)/bin

clean::
	rm -f *.cdbs-config_list stamp-build-flexdll stamp-build-ocamlcore \
	      stamp-prepare-cross-build stamp-build-mingw-ocaml stamp-build-findlib \
	      stamp-patch-mingw-include 
