# -*- Mode: makefile -*-
#
# Assumes variables:
#    MFILES: root names of files
#    LMFILES: root names of library files
#    MLLIBS: root name of libraries
#    MAIN: root name of generated program
#

include $(ROOT)/mk/preface

#
# Use this when compiling with threads.
# This is tested only on Linux i386 and Solaris 2.5
#
ifndef OCAMLCPOPT
   THREADS = -thread
   THREADSLIB = $(CAMLLIB)/threads/threads.cma
else
   THREADS = -I $(CAMLLIB)/threads
   THREADSLIB = $(CAMLLIB)/profiling.cmo $(CAMLLIB)/threads/threads.cma
endif
OPTTHREADSLIB = $(CAMLLIB)/threads/threads.cmxa
ifeq ($(OSTYPE),Linux)
   OPTTHREADS = -cclib -lthreadsnat$(EXT_PROF) -cclib -lunix$(EXT_PROF) -cclib -lpthread
   LIBTHREADS = -cclib -lthreads -cclib -lunix -cclib -lpthread
else
ifeq ($(OSTYPE),darwin)
   OPTTHREADS = -cclib -lthreadsnat$(EXT_PROF) -cclib -lunix$(EXT_PROF) -cclib -lpthread
   LIBTHREADS = -cclib -lthreads -cclib -lunix -cclib -lpthread
else
ifeq ($(OSTYPE),Solaris)
   OPTTHREADS = -cclib -lthreadsnat$(EXT_PROF) -cclib -lunix$(EXT_PROF) -cclib -lpthread -cclib -lposix4
   LIBTHREADS = -cclib -lthreads -cclib -lunix -cclib -lpthread -cclib -lposix4
else
.PHONY: threads
$(THREADSLIB) $(OPTTHREADSLIB): threads
threads:
	@echo "!!! " > /dev/stderr
	@echo "!!! The value of your OSTYPE enviroment variable, \"$(OSTYPE)\", is unknown." > /dev/stderr
	@echo "!!! I do not know how to link POSIX threads on your OS" > /dev/stderr
	@echo "!!! If you know how to do it, add it to mk/rules file" > /dev/stderr
	@echo "!!! " > /dev/stderr
	@exit 1
endif
endif
endif

#
# Configuration
#
OCAMLDEP = $(ROOT)/bin/ocamldep
OCAMLCFLAGS = $(INCLUDE) -I $(ROOT)/lib $(OCAMLFLAGS) $(NOASSERT) $(THREADS)
OCAMLDEPFLAGS := $(OCAMLDEPFLAGS) $(INCLUDE) -I $(ROOT)/lib
OCAMLOPTFLAGS = $(INCLUDE) -I $(ROOT)/lib $(OCAMLFLAGS) $(PROFILE) -inline $(INLINE) -noassert $(THREADS)
CAMLP4NFLAGS = $(INCLUDE) $(OCAMLFLAGS)
CAMLP4OFLAGS = $(INCLUDE)
CFLAGS = $(CINCLUDE) -I$(CAMLLIB) -D_REENTRANT
ifeq ($(READLINE),YES)
   CFLAGS := $(CFLAGS) -DREADLINE
endif
ifdef PROFILE
   CFLAGS := $(CFLAGS) -p -DPROF
endif
NATIVE_CFLAGS = -DNATIVE_CODE
BYTE_CFLAGS =
RM = rm -f
INSTALL = /bin/cp -pf
CP = /bin/cp -pf
LN = ln -sf
ifndef CAMLP4N
	CAMLP4N = $(ROOT)/lib/camlp4n$(EXE)
endif

CAMLP4MACROPRINT = camlp4o pr_o.cmo $(ROOT)/util/macro.cmo $(PPFLAGS)

CAMLP4MACRO = camlp4o $(ROOT)/util/macro.cmo $(PPFLAGS)

#
# This works for some C compiler, edit if it does not work for yours
#
ifeq ($(CC),gcc)
   CCDEPEND=-MM
else
ifeq ($(OSTYPE),Solaris)
   CCDEPEND=-xM1
else
   CCDEPEND=-MM
endif
endif

# For cleaning the directory
ifdef MAIN
   CLEAN_MAIN = $(MAIN)
endif

# Most of MetaPRL uses the same LMIFILES as LMFILES
ifndef LMIFILES
	LMIFILES := $(LMFILES)
