####################################################################
#         Makefile rules for compiling ocaml programs              #
####################################################################

####################################################################
### Try to automatically guess OS

ifeq (${OSCOMP},cross) # Cross-compilation under Linux
  OSARCH=win32gnuc
  PATH := /usr/i586-mingw32msvc/bin:$(PATH)
endif

ifeq (${OSCOMP},cygwingnuc) # Define this if compiling with Cygwin GNU C
  OSARCH=win32gnuc
  ETAGS=/bin/etags
  buildexecutable:: win32rc/unison.res.lib
else
# Win32 system
ifeq (${OSTYPE},cygwin32) # Cygwin Beta 19
  OSARCH=win32
  ETAGS=/bin/etags
else
ifeq (${OSTYPE},cygwin)	  # Cygwin Beta 20
  OSARCH=win32
  ETAGS=/bin/etags
else

# Unix system
ifeq ($(shell uname),SunOS)
  OSARCH=solaris
else
ifeq ($(shell uname),Darwin)
  OSARCH=osx
else
ifeq ($(shell uname),OpenBSD)
  OSARCH=OpenBSD
else
ifeq ($(shell uname),NetBSD)
  OSARCH=NetBSD
endif
endif
endif
endif
ETAGS=etags
endif
endif
endif

# The OCaml lib dir is used by all versions
# It is extracted from 'ocamlc -v' and Windows '\' separators are turned
# to Unix '/' separators, and extraneous control-M's are deleted.
# Unfortunately there is a literal control-M buried in this, I'd rather
# get rid of it...
# OCAMLLIBDIR=$(shell ocamlc -v | tail -1 | sed -e 's/.* //g' | sed -e 's/\\/\//g' | sed -e 's///g')
# Better(?) version, June 2005:
OCAMLLIBDIR=$(shell ocamlc -v | tail -1 | sed -e 's/.* //g' | sed -e 's/\\/\//g' | tr -d '\r')

## BCP (6/05) an alternative, but not quite working, version
## suggested by Nick Montfort:
# OCAMLLIBDIR=$(shell ocamlc -v | sed -n '$p' | sed -e 's/^Standard library directory: //' | sed -e 's/\\/\//g' | sed -e 's/\r//g')

# User interface style:
#   Legal values are
#     UISTYLE=text
#     UISTYLE=gtk
#     UISTYLE=gtk2
#     UISTYLE=mac       (old and limited, but working)
#     UISTYLE=macnew    (spiffier)
#     UISTYLE=macnew09  (even spiffier, but not yet extensively tested)
#
# This should be set to an appropriate value automatically, depending
# on whether the lablgtk library is available
LABLGTKLIB=$(OCAMLLIBDIR)/lablgtk
LABLGTK2LIB=$(OCAMLLIBDIR)/lablgtk2
##BCP [3/2007]: Removed temporarily, since the OSX UI is not working well 
## at the moment and we don't want to confuse people by building it by default
ifeq ($(OSARCH),osx)
  UISTYLE=macnew
else
  ifeq ($(wildcard $(LABLGTK2LIB)),$(LABLGTK2LIB))
    UISTYLE=gtk2
  else
    UISTYLE=text
endif
endif
buildexecutable::
	@echo UISTYLE = $(UISTYLE)

####################################################################
### Default parameters

INCLFLAGS=-I lwt -I ubase -I system
CAMLFLAGS+=$(INCLFLAGS)
CAMLFLAGS+=-I system/$(SYSTEM) -I lwt/$(SYSTEM)

ifeq ($(OSARCH),win32)
  # Win32 system
  EXEC_EXT=.exe
  OBJ_EXT=.obj
  OUTPUT_SEL=/Fo
  CWD=.
#  Fix suggested by Karl M, Jan 2009:
#    "The new flexlink wrapper that OCaml 3.11 uses was gagging on the res
#    file. So the res file has to be passed through flexlink untouched to
#    the linker.  I only touched the MSVC side, but mingw may have the same
#    issue."
#  CLIBS+=-cclib win32rc/unison.res
#  STATICLIBS+=-cclib win32rc/unison.res
  COBJS+=system/system_win_stubs$(OBJ_EXT) lwt/lwt_unix_stubs$(OBJ_EXT)
  WINOBJS=system/system_win.cmo
  SYSTEM=win
  CLIBS+=-cclib "-link win32rc/unison.res" shell32.lib
  STATICLIBS+=-cclib "-link win32rc/unison.res" shell32.lib
  buildexecutable::
	@echo Building for Windows
