ifneq ($(filter-out archives cache-archives lib-pkg,$(MAKECMDGOALS)),)
-include ../Makefile.config
endif

ifneq ($(wildcard Makefile.config),)
include Makefile.config
CAN_PKG=1
else
CAN_PKG=0
endif

PATCH ?= patch

URL_ocaml = https://caml.inria.fr/pub/distrib/ocaml-4.13/ocaml-4.13.1.tar.gz
MD5_ocaml = a55ca12a4e6edf83cb4777abdb7b2f4d

URL_flexdll = https://github.com/alainfrisch/flexdll/archive/0.40.tar.gz
MD5_flexdll = e68f7311179fa7e09408825b362c5c5a

ifndef FETCH
  ifneq ($(shell command -v curl 2>/dev/null),)
    FETCH = curl -LSfs -o $(2) $(1)
  else
    FETCH = wget -O $(2) $(1)
  endif
endif

# Shorthand for designating that lib-ext and lib-pkg use the same version of a library
PKG_SAME = $(eval $(call PKG_SAME_DEFS,$(1)))
define PKG_SAME_DEFS
URL_PKG_$(1) = $(URL_$(1))
MD5_PKG_$(1) = $(MD5_$(1))
endef

SRC_EXTS = cppo base64 extlib re cmdliner ocamlgraph cudf dose3 opam-file-format result seq stdlib-shims
PKG_EXTS = $(SRC_EXTS) dune-local findlib ocamlbuild topkg mccs

ifeq ($(MCCS_ENABLED),true)
SRC_EXTS := $(SRC_EXTS) mccs
endif

ifeq ($(OPAM_0INSTALL_SOLVER_ENABLED),true)
SRC_EXTS := $(SRC_EXTS) opam-0install-cudf 0install-solver
endif

include Makefile.sources
ifneq ($(shell PATH="$(PATH)" command -v ocamlc 2>/dev/null),)
include Makefile.packages
endif

ARCHIVES = $(foreach lib,$(SRC_EXTS),$(notdir $(URL_$(lib))))
lib_of = $(foreach lib,$(SRC_EXTS),$(if $(findstring $(1),$(URL_$(lib))),$(lib),,))

ARCHIVE_FILE = $(1)$(patsubst %.tbz,.tbz,$(patsubst %.tar.gz,.tar.gz,$(URL_$(2)$(1))))
DOWNLOAD_COOKIE = touch $(1).$(4)download && \
                  $(if $(filter $(MD5_$(2)$(1)),$(MD5_$(3)$(1))),touch,rm -f) $(1).$(5)download && \
                  rm -f $(call ARCHIVE_FILE,$(1),$(2)) $(1).stamp $(1).pkgbuild

ifdef OCAML
# Portable md5check
MD5CHECK = $(OCAML) ../shell/md5check.ml $(1) $(2)
else
MD5CHECK = { \
  sum=`md5sum $(1) | sed -e 's/^[^a-f0-9]*\([a-f0-9]*\).*/\1/'`; \
  { test "$$sum" = "$(2)" && echo '$(1) has the expected MD5.'; } || \
  { rm -f $(1); \
    echo 'MD5 for $(1) differs:'; \
    echo '  expected: $(2)'; \
    echo "    actual: $$sum"; \
    false; \
  }; \
}
endif

lib-ext: clone ensure-seq-patched.stamp
	@

ifeq ($(CAN_PKG),1)
lib-pkg: clone-pkg build-pkg
	@
else
lib-pkg:
	@echo "Installation of packages is only permitted for the bootstrap compiler"
	@echo "Run $(MAKE) [OCAML_PORT=auto|msvc|msvc64|mingw|mingw64] compiler first"
	@false
endif

.PHONY: lib-pkg-urls
lib-pkg-urls:
	@$(foreach i,$(PKG_EXTS),$(info $i $(URL_PKG_$i)))
	@find patches -type f | grep '\.\(pkg\|common\)/' | xargs sha1sum

