#!/bin/sh
#  file kernel/ocaml/remake: compile rules for the libnumerix-ocaml library
#-----------------------------------------------------------------------+
#  Copyright 2005-2006, Michel Quercia (michel.quercia@prepas.org)      |
#                                                                       |
#  This file is part of Numerix. Numerix is free software; you can      |
#  redistribute it and/or modify it under the terms of the GNU Lesser   |
#  General Public License as published by the Free Software Foundation; |
#  either version 2.1 of the License, or (at your option) any later     |
#  version.                                                             |
#                                                                       |
#  The Numerix Library is distributed in the hope that it will be       |
#  useful, but WITHOUT ANY WARRANTY; without even the implied warranty  |
#  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU  |
#  Lesser General Public License for more details.                      |
#                                                                       |
#  You should have received a copy of the GNU Lesser General Public     |
#  License along with the GNU MP Library; see the file COPYING. If not, |
#  write to the Free Software Foundation, Inc., 59 Temple Place -       |
#  Suite 330, Boston, MA 02111-1307, USA.                               |
#-----------------------------------------------------------------------+
#                                                                       |
#                Rgles de construction de libnumerix-ocaml             |
#                                                                       |
#-----------------------------------------------------------------------+

# m_list    = liste des modes (c/d/s)
# b_list    = liste additionnelle pour Bignum (b)
# g_list    = liste additionnelle pour Gmp (g)
# mode_list = liste des noms complets (clong/dlong/slong/big/gmp)
# Mode_list = idem avec initiale en majuscule
# cclib     = bibliothques  fournir au linker
# gcclib    = idem pour gcc -shared
# cma_list  = liste des bibliothques compiles
# cmxa_list = idem pour ocamlopt

m_list=
b_list=
g_list=
mode_list=
Mode_list=
cclib="-cclib -lnumerix-ocaml"
gcclib=
cma_list=
cmxa_list=

if test "$USE_CLONG" = "1"; then
    m_list="${m_list} c"
    mode_list="${mode_list} clong"
    Mode_list="${Mode_list} Clong"
fi
if test "$USE_DLONG" = "1"; then
    m_list="${m_list} d"
    mode_list="${mode_list} dlong"
    Mode_list="${Mode_list} Dlong"
fi
if test "$USE_SLONG" = "1"; then
    m_list="${m_list} s"
    mode_list="${mode_list} slong"
    Mode_list="${Mode_list} Slong"
fi
if test "$USE_OCAML_BIGNUM" = "1"; then
    b_list="${b_list} b"
    mode_list="${mode_list} big"
    Mode_list="${Mode_list} Big"
    cma_list="${cma_list} nums.cma"
    cmxa_list="${cmxa_list} nums.cmxa"
fi
if test "$USE_GMP" = "1"; then
    g_list="${g_list} g"
    mode_list="${mode_list} gmp"
    Mode_list="${Mode_list} Gmp"
    cclib="${cclib} -cclib -lgmp"
    gcclib="${gcclib} -lgmp"
fi
cma_list="${cma_list} kernel/ocaml/o/numerix.cma"
cmxa_list="${cmxa_list} kernel/ocaml/o/numerix.cmxa"

# On y va
cat <<EOF
# File kernel/ocaml/makefile: compile rules for the libnumerix-ocaml library
EOF
sed -n -e '3,/^$/p' $0 
cat <<EOF
# This file was generated by the kernel/ocaml/remake script
# switches:
#   USE_CLONG=$USE_CLONG
#   USE_DLONG=$USE_DLONG
#   USE_SLONG=$USE_SLONG
#   USE_OCAML_BIGNUM=$USE_OCAML_BIGNUM
#   USE_GMP=$USE_GMP
#   MAKE_OCAML_LIB=$MAKE_OCAML_LIB
#   OCAMLOPT=$OCAMLOPT
#   OCAMLMKLIB=$OCAMLMKLIB
#   SHARED=$SHARED
EOF

if test "$MAKE_OCAML_LIB" = "0"; then exit; fi

cat <<EOF
#-------------------- config files
lib_ocaml_config = Makefile kernel/config.h kernel/ocaml/makefile