else
  # Unix system, or Cygwin with GNU C compiler
  OBJ_EXT=.o
  OUTPUT_SEL="-o "
  ifeq ($(OSARCH),win32gnuc)
    CWD=.
    EXEC_EXT=.exe
    COBJS+=system/system_win_stubs$(OBJ_EXT) lwt/lwt_unix_stubs$(OBJ_EXT)
    WINOBJS=system/system_win.cmo
    SYSTEM=win
    CLIBS+=-cclib win32rc/unison.res.lib
    STATIC=false                      # Cygwin is not MinGW :-(
    buildexecutable::
	@echo Building for Windows with Cygwin GNU C
  else
    CWD=$(shell pwd)
    EXEC_EXT=
    WINOBJS=
    SYSTEM=generic
    # openpty is in the libutil library
    ifneq ($(OSARCH),solaris)
      ifneq ($(OSARCH),osx)
        CLIBS+=-cclib -lutil
      endif
    endif
    buildexecutable::
	@echo Building for Unix
  endif
endif

.PHONY: buildexecutable
buildexecutable::
	@echo NATIVE = $(NATIVE)
	@echo THREADS = $(THREADS)
	@echo STATIC = $(STATIC)
	@echo OSTYPE = $(OSTYPE)
	@echo OSARCH = $(OSARCH)

ubase/projectInfo.ml: Makefile.ProjectInfo
	echo 'let myName = "'$(NAME)'";;' > $@
	echo 'let myVersion = "'$(VERSION)'";;' >> $@
	echo 'let myMajorVersion = "'$(MAJORVERSION)'";;' >> $@

clean::
	$(RM) ubase/projectInfo.ml

####################################################################
### Unison objects and libraries

ifeq ($(UISTYLE),mac)
  buildexecutable:: macexecutable
  UIMACDIR=uimac
else
ifeq ($(UISTYLE),macnew)
  buildexecutable:: macexecutable
  UIMACDIR=uimacnew
else
ifeq ($(UISTYLE),macnew09)
  buildexecutable:: macexecutable
  UIMACDIR=uimacnew09
else
  buildexecutable:: $(NAME)$(EXEC_EXT)
endif
endif
endif

MINOSXVERSION=10.5
# XCODEFLAGS=-sdk macosx$(MINOSXVERSION)
ifeq ($(OSARCH),osx)
  CAMLFLAGS+=-ccopt -mmacosx-version-min=$(MINOSXVERSION)
endif

# NOTE: the OCAMLLIBDIR is not getting passed correctly?
# The two cases for cltool are needed because Xcode 2.1+
# builds in build/Default/, and earlier versions use build/
.PHONY: macexecutable
macexecutable: 
#	sed -e's/@@VERSION@@/$(VERSION)/' $(UIMACDIR)/Info.plist.template > $(UIMACDIR)/Info.plist
	(cd $(UIMACDIR); xcodebuild $(XCODEFLAGS) OCAMLLIBDIR="$(OCAMLLIBDIR)" SYMROOT=build)
	if [ -e $(UIMACDIR)/build/Default ]; then \
	  gcc -mmacosx-version-min=$(MINOSXVERSION) $(UIMACDIR)/cltool.c -o $(UIMACDIR)/build/Default/Unison.app/Contents/MacOS/cltool -framework Carbon; \
	else \
	  gcc -mmacosx-version-min=$(MINOSXVERSION) $(UIMACDIR)/cltool.c -o $(UIMACDIR)/build/Unison.app/Contents/MacOS/cltool -framework Carbon; \
	fi

# OCaml objects for the bytecode version
# File extensions will be substituted for the native code version

OCAMLOBJS += \
          ubase/rx.cmo \
	  \
          unicode_tables.cmo unicode.cmo bytearray.cmo \
          $(WINOBJS) system/system_generic.cmo \
          system/$(SYSTEM)/system_impl.cmo \
          system.cmo \
          \
          ubase/projectInfo.cmo ubase/myMap.cmo ubase/safelist.cmo \
          ubase/uprintf.cmo ubase/util.cmo ubase/uarg.cmo \
          ubase/prefs.cmo ubase/trace.cmo ubase/proplist.cmo \
          \
          lwt/pqueue.cmo lwt/lwt.cmo lwt/lwt_util.cmo \
          lwt/$(SYSTEM)/lwt_unix_impl.cmo lwt/lwt_unix.cmo \
          \
          case.cmo pred.cmo uutil.cmo \
          fileutil.cmo name.cmo path.cmo fspath.cmo fs.cmo fingerprint.cmo \
          abort.cmo osx.cmo external.cmo \
          props.cmo fileinfo.cmo os.cmo lock.cmo clroot.cmo common.cmo \
          tree.cmo checksum.cmo terminal.cmo \
          transfer.cmo xferhint.cmo remote.cmo globals.cmo \
          fpcache.cmo update.cmo copy.cmo stasher.cmo \
	  files.cmo sortri.cmo recon.cmo transport.cmo \
          strings.cmo uicommon.cmo uitext.cmo test.cmo