reset-lib-pkg:
	@rm -f ../bootstrap/ocaml/bin/ocamlbuild* ../bootstrap/ocaml/bin/ocamlfind* `ls ../bootstrap/ocaml/bin/* | grep -v "flexlink\|\/ocaml[^\/]*$$"` ../bootstrap/ocaml/lib/topfind
	@rm -rf ../bootstrap/ocaml/lib/ocaml/site-lib ../bootstrap/ocaml/etc *.pkgbuild

ifeq ($(DUNE),)
DUNE_DEP=dune-local/_boot/dune$(EXE)
DUNE_CLONE=dune-local.stamp
ifeq ($(shell command -v cygpath 2>/dev/null),)
DUNE:=$(DUNE_DEP)
else
DUNE:=$(shell echo "$(DUNE_DEP)" | cygpath -f - -a)
endif
else
DUNE_DEP=
DUNE_CLONE=
endif

dune-local/_boot/dune$(EXE): $(DUNE_CLONE)
	cd dune-local && ocaml boot/bootstrap.ml

build-pkg: clone-pkg $(PKG_EXTS:=.pkgbuild)
	@

%.pkgbuild: | %.pkgstamp
	@rm -f $*.pkgstamp
	$(MAKE) MAKEFLAGS= -f ../Makefile.packages -C $* $*-pkg-build && touch $@

.PHONY: ext-ignore
ext-ignore:
	@echo "; This file is automatically generated" > dune
	@echo "(dirs :standard \ dune-local $(filter-out dune-local $(SRC_EXTS),$(PKG_EXTS)))" >> dune
	@echo "(vendored_dirs $(SRC_EXTS))" >> dune

clone: $(DUNE_CLONE) $(SRC_EXTS:=.stamp) | ext-ignore
	@

.PHONY: pkg-ignore
pkg-ignore:
	@echo "; This file is automatically generated" > dune
	@echo "(dirs :standard \ $(PKG_EXTS))" >> dune

clone-pkg: $(PKG_EXTS:=.pkgstamp) | pkg-ignore
	@

.PHONY: archives
archives: $(SRC_EXTS:=.download)
	@

archives-pkg: $(PKG_EXTS:=.pkgdownload)
	@

cache-archives: $(SRC_EXTS:=.cache) $(PKG_EXTS:=.pkgcache) ocaml.cache flexdll.cache
	@

has-archives: $(addprefix archives/, $(notdir $(URL_ocaml)) $(notdir $(URL_flexdll)) $(ARCHIVES) $(filter-out $(ARCHIVES), $(foreach pkg,$(PKG_EXTS), $(notdir $(URL_PKG_$(pkg))))))
	@

define cache_url
https://opam.ocaml.org/cache/md5/$(shell echo $(MD5_$(2)$(1)) | cut -c -2)/$(MD5_$(2)$(1))
endef

GET_ARCHIVE=\
  { { { $(call FETCH,$(URL_$(2)$(1)),$(call ARCHIVE_FILE,$(1),$(2))) && $(call MD5CHECK,$(call ARCHIVE_FILE,$(1),$(2)),$(MD5_$(2)$(1))); } \
      || { echo 'Failed to download $(URL_$(2)$(1))'; false; }; } || \
    { { $(call FETCH,$(call cache_url,$(1),$(2)),$(call ARCHIVE_FILE,$(1),$(2))) && $(call MD5CHECK,$(call ARCHIVE_FILE,$(1),$(2)),$(MD5_$(2)$(1))) && echo 'Warning: downloaded $(URL_$(2)$(1)) from opam cache'; } \
      || { echo 'Failed to download $(1) from opam cache'; false; }; }; }

%.cache:
	@mkdir -p archives
	@test -e archives/$(notdir $(URL_$*)) || \
          { $(call GET_ARCHIVE,$*) && mv $(call ARCHIVE_FILE,$*) archives/$(notdir $(URL_$*)); }