endif
ifndef MPIFILES
	MPIFILES := $(MPFILES)
endif
ifndef MP2IFILES
	MP2IFILES := $(MP2FILES)
endif
ifndef MIFILES
	MIFILES := $(MFILES)
endif
ifndef PIFILES
	PIFILES := $(PFILES)
endif

# Library file names
MLFILES      = $(sort $(addsuffix .ml,   $(MPFILES) $(MP2FILES) $(LMFILES) $(MFILES) $(PFILES)))
MLIFILES     = $(sort $(addsuffix .mli,  $(MPIFILES) $(MP2IFILES) $(LMIFILES) $(MIFILES) $(PIFILES)))

MP_CMIFILES  = $(addsuffix .cmi,  $(MPIFILES))
MP_CMOFILES  = $(addsuffix .cmo,  $(MPFILES))
MP_CMXFILES  = $(addsuffix .cmx,  $(MPFILES))
MP_PPOFILES  = $(addsuffix .ppo,  $(MPFILES))
MP_PRLAFILES = $(addsuffix .prla, $(MPFILES))
MP_PRLBFILES = $(addsuffix .prlb, $(MPFILES))

MP2_CMIFILES  = $(addsuffix .cmi,  $(MP2IFILES))
MP2_CMOFILES  = $(addsuffix .cmo,  $(MP2FILES))
MP2_CMXFILES  = $(addsuffix .cmx,  $(MP2FILES))
MP2_PPOFILES  = $(addsuffix .ppo,  $(MP2FILES))
MP2_PRLAFILES = $(addsuffix .prla, $(MP2FILES))
MP2_PRLBFILES = $(addsuffix .prlb, $(MP2FILES))

LCMOFILES    = $(addsuffix .cmo,  $(LMFILES))
LCMIFILES    = $(addsuffix .cmi,  $(LMIFILES))
LCMXFILES    = $(addsuffix .cmx,  $(LMFILES))
MCMIFILES    = $(addsuffix .cmi,  $(MIFILES))
MCMOFILES    = $(addsuffix .cmo,  $(MFILES))
MCMXFILES    = $(addsuffix .cmx,  $(MFILES))
PCMIFILES    = $(addsuffix .cmi,  $(PIFILES))
PCMOFILES    = $(addsuffix .cmo,  $(PFILES))
PCMXFILES    = $(addsuffix .cmx,  $(PFILES))

LMLIFILES    = $(addsuffix .mli,  $(LMIFILES))
LMLFILES     = $(addsuffix .ml,   $(LMFILES))
MMLFILES     = $(addsuffix .mli,  $(MFILES))
MMLIFILES    = $(addsuffix .ml,   $(MIFILES))
PMLIFILES    = $(addsuffix .mli,  $(PIFILES))
PMLFILES     = $(addsuffix .ml,   $(PFILES))

REG_CMIFILES = $(sort $(LCMIFILES) $(MCMIFILES) $(PCMIFILES))
REG_CMOFILES = $(sort $(LCMOFILES) $(MCMOFILES) $(PCMOFILES))
REG_CMXFILES = $(sort $(LCMXFILES) $(MCMXFILES) $(PCMXFILES))

CMIFILES     = $(sort $(MP_CMIFILES) $(MP2_CMIFILES) $(LCMIFILES) $(MCMIFILES))
CMOFILES     = $(sort $(MP_CMOFILES) $(MP2_CMOFILES) $(LCMOFILES) $(MCMOFILES))
CMXFILES     = $(sort $(MP_CMXFILES) $(MP2_CMXFILES) $(LCMXFILES) $(MCMXFILES))

CMAFILES     = $(addsuffix .cma,  $(MLLIBS))
CMXAFILES    = $(addsuffix .cmxa, $(MLLIBS))

BOFILES      = $(addsuffix -byte$(EXT_OBJ), $(LCFILES))
NOFILES      = $(addsuffix -native$(EXT_OBJ), $(LCFILES))
CFILES       = $(addsuffix .c, $(LCFILES))

RMLIFILES    = $(addprefix $(ROOT)/lib/, $(LMLIFILES))
RCMIFILES    = $(addprefix $(ROOT)/lib/, $(CMIFILES))
RCMAFILES    = $(addprefix $(ROOT)/lib/, $(addsuffix .cma, $(INSTALL_LIBS)))
RCMXAFILES   = $(addprefix $(ROOT)/lib/, $(addsuffix .cmxa, $(INSTALL_LIBS)))
RAFILES      = $(addprefix $(ROOT)/lib/, $(addsuffix $(EXT_LIB), $(INSTALL_LIBS)))