OCAMLOBJS+=main.cmo

# OCaml libraries for the bytecode version
# File extensions will be substituted for the native code version
OCAMLLIBS+=unix.cma str.cma bigarray.cma

COBJS+=osxsupport$(OBJ_EXT) pty$(OBJ_EXT) bytearray_stubs$(OBJ_EXT)

########################################################################
### User Interface setup

## Text UI
ifeq ($(UISTYLE), text)
  OCAMLOBJS+=linktext.cmo
endif

## Old Mac UI
ifeq ($(UISTYLE),mac)
  OCAMLOBJS+=uimacbridge.cmo
endif

## New Mac UI
ifeq ($(UISTYLE),macnew)
  OCAMLOBJS+=uimacbridgenew.cmo
  THREADS=true
  OCAMLLIBS+=threads.cma
  INCLFLAGS+=-thread 
endif

## New Mac UI, 2009 version
ifeq ($(UISTYLE),macnew09)
  OCAMLOBJS+=uimacbridgenew.cmo
  THREADS=true
  OCAMLLIBS+=threads.cma
  INCLFLAGS+=-thread 
endif

## Graphic UI

# Setup the lib directories

# Win32 system : this very Makefile must be used with GNU Make, so that we
#                expect CygWin Bash to be used.
# The directory must be provided following one of the model below :
# - unix, relative      ../../ocaml/lib/labltk
# - unix, absolute      d:/home/foobar/ocaml/lib/labltk
# -  dos, relative      ..\\..\\ocaml\\lib\\labltk
# -  dos, absolute      d:\\home\\foobar\\ocaml\\lib\\labltk

# Patch to make a Windows GUI version come up with no
# console when click-started
#  ifeq ($(OSARCH), win32)
#    COBJS+=winmain.c
#    CFLAGS+=-cclib /subsystem:windows
#  endif

# Gtk GUI
ifeq ($(UISTYLE), gtk)
  CAMLFLAGS+=-I +lablgtk
  OCAMLOBJS+=pixmaps.cmo uigtk.cmo linkgtk.cmo
  OCAMLLIBS+=lablgtk.cma
endif

# Gtk2 GUI
ifeq ($(UISTYLE), gtk2)
  CAMLFLAGS+=-I +lablgtk2
  OCAMLOBJS+=pixmaps.cmo uigtk2.cmo linkgtk2.cmo
  OCAMLLIBS+=lablgtk.cma
endif

####################################################################
### Static build setup

ifeq ($(STATIC), true)
  CFLAGS+=-cclib -static
endif

####################################################################
### Dependencies

# Include an automatically generated list of dependencies
include .depend
# Additional dependencied depending on the system
system.cmo fspath.cmo fs.cmo: system/$(SYSTEM)/system_impl.cmo
system.cmx fspath.cmx fs.cmx: system/$(SYSTEM)/system_impl.cmx
lwt/lwt_unix.cmo: lwt/$(SYSTEM)/lwt_unix_impl.cmo
lwt/lwt_unix.cmx: lwt/$(SYSTEM)/lwt_unix_impl.cmx

ifeq ($(OSARCH), OpenBSD)
  ifeq ($(shell echo type ocamldot | ksh), file)
    OCAMLDOT=true
  endif
else
  ifeq ($(shell echo type -t ocamldot | bash), file)
    OCAMLDOT=true
  endif
endif

ifeq ($(OSARCH), NetBSD)
  OCAMLDOT=false
endif