%.pkgcache:
	@mkdir -p archives
	@test -e archives/$(notdir $(URL_$*)) || \
          { $(call GET_ARCHIVE,$*,PKG_) && mv $(call ARCHIVE_FILE,$*,PKG_) archives/$(notdir $(URL_PKG_$*)); }

%.download: Makefile.sources
	@$(call DOWNLOAD_COOKIE,$*,,PKG_,,pkg)
	[ -e $(call ARCHIVE_FILE,$*) ] || \
	cp archives/$(notdir $(URL_$*)) $(call ARCHIVE_FILE,$*) 2>/dev/null || $(call GET_ARCHIVE,$*)

%.pkgdownload: Makefile.sources
	@$(call DOWNLOAD_COOKIE,$*,PKG_,,pkg)
	[ -e $(call ARCHIVE_FILE,$*,PKG_) ] || \
	cp archives/$(notdir $(URL_PKG_$*)) $(call ARCHIVE_FILE,$*,PKG_) 2>/dev/null || $(call GET_ARCHIVE,$*,PKG_)

%.stamp: %.download
	mkdir -p tmp-$*
	cd tmp-$* && $(if $(patsubst %.tar.gz,,$(URL_$*)),bunzip2,gunzip) -c ../$(call ARCHIVE_FILE,$*) | tar xf -
	rm -rf $*
	@for ii in tmp-$*/*; do if [ -d $${ii} ]; then mv $${ii} $*; fi; done; \
	rm -rf tmp-$*
	@if [ -d patches/$*.common ]; then \
          cd $* && \
	  for p in ../patches/$*.common/*.patch; do \
	    $(PATCH) -p1 < $$p; \
	  done; \
        fi
	@if [ -d patches/$* ]; then \
          cd $* && \
	  for p in ../patches/$*/*.patch; do \
	    $(PATCH) -p1 < $$p; \
	  done; \
        fi
	@if [ "$*" != "dune-local" ] ; then \
     for j in $(wildcard dune-$* dune-$*-*); do \
       cp $$j $*$$(echo "$$j" | sed -e "s/dune-$*//" -e "s|-|/|g")/dune; \
       echo "(lang dune 1.2)" > $*/dune-project; \
       echo "(name $*)" >> $*/dune-project; \
       touch $*/$*.opam; \
     done; \
   fi
	@touch $@ && rm -f $*.pkgstamp $*.pkgbuild

%.pkgstamp: %.pkgdownload
	mkdir -p tmp-$*
	cd tmp-$* && tar xf$(if $(patsubst %.tar.gz,,$(call ARCHIVE_FILE,$*,PKG_)),j,z) ../$(call ARCHIVE_FILE,$*,PKG_)
	rm -rf $*
# On Cygwin, the mv has a tedious habit of sometimes failing, hence the slightly odd repetition
	@for ii in tmp-$*/*; do if [ -d $${ii} ]; then mv $${ii} $* || mv $${ii} $*; fi; done; \
	rm -rf tmp-$*
	@if [ -d patches/$*.common ]; then \
          cd $* && \
	  for p in ../patches/$*.common/*.patch; do \
	    $(PATCH) -p1 < $$p; \
	  done; \
        fi
	@if [ -d patches/$*.pkg ]; then \
          cd $* && \
	  for p in ../patches/$*.pkg/*.patch; do \
	    $(PATCH) -p1 < $$p; \
	  done; \
        fi
	@touch $@ && rm -f $*.stamp

clean:
	@

distclean: clean
	rm -rf dune-local secondary $(SRC_EXTS) $(PKG_EXTS)
	rm -f *.tar.gz *.tbz *.*stamp *.*download *.pkgbuild dune \
        Makefile.config
	[ -d archives ] && ([ "$$(find archives -maxdepth 0 -type d -empty)" != "" ] && rmdir archives || echo "WARNING! $$(pwd)/archives/ not empty so left") || true