ZMLFILES     = $(addsuffix .ml, $(MLZFILES))
ZMLIFILES    = $(addsuffix .mli, $(MLZFILES))

# Instructions to make
.PRECIOUS: %.cmo %.cmi %.cmx %.ml %.mli

.SUFFIXES: .cma .cmx .cmo .cmi .ml .mli .mll .mly

$(MAIN)-byte$(EXT_LIB): $(BOFILES)
	$(MPTIME) ar r $@ $?
	$(MPTIME) ranlib $@

$(MAIN)-native$(EXT_LIB): $(NOFILES)
	$(MPTIME) ar r $@ $?
	$(MPTIME) ranlib $@

$(MAIN).cma: $(LCMOFILES) $(MP_CMOFILES) $(ROOT)/mk/config
	$(MPTIME) $(OCAMLC) $(OCAMLCFLAGS) -a -o $@ $(LCMOFILES) $(MP_CMOFILES)

$(MAIN).cmxa: $(LCMXFILES) $(MP_CMXFILES) $(ROOT)/mk/config
	$(MPTIME) $(OCAMLOPT) $(OCAMLOPTFLAGS) -a -o $@ $(LCMXFILES) $(MP_CMXFILES)

$(MAIN).run: $(CMAFILES) $(CMADEPS) $(PCMOFILES) $(ROOT)/mk/config $(THREADSLIB)
	$(MPTIME) $(OCAMLCP) -custom $(OCAMLCFLAGS) -o $@ $(OCAMLCPOPT) $(CMALIBS) $(CMAFILES) $(PCMOFILES) $(BYTE_CCLIBS) $(LIBTHREADS)
	if [ -f $(MAIN).run.exe ]; then\
		mv $(MAIN).run.exe $(MAIN).run.bak;\
		mv $(MAIN).run.bak $(MAIN).run;\
	fi

$(MAIN).opt: $(CMXAFILES) $(CMXDEPS) $(PCMXFILES) $(ROOT)/mk/config $(OPTTHREADSLIB)
	$(MPTIME) $(OCAMLOPT) $(OCAMLOPTFLAGS) -o $@ $(CMXAFILES) $(CMXLIBS) $(PCMXFILES) $(NATIVE_CCLIBS) $(OPTTHREADS)
	if [ -f $(MAIN).exe ]; then\
		mv $(MAIN).exe $(MAIN).bak;\
		mv $(MAIN).bak $(MAIN);\
	fi

#
# No default action for install
#
install::

export:: $(MP_PRLAFILES) $(MP2_PRLAFILES)
import:: $(MP_PRLBFILES) $(MP2_PRLBFILES)

$(RMLIFILES): $(ROOT)/lib/%.mli: %.mli
	$(LN) ../$(DIR)/$*.mli $(ROOT)/lib

$(RCMIFILES): $(ROOT)/lib/%.cmi: %.cmi
	$(LN) ../$(DIR)/$*.cmi $(ROOT)/lib

$(RCMAFILES): $(ROOT)/lib/%.cma: %.cma
	$(LN) ../$(DIR)/$*.cma $(ROOT)/lib

$(RCMXAFILES): $(ROOT)/lib/%.cmxa: %.cmxa
	$(LN) ../$(DIR)/$*.cmxa $(ROOT)/lib
	$(LN) ../$(DIR)/$*$(EXT_LIB) $(ROOT)/lib

$(RAFILES): $(ROOT)/lib/%$(EXT_LIB): %$(EXT_LIB)
	$(LN) ../$(DIR)/$*$(EXT_LIB) $(ROOT)/lib

$(MP_CMIFILES) $(MP2_CMIFILES): %.cmi: %.mli $(ROOT)/mk/config
	MPLIB=$(MPLIB) LC_ALL=C $(MPTIME) $(PRLC) $(OCAMLCFLAGS) -c $*.mli

$(MP_PPOFILES) $(MP2_PPOFILES): %.ppo: %.ml $(ROOT)/mk/config
	MPLIB=$(MPLIB) LC_ALL=C $(MPTIME) $(CAMLP4N) $(CAMLP4NFLAGS) $*.ml -o $*.ppo