# Rebuild dependencies (must be invoked manually)
.PHONY: depend
depend::
	ocamldep $(INCLFLAGS) *.mli *.ml */*.ml */*.mli */*/*.ml */*/*.mli > .depend
ifdef OCAMLDOT
	echo 'digraph G {' > dot.tmp
	echo '{ rank = same; "Fileinfo"; "Props"; "Fspath"; "Os"; "Path"; }'\
           >>dot.tmp
	echo '{ rank = same; "Uitext"; "Uigtk"; }'>>dot.tmp
	echo '{ rank = same; "Recon"; "Update"; "Transport"; "Files"; }'\
           >>dot.tmp
	echo '{ rank = same; "Tree"; "Safelist"; }'>>dot.tmp
	echo '{ rank = same; "Uarg"; "Prefs"; }'>>dot.tmp
	ocamldot .depend | tail -n +2 >> dot.tmp
	-dot -Tps -o DEPENDENCIES.ps dot.tmp
endif

####################################################################
### Compilation boilerplate

ifeq ($(DEBUGGING), false)
  ifneq ($(OSARCH), win32)
    ifneq ($(OSARCH), osx)
      # Strip the binary (does not work with MS compiler; might not work
      # under OSX)
      CFLAGS+=-cclib -Wl,-s
    endif
  endif
endif

ifeq ($(PROFILING), true)
  OCAMLC=ocamlcp
else
  OCAMLC=ocamlc
endif
OCAMLOPT=ocamlopt

ifeq ($(NATIVE), true)
  ## Set up for native code compilation

  CAMLC=$(OCAMLOPT)
  ifeq ($(PROFILING), true)
    CAMLFLAGS+=-p
    CLIBS+=-cclib -ldl
  endif

  CAMLOBJS=$(subst .cmo,.cmx, $(subst .cma,.cmxa, $(OCAMLOBJS)))
  CAMLLIBS=$(subst .cma,.cmxa, $(OCAMLLIBS))

else
  ## Set up for bytecode compilation

  CAMLC=$(OCAMLC)
  CAMLFLAGS+=-custom
  ifeq ($(DEBUGGING), true)
    CAMLFLAGS+=-g
  endif

  CAMLOBJS=$(OCAMLOBJS)
  CAMLLIBS=$(OCAMLLIBS)

endif

win32rc/unison.res: win32rc/unison.rc win32rc/U.ico
	windres win32rc/unison.rc win32rc/unison.res

win32rc/unison.res.lib: win32rc/unison.res
	windres win32rc/unison.res win32rc/unison.res.lib

%.ml: %.mll
	-$(RM) $@
	ocamllex $<

%.cmi : %.mli
	@echo "$(CAMLC): $< ---> $@"
	$(CAMLC) $(CAMLFLAGS) -c $(CWD)/$<

%.cmo: %.ml
	@echo "$(OCAMLC): $< ---> $@"
	$(OCAMLC) $(CAMLFLAGS) -c $(CWD)/$<

%.cmx: %.ml
	@echo "$(OCAMLOPT): $< ---> $@"
	$(OCAMLOPT) $(CAMLFLAGS) -c $(CWD)/$<

%.o %.obj: %.c
	@echo "$(OCAMLOPT): $< ---> $@"
	$(CAMLC) $(CAMLFLAGS) -ccopt $(OUTPUT_SEL)$(CWD)/$@ -c $(CWD)/$<

$(NAME)$(EXEC_EXT): $(CAMLOBJS) $(COBJS)
	@echo Linking $@
	$(CAMLC) -verbose $(CAMLFLAGS) -o $@ $(CFLAGS) $(CAMLLIBS) $^ $(CLIBS)

# Unfortunately -output-obj does not put .o files into the output, only .cmx
# files, so we have to use $(LD) to take care of COBJS.
$(NAME)-blob.o: $(CAMLOBJS) $(COBJS)
	@echo Linking $@
	$(CAMLC) -dstartup -output-obj -verbose -cclib -keep_private_externs $(CAMLFLAGS) -o u-b.o $(CFLAGS) $(CAMLLIBS) $(CLIBS) $(CAMLOBJS)
	$(LD) -r -keep_private_externs -o $@ u-b.o $(COBJS)
	$(RM) u-b.o


# Original:
# $(NAME)-blob.o: $(CAMLOBJS) $(COBJS)
# 	@echo Linking $@
# 	$(CAMLC) -output-obj -verbose $(CAMLFLAGS) -o u-b.o $(CFLAGS) $(CAMLLIBS) $(CLIBS) $(CAMLOBJS)
# 	$(LD) -r -o $@ u-b.o $(COBJS)
# 	$(RM) u-b.o

%$(EXEC_EXT): %.ml
	$(OCAMLC) -verbose -o $@ $^

######################################################################
### Misc

clean::
	-$(RM) -r *.cmi *.cmo *.cmx *.cma *.cmxa TAGS tags
	-$(RM) -r *.o core gmon.out *~ .*~
	-$(RM) -r *.obj *.lib *.exp
	-$(RM) -r *.tmp *.bak?.tmp .*.bak?.tmp
	-$(RM) system/*.cm[iox] system/*.{o,obj} system/win/*~
	-$(RM) system/generic/*.cm[iox] system/generic/*.{o,obj} system/generic/*~
	-$(RM) system/win/*.cm[iox] system/win/*.{o,obj} system/win/*~

.PHONY: paths
paths:
	@echo PATH = $(PATH)
	@echo OCAMLLIBDIR = $(OCAMLLIBDIR)