#-------------------- source files
lib_ocaml_c_src = \\
  kernel/ocaml/c/numerix.c \\
  kernel/ocaml/c/hash.c  \\
  kernel/x/c/add.c       \\
  kernel/x/c/cmp.c       \\
  kernel/x/c/convert.c   \\
  kernel/x/c/copy.c      \\
  kernel/x/c/div.c       \\
  kernel/x/c/dump.c      \\
  kernel/x/c/fact.c      \\
  kernel/x/c/gcd.c       \\
  kernel/x/c/mul.c       \\
  kernel/x/c/pow.c       \\
  kernel/x/c/powmod.c    \\
  kernel/x/c/prime.c     \\
  kernel/x/c/random.c    \\
  kernel/x/c/root.c      \\
  kernel/x/c/shift.c     \\
  kernel/x/c/sqrt.c      \\
  kernel/x/c/string.c

lib_ocaml_h_src = \\
  kernel/ocaml/h/numerix.h \\
  kernel/x/h/numerix.h   \\
  kernel/x/h/alloc.h     \\
  kernel/x/h/add.h       \\
  kernel/x/h/cmp.h       \\
  kernel/x/h/convert.h   \\
  kernel/x/h/copy.h      \\
  kernel/x/h/div.h       \\
  kernel/x/h/dump.h      \\
  kernel/x/h/fact.h      \\
  kernel/x/h/gcd.h       \\
  kernel/x/h/mul.h       \\
  kernel/x/h/pow.h       \\
  kernel/x/h/powmod.h    \\
  kernel/x/h/prime.h     \\
  kernel/x/h/random.h    \\
  kernel/x/h/root.h      \\
  kernel/x/h/shift.h     \\
  kernel/x/h/sqrt.h      \\
  kernel/x/h/string.h    \\
  kernel/x/h/chrono.h


#-------------------- library, C-part

kernel/ocaml/o/chrono.o: \$(lib_ocaml_config) kernel/x/c/chrono.c kernel/x/h/chrono.h
	\$(GCC) \$(PIC) -I\$(OCAML_LIBDIR)/caml -Docaml_api -c -o \$@ kernel/x/c/chrono.c
kernel/ocaml/o/hash.o: kernel/ocaml/c/hash.c
	\$(GCC) \$(PIC) -c -o \$@ kernel/ocaml/c/hash.c
EOF
for m in $m_list; do cat <<EOF
kernel/ocaml/o/numerix-$m.o: \$(lib_ocaml_config) \$(lib_ocaml_c_src) \$(lib_ocaml_h_src) \$(lib_n_obj)
	\$(GCC) \$(PIC) -I\$(OCAML_LIBDIR)/caml -Duse_${m}long -c -o \$@ kernel/ocaml/c/numerix.c
EOF
done
if test "$USE_GMP" = "1"; then cat <<EOF
kernel/ocaml/o/numerix-g.o: \$(lib_ocaml_config) kernel/ocaml/c/gmp.c kernel/x/c/gmp.c
	\$(GCC) \$(PIC) -I\$(OCAML_LIBDIR)/caml -c -o \$@ kernel/ocaml/c/gmp.c
EOF
fi

cat <<EOF

#-------------------- library, Ocaml-part
EOF
echo -n "lib_ocaml_ml = \\
  kernel/ocaml/ml/numerix.ml   \\
  kernel/ocaml/ml/cmp.ml       \\
  kernel/ocaml/ml/count.ml     \\
  kernel/ocaml/ml/rfuns.ml     \\
  kernel/ocaml/ml/start.ml     \\
  kernel/ocaml/ml/xlong.ml     "
if test "$USE_OCAML_BIGNUM" = "1"; then echo -n "\\
  kernel/ocaml/ml/big.ml       "
fi
echo
echo

echo -n "lib_ocaml_mli = \\
  kernel/ocaml/mli/numerix.mli   \\
  kernel/ocaml/mli/cmp.mli       \\
  kernel/ocaml/mli/count.mli     \\
  kernel/ocaml/mli/rfuns.mli     \\
  kernel/ocaml/mli/start.mli     \\
  kernel/ocaml/mli/xlong.mli     "
if test "$USE_OCAML_BIGNUM" = "1"; then echo -n "\\
  kernel/ocaml/mli/big.mli       "