$(MP_PRLAFILES) $(MP2_PRLAFILES): %.prla: %.cmoz $(ROOT)/mk/config
	MPLIB=$(MPLIB) LC_ALL=C $(MPTIME) $(CONVERT) $(INCLUDE) -impl $*.cmoz

$(MP_PRLBFILES) $(MP2_PRLBFILES): %.prlb: %.prla $(ROOT)/mk/config
	MPLIB=$(MPLIB) LC_ALL=C $(MPTIME) $(CONVERT) $(INCLUDE) -raw -impl $*.prla

$(MP_CMOFILES) $(MP2_CMOFILES): %.cmo: %.ppo $(ROOT)/mk/config
	$(MPTIME) $(OCAMLC) $(OCAMLCFLAGS) -c -impl $*.ppo

$(MP_CMXFILES) $(MP2_CMXFILES): %.cmx: %.ppo $(ROOT)/mk/config
	$(MPTIME) $(OCAMLOPT) $(OCAMLOPTFLAGS) -c -impl $*.ppo

$(REG_CMOFILES): %.cmo: %.ml $(ROOT)/mk/config
	$(MPTIME) $(OCAMLCP) $(OCAMLCFLAGS) -c $(OCAMLCPOPT) $*.ml

$(REG_CMIFILES): %.cmi: %.mli $(ROOT)/mk/config
	$(MPTIME) $(OCAMLC) $(OCAMLCFLAGS) -c $*.mli

$(REG_CMXFILES): %.cmx: %.ml $(ROOT)/mk/config
	$(MPTIME) $(OCAMLOPT) $(OCAMLOPTFLAGS) -c $*.ml

%.p4i: %.mli $(ROOT)/mk/config
	MPLIB=$(MPLIB) LC_ALL=C $(MPTIME) $(PRLC) $(INCLUDE) -E $*.mli > $*.p4i

%.p4: %.ml $(ROOT)/mk/config
	MPLIB=$(MPLIB) LC_ALL=C $(MPTIME) $(PRLC) $(INCLUDE) -E $*.ml > $*.p4

%.ml: %.mll $(ROOT)/mk/config
	$(RM) $@
	$(MPTIME) $(OCAMLLEX) $*.mll

%.ml %.mli: %.mly $(ROOT)/mk/config
	$(RM) $*.ml $*.mli
	$(MPTIME) $(OCAMLYACC) $*.mly

%.ml: %.mlz
	$(RM) $@
	$(LN) $*.mlz $@

%.mli: %.mlz
	$(RM) $@
	$(LN) $*.mlz $@

%-byte.o: %.c $(ROOT)/mk/config
	$(MPTIME) $(CC) $(BYTE_CFLAGS) $(CFLAGS) -c $*.c -o $@

%-native.o: %.c $(ROOT)/mk/config
	$(MPTIME) $(CC) $(NATIVE_CFLAGS) $(CFLAGS) -c $*.c -o $@

%-byte.p.o: %.c $(ROOT)/mk/config
	$(MPTIME) $(CC) -p $(BYTE_CFLAGS) $(CFLAGS) -c $*.c -o $@

%-native.p.o: %.c $(ROOT)/mk/config
	$(MPTIME) $(CC) -p $(NATIVE_CFLAGS) $(CFLAGS) -c $*.c -o $@

#
clean::
	$(RM) *.run *.top *.opt *.cma *.cmxa *.cmx *.cmi* *.cmo* *.z* *.o *.a *~ *.bak *.output $(CLEAN_MAIN)
	$(RM) gmon.out $(ZMLFILES) $(ZMLIFILES) Makefile.dep

depend:: $(MLFILES) $(MLIFILES)
	$(RM) Makefile.tmp
	touch Makefile.tmp
ifneq ($(MLFILES),)
	$(MPTIME) $(OCAMLDEP) $(OCAMLDEPFLAGS) $(INCLUDE) $(MLFILES) $(MLIFILES) >> Makefile.tmp
endif
ifneq ($(CFILES),)
	$(MPTIME) $(CC) $(CFLAGS) $(CCDEPEND) $(CFILES) >> Makefile.tmp
endif
	mv Makefile.tmp Makefile.dep

Makefile.dep: Makefile $(ROOT)/mk/config $(ROOT)/mk/preface $(ROOT)/mk/rules
	+@if [ -f $(OCAMLDEP) ]; then touch Makefile.dep; $(MAKE) depend; fi