fi
echo

cat <<EOF

lib_ocaml_include = kernel/ocaml/o/numerix.ml kernel/ocaml/o/numerix.mli
kernel/ocaml/o/numerix.mli: \$(lib_ocaml_config) \$(lib_ocaml_mli)
	kernel/ocaml/numerix.sh $mode_list kernel/ocaml/mli/numerix.mli >\$@
kernel/ocaml/o/numerix.cmi: kernel/ocaml/o/numerix.mli
	\$(OCAMLC) -I kernel/ocaml/o -c kernel/ocaml/o/numerix.mli
kernel/ocaml/o/numerix.ml: \$(lib_ocaml_config) \$(lib_ocaml_ml)
	kernel/ocaml/numerix.sh $mode_list kernel/ocaml/ml/numerix.ml >\$@
kernel/ocaml/o/numerix.cmo: kernel/ocaml/o/numerix.ml kernel/ocaml/o/numerix.cmi
	\$(OCAMLC) -I kernel/ocaml/o -c kernel/ocaml/o/numerix.ml
kernel/ocaml/o/numerix.cmx: kernel/ocaml/o/numerix.ml kernel/ocaml/o/numerix.cmi
	\$(OCAMLOPT) -I kernel/ocaml/o -c kernel/ocaml/o/numerix.ml

EOF
echo -n "lib_ocaml_obj =  \\
  kernel/ocaml/o/chrono.o \\
  kernel/ocaml/o/hash.o   "
for m in $m_list $g_list; do echo -n "\\
  kernel/ocaml/o/numerix-$m.o "
done
echo

echo -n "lib_ocaml_cm = \\
  kernel/ocaml/o/numerix.cmo "
if test "$OCAMLOPT" != ""; then echo -n "\\
  kernel/ocaml/o/numerix.cmx "
fi
echo

if test x$SHARED = x1; then
cat <<EOF
lib_ocaml_0 = libnumerix-ocaml.so
lib_ocaml_1 = \$(lib_ocaml_0).\$(NUMERIX_MAJOR)
lib_ocaml_2 = \$(lib_ocaml_1).\$(NUMERIX_MINOR)
lib_ocaml_3 = dllnumerix-ocaml.so
lib_ocaml = kernel/ocaml/o/\$(lib_ocaml_2)
EOF
else cat <<EOF
lib_ocaml = kernel/ocaml/o/libnumerix-ocaml.a
EOF
fi

echo -n "
lib_ocaml_lib = \\
  \$(lib_ocaml) \\
  kernel/ocaml/o/numerix.cmi  \\
  kernel/ocaml/o/numerix.cma  "
if test "$OCAMLOPT" != ""; then echo -n "\\
  kernel/ocaml/o/numerix.a    \\
  kernel/ocaml/o/numerix.cmxa "
fi
echo

cat <<EOF

\$(lib_ocaml): \$(lib_ocaml_cm) \$(lib_ocaml_obj) \$(lib_n_obj)
EOF

if test "$SHARED" = "1"; then
if test "$OCAMLMKLIB" = ""; then
#-------------------- shared = 1, sans ocamlmklib
cat <<EOF
	\$(GCC) -shared -o \$@ \$(lib_ocaml_obj) \$(lib_n_obj) $gcclib
	\$(OCAMLC) -I kernel/ocaml/o -a -o kernel/ocaml/o/numerix.cma \\
		kernel/ocaml/o/numerix.cmo -dllib -lnumerix-ocaml $cclib
EOF
if test "$OCAMLOPT" != ""; then
cat <<EOF
	\$(OCAMLOPT) -I kernel/ocaml/o -a -o kernel/ocaml/o/numerix.cmxa \\
		kernel/ocaml/o/numerix.cmx $cclib
EOF
fi
#-------------------- shared = 1, avec ocamlmklib
else cat <<EOF
	\$(OCAMLMKLIB) -I kernel/ocaml/o -o numerix -oc numerix-ocaml \\
	  \$(lib_ocaml_cm) \$(lib_ocaml_obj) \$(lib_n_obj) $gcclib
	mv numerix.cma kernel/ocaml/o
	rm libnumerix-ocaml.a
	mv dllnumerix-ocaml.so \$(lib_ocaml)
EOF
if test "$OCAMLOPT" != ""; then
cat <<EOF
	mv numerix.cmxa numerix.a kernel/ocaml/o
EOF
fi
fi
#-------------------- shared = 1
cat <<EOF
	ln -s \$(lib_ocaml_2) kernel/ocaml/o/\$(lib_ocaml_1)
	ln -s \$(lib_ocaml_1) kernel/ocaml/o/\$(lib_ocaml_0)
	ln -s \$(lib_ocaml_2) kernel/ocaml/o/\$(lib_ocaml_3)
EOF
else
if test "$OCAMLMKLIB" = ""; then
#-------------------- shared = 0, sans ocamlmklib
cat <<EOF
	rm -f \$@
	\$(AR) \$@ \$(lib_ocaml_obj) \$(lib_n_obj)
	\$(RANLIB) \$@
	\$(OCAMLC) -custom -I kernel/ocaml/o -a -o kernel/ocaml/o/numerix.cma \\
		kernel/ocaml/o/numerix.cmo $cclib
EOF
if test "$OCAMLOPT" != ""; then
cat <<EOF
	\$(OCAMLOPT) -I kernel/ocaml/o -a -o kernel/ocaml/o/numerix.cmxa \\
		kernel/ocaml/o/numerix.cmx $cclib
EOF
fi
#-------------------- shared = 0, avec ocamlmklib
else cat <<EOF
	\$(OCAMLMKLIB) -I kernel/ocaml/o -o numerix -oc numerix-ocaml \$(lib_ocaml_cm) \$(lib_ocaml_obj) \$(lib_n_obj) $gcclib
	mv numerix.cma libnumerix-ocaml.a kernel/ocaml/o
	if test -e dllnumerix-ocaml.so; then mv dllnumerix-ocaml.so kernel/ocaml/o; fi
EOF
if test "$OCAMLOPT" != ""; then
cat <<EOF
	mv numerix.cmxa numerix.a kernel/ocaml/o
EOF
fi
fi
fi

#-------------------- toplevel
l=
for m in $Mode_list; do l="$l \"$m\" ::"; done
cat <<EOF

#-------------------- toplevel
kernel/ocaml/o/toplevelcfg.cmo: kernel/ocaml/ml/toplevelcfg.ml kernel/ocaml/o/numerix.cmi
	sed -e 's/_Mode_list_/$l/' \\
	    -e 's?_directory_?\$(OCAML_INSTALL_LIB)?' \\
	    -e 's/_numerix_version_/\$(NUMERIX_MAJOR).\$(NUMERIX_MINOR)/' \\
	    kernel/ocaml/ml/toplevelcfg.ml >kernel/ocaml/o/toplevelcfg.ml
	\$(OCAMLC) -I kernel/ocaml/o -o \$@ -c kernel/ocaml/o/toplevelcfg.ml

kernel/ocaml/o/ocamlnumx: kernel/ocaml/o/toplevelcfg.cmo \$(lib_ocaml)
	\$(OCAMLMKTOP) -I kernel/ocaml/o -o \$@$cma_list kernel/ocaml/o/toplevelcfg.cmo

lib_ocaml_bin = kernel/ocaml/o/ocamlnumx
EOF

#-------------------- installation
cat <<EOF

#-------------------- installation
.PHONY: install_ocaml
install_ocaml: \$(lib_ocaml_bin) \$(lib_ocaml) \$(lib_ocaml_include)
	mkdir -p \$(OCAML_INSTALL_BIN) \$(OCAML_INSTALL_LIB) \$(OCAML_INSTALL_INCLUDE)
	cp -p \$(lib_ocaml_bin) \$(OCAML_INSTALL_BIN)
	cp -p \$(lib_ocaml_lib) \$(OCAML_INSTALL_LIB)
	cp -p \$(lib_ocaml_include) \$(OCAML_INSTALL_INCLUDE)
EOF

if test x$SHARED = x1; then cat <<EOF
	ln -s \$(lib_ocaml_2) \$(OCAML_INSTALL_LIB)/\$(lib_ocaml_1)
	ln -s \$(lib_ocaml_1) \$(OCAML_INSTALL_LIB)/\$(lib_ocaml_0)
	ln -s \$(lib_ocaml_2) \$(OCAML_INSTALL_LIB)/\$(lib_ocaml_3)
EOF
else cat <<EOF
	\$(RANLIB) \$(OCAML_INSTALL_LIB)/libnumerix-ocaml.a
	if test -e kernel/ocaml/o/dllnumerix-ocaml.so; then cp -p kernel/ocaml/o/dllnumerix-ocaml.so \$(OCAML_INSTALL_LIB); fi
EOF
fi

#-------------------- examples
exemples="pi shanks simple digits sqrt-163"
check="cmp rcheck"
cat <<EOF

#-------------------- examples
EOF

echo -n "ex_ocaml_obj = "
for e in $exemples $check; do echo -n "\\
  exemples/ocaml/$e "
done
if test "$OCAMLOPT" != ""; then for e in $exemples $check; do echo -n "\\
  exemples/ocaml/$e-opt "
done; fi
echo
echo

for e in $exemples $check; do cat <<EOF
exemples/ocaml/$e: exemples/ocaml/$e.ml \$(lib_ocaml)
	\$(OCAMLC) -I kernel/ocaml/o -o \$@ $cma_list exemples/ocaml/$e.ml
	@rm exemples/ocaml/$e.cmi exemples/ocaml/$e.cmo
EOF
done
if test "$OCAMLOPT" != ""; then for e in $exemples $check; do cat <<EOF
exemples/ocaml/$e-opt: kernel/ocaml/o/numerix.cmxa exemples/ocaml/$e.ml \$(lib_ocaml)
	\$(OCAMLOPT) -I kernel/ocaml/o -o \$@ $cmxa_list exemples/ocaml/$e.ml
	@rm exemples/ocaml/$e.cmi exemples/ocaml/$e.cmx exemples/ocaml/$e.o
EOF
done; fi

cat <<EOF

.PHONY: test_ocaml
test_ocaml: \$(ex_ocaml_obj)
	@echo "-------------------- Testing the Ocaml interface"
	CAML_LD_LIBRARY_PATH=kernel/ocaml/o:\$\$CAML_LD_LIBRARY_PATH; \\
	LD_LIBRARY_PATH=kernel/ocaml/o:\$\$LD_LIBRARY_PATH; \\
	export CAML_LD_LIBRARY_PATH LD_LIBRARY_PATH; \\
	for i in $exemples; do for j in $mode_list; do \\
	     exemples/ocaml/\$\$i -test -e \$\$j; \\
	done; done
EOF
if test "$OCAMLOPT" != ""; then cat <<EOF
	@echo "-------------------- Testing the Ocamlopt interface"
	CAML_LD_LIBRARY_PATH=kernel/ocaml/o:\$\$CAML_LD_LIBRARY_PATH; \\
	LD_LIBRARY_PATH=kernel/ocaml/o:\$\$LD_LIBRARY_PATH; \\
	export CAML_LD_LIBRARY_PATH LD_LIBRARY_PATH; \\
	for i in $exemples; do for j in $mode_list; do \\
	    exemples/ocaml/\$\$i-opt -test -e \$\$j; \\
	done; done
EOF
fi
cat <<EOF

#-------------------- cleanup
.PHONY: clean_ocaml
clean_ocaml:
	rm -f kernel/ocaml/o/*
EOF
for i in $exemples $check; do cat <<EOF
	@rm -f exemples/ocaml/$i{,-opt}{,.exe}
EOF
done

cat <<EOF

#-------------------- done
lib: \$(lib_ocaml) 
lib: kernel/ocaml/o/numerix.ml  
lib: kernel/ocaml/o/numerix.mli 
lib: kernel/ocaml/o/numerix.cmi 
EOF
if test "$OCAMLOPT" != ""; then cat <<EOF
lib: kernel/ocaml/o/numerix.cmxa 
EOF
fi
cat <<EOF
lib: kernel/ocaml/o/ocamlnumx

install:      install_ocaml
exemples:     \$(ex_ocaml_obj)
test:         test_ocaml
clean:        clean_ocaml
EOF
