#!/usr/bin/make -f

include /usr/share/dpkg/pkg-info.mk
include /usr/share/dpkg/buildflags.mk

PACKAGE := ocaml
ALL_PACKAGES := $(shell dh_listpackages)

# Can't use /usr/share/ocaml/ocamlvars.mk because it tries to run ocamlc
include $(CURDIR)/debian/ocamlvars.mk

# Use ccache if pkg.ocaml.ccache build-profile is active.
ifneq (,$(filter pkg.ocaml.ccache,$(DEB_BUILD_PROFILES)))
export PATH := /usr/lib/ccache:$(PATH)
export CCACHE_DIR := $(CURDIR)/debian/ccache
#export CCACHE_BASEDIR := $(CURDIR)/debian/build
$(shell mkdir -p "$(CCACHE_DIR)")
endif

# Build cache (for Debian debugging)
BUILDCACHE := $(wildcard ../ocaml.cache)

MD5SUMSDIR = /var/lib/ocaml/md5sums
INSTDIR = $(CURDIR)/debian/tmp/usr
DISTDIR = $(PACKAGE)-$(OCAML_ABI)
UPSTREAM_VERSION = $(shell dpkg-parsechangelog | awk '/^Version:/{print $$2}' | { read u; echo $${u%-*}; })
UPSTREAM_TARBALL = $(wildcard ../$(PACKAGE)_$(UPSTREAM_VERSION).orig.tar.*)
SRCTARBALL = $(PACKAGE)-source-$(OCAML_ABI).tar

TESTDIR := debian/test-build
TESTRULES := debian/rules DEB_TEST_BUILD_PREFIX=$(CURDIR)/$(TESTDIR)

BUILD_DATE := $(shell dpkg-parsechangelog --show-field=Date)

ifeq (,$(DEB_TEST_BUILD_PREFIX))
ifneq (,$(findstring ocaml-source,$(ALL_PACKAGES)))
  TARBALL_TARGET = debian/$(SRCTARBALL)
endif
endif

# Environment variable for dh_ocaml
export OCAMLOBJINFO = OCAMLLIB=tools boot/ocamlrun tools/ocamlobjinfo

# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1

export DH_OPTIONS

# This has to be exported to make dispatch work
export OCAML_OPT_ARCH
export OCAML_STDLIB_DIR

export DEB_BUILD_MAINT_OPTIONS=hardening=+bindnow
export CCLINKFLAGS=$(shell dpkg-buildflags --get LDFLAGS)

CONFIGURE_OPTS := \
  --without-zstd \
  --enable-ocamltest \
  --host $(DEB_BUILD_GNU_TYPE)\
  -prefix $(DEB_TEST_BUILD_PREFIX)/usr \
  -libdir $(DEB_TEST_BUILD_PREFIX)$(OCAML_STDLIB_DIR) \
  -mandir $(DEB_TEST_BUILD_PREFIX)/usr/share/man \

# Upstream recommends dropping support on armel, see https://github.com/ocaml/ocaml/issues/7642
# Binaries generated by ocamlopt segfault on x32
# ld reports spurious messages on powerpc, see https://github.com/ocaml/ocaml/issues/8846
ifeq (,$(OCAML_OPT_ARCH))
CONFIGURE_OPTS += --disable-native-compiler
endif

# fma does not work on m68k, enable emulation as instructed by configure script
ifeq (m68k,$(DEB_BUILD_ARCH))
CONFIGURE_OPTS += --enable-imprecise-c99-float-ops
IGNORE_TESTS_FAILURE := || true
else ifneq (,$(findstring hurd,$(DEB_BUILD_ARCH)))
IGNORE_TESTS_FAILURE := || true
else
IGNORE_TESTS_FAILURE :=
endif

# To avoid Lintian's file-references-package-build-path
export BUILD_PATH_PREFIX_MAP=.=$(CURDIR)

%:
	dh $@

# Needed because there is a "build" in the upstream tarball
.PHONY: build
build:
	dh $@

pre-config-stamp: $(TARBALL_TARGET)
# Backup upstream config.{sub,guess}, and use most up-to-date ones
	set -e; for ext in sub guess; do \
	  if [ -f /usr/share/misc/config.$$ext ] && \
	    ! [ -f debian/config.orig.$$ext ]; then \
	    mv build-aux/config.$$ext debian/config.orig.$$ext; \
	    cp -f /usr/share/misc/config.$$ext build-aux/config.$$ext; \
	  fi; \
	done
# Debian kfreebsd has non-working shims for dup3/pipe2, see #827935. Upstream
# ./configure isn't sophisticated enough to detect this so patch it out here.
ifeq (kfreebsd,$(DEB_HOST_ARCH_OS))
	sed -i -e '/HAS_DUP3/d' -e '/HAS_PIPE2/d' ./configure
endif
	touch $@

ifneq (,$(TARBALL_TARGET))
$(TARBALL_TARGET): $(UPSTREAM_TARBALL)
	mkdir -p debian/$(DISTDIR)
# Copy upstream tarball
	cp $< debian/$(DISTDIR)
# Copy debian/patches
	cp -a debian/patches debian/$(DISTDIR)/debian-patches
# Set permissions (workaround for #796257)
	chmod 755 debian/$(DISTDIR)/debian-patches
	chmod 644 debian/$(DISTDIR)/debian-patches/*
# Create the tarball and cleanup
	cd debian && find $(DISTDIR) -not -type d -print0 | \
		LC_ALL=C sort --zero-terminated | \
		tar --create --null --files-from=- \
			--file=$(abspath $@) --mtime="$(BUILD_DATE)" \
			--owner=root --group=root --numeric-owner
	rm -Rf debian/$(DISTDIR)
endif

.PHONY: override_dh_auto_configure
override_dh_auto_configure: config-stamp ocamlinit-stamp

config-stamp: pre-config-stamp
	./configure $(CONFIGURE_OPTS)
	sed -r -i '/^CFLAGS/s/-f(file|debug)-prefix-map=[^ ]* //g' Makefile.config
	touch $@

ocamlinit-stamp: $(TARBALL_TARGET) config-stamp
	$(MAKE) -f $(CURDIR)/debian/ocamlinit.mk ocamlinit-stamp

.PHONY: override_dh_auto_build
override_dh_auto_build: build-stamp

build-stamp: config-stamp
	if test ! -d boot.debian; then \
	  cp -xa boot boot.debian; \
	fi
ifeq ($(BUILDCACHE),)
	$(MAKE) world
	$(MAKE) -C tools dumpobj
ifneq (,$(OCAML_OPT_ARCH))
	@echo "Building native compilers"
	$(MAKE) opt opt.opt
	touch opt-built-stamp
endif
	@echo "Building manpages"
	$(MAKE) manpages
else
	@echo "===> WARNING: $(BUILDCACHE) detected, compilation skipped! <==="
	rsync -a --exclude=debian --exclude=.git $(BUILDCACHE)/ .
	rm -f build-stamp install-stamp*
endif
	touch $@

.PHONY: override_dh_auto_clean
override_dh_auto_clean:
ifneq ($(wildcard $(CURDIR)/Makefile.config),)
	$(MAKE) clean
endif
	$(MAKE) -f $(CURDIR)/debian/ocamlinit.mk ocamlinit-clean
# Restore files altered by the build process
	if test -d boot.debian; then \
	  rm -Rf boot; \
	  mv boot.debian boot; \
	fi
	set -e; for ext in sub guess; do \
	  if [ -f debian/config.orig.$$ext ] ; then \
	    mv -f debian/config.orig.$$ext build-aux/config.$$ext; \
	  fi; \
	done
# Remaining stuff
	-rm -Rf debian/$(SRCTARBALL) $(TESTDIR)

execute_after_dh_clean:
	rm -f install-stamp-*
	rm -f debian/installed-files debian/*.install

.PHONY: override_dh_auto_install-arch override_dh_auto_install-indep
override_dh_auto_install-arch: install-stamp-arch
override_dh_auto_install-indep: install-stamp-indep

install-stamp-indep: install-stamp
	touch $@

install-stamp-arch: install-stamp
# Install additional files not handled by dh_install
# Beware: dh_install does not handle renamings, please pay attention
	set -e; for u in dumpobj; do \
	  if [ -f tools/$$u ]; then \
	    cp tools/$$u debian/ocaml/usr/bin/ocaml$$u; \
	  fi \
	done
# Install the seq compatibility package (OCaml >= 4.07)
	mkdir -p debian/libstdlib-ocaml-dev$(OCAML_STDLIB_DIR)/seq
	cp debian/META.seq debian/libstdlib-ocaml-dev$(OCAML_STDLIB_DIR)/seq/META
# Install the uchar compatibility package (OCaml >= 4.03)
	mkdir -p debian/libstdlib-ocaml-dev$(OCAML_STDLIB_DIR)/uchar
	cp debian/META.uchar debian/libstdlib-ocaml-dev$(OCAML_STDLIB_DIR)/uchar/META
# Install the stdlib-shims compatibility package (OCaml >= 4.07)
	mkdir -p debian/libstdlib-ocaml-dev$(OCAML_STDLIB_DIR)/stdlib-shims
	cp debian/META.stdlib-shims debian/libstdlib-ocaml-dev$(OCAML_STDLIB_DIR)/stdlib-shims/META
# Install the bigarray compatibility package (OCaml >= 5.2)
	mkdir -p debian/libstdlib-ocaml-dev$(OCAML_STDLIB_DIR)/bigarray
	cp debian/META.bigarray debian/libstdlib-ocaml-dev$(OCAML_STDLIB_DIR)/bigarray/META
# Install the bytes compatibility package (OCaml >= 5.2)
	mkdir -p debian/libstdlib-ocaml-dev$(OCAML_STDLIB_DIR)/bytes
	cp debian/META.bytes debian/libstdlib-ocaml-dev$(OCAML_STDLIB_DIR)/bytes/META
# Remaining stuff
	touch $@

install-stamp:
# Install OCaml
	$(MAKE) install DESTDIR=$(CURDIR)/debian/tmp
ifeq (,$(DEB_TEST_BUILD_PREFIX))
# Remove Debian-specific file
	rm -f debian/tmp$(OCAML_STDLIB_DIR)/ld.conf
# Remove uninstalled files
	rm -f \
	  $(INSTDIR)/share/man/man1/ocamlopt.opt.1 \
	  $(INSTDIR)/share/man/man1/ocamlc.opt.1
ifeq ($(OCAML_HAVE_OCAMLOPT),no)
# Remove files that make no sense without ocamlopt
	rm -f \
	  $(INSTDIR)/share/man/man1/ocamloptp.1 \
	  $(INSTDIR)/share/man/man1/ocamlopt.1 \
	  $(INSTDIR)/bin/ocamloptp.* \
	  $(INSTDIR)/bin/ocamloptp
endif
# Remove irrelevant files
	rm -f \
	  $(INSTDIR)/share/doc/ocaml/README.win32.adoc \
	  $(INSTDIR)/share/doc/ocaml/LICENSE
# Dispatch files with dh_install
	find debian/tmp \( -type f -or -type l \) -printf '%P\n' > debian/installed-files
	boot/ocamlrun ./ocaml -nostdlib -I debian/tmp$(OCAML_STDLIB_DIR) debian/dispatch.ml
	dh_install
endif
	touch $@

.PHONY: override_dh_gencontrol
override_dh_gencontrol:
	set -e; for u in ocaml-source ocaml-interp ocaml-base ocaml; do \
	  echo 'F:OCamlABI=$(OCAML_ABI)' >> debian/$$u.substvars; \
	done
ifeq (,$(OCAML_OPT_ARCH))
	echo 'F:NativeProvides=' >> debian/ocaml.substvars
else
	echo 'F:NativeProvides=ocaml-native-compilers (= $${binary:Version})' >> debian/ocaml.substvars
endif
# Create .md5sums files and compute dependencies.
	dh_ocaml
	dh_gencontrol
# Check that OCAML_ABI is correct
	if [ "$(OCAML_ABI)" != "$(shell boot/ocamlrun ./ocamlc -version | { read a && echo $${a%%_*}; })" ]; then \
	  echo "Please adjust OCAML_ABI in debian/rules"; \
	  exit 2; \
	fi

.PHONY: regenerate
regenerate: debian/control
	git ls-tree --name-only -r HEAD debian \
	  | grep -v '^debian/\(patches/\|source/local-\)' \
	> debian/MANIFEST

# Architectures where running the test suite completely makes the
# whole build last more than 30 minutes on buildds. Originally,
# because some tests do not even finish on mips.
SLOW_ARCHITECTURES := armel armhf ia64 mips mipsel powerpc powerpcspe sparc

.PHONY: override_dh_auto_test
override_dh_auto_test:
ifeq (,$(findstring nocheck,$(DEB_BUILD_OPTIONS)))
	: # tries to connect the net
	rm -f testsuite/tests/lib-threads/sockets.*
	: # FIXME: the following test fails, we temporarily disable it
	rm -rf testsuite/tests/tool-debugger/find-artifacts/
ifeq ($(DEB_BUILD_ARCH),arm64)
	: # the following test is flaky, see #1103008
	rm -f testsuite/tests/lib-runtime-events/test_dropped_events.ml
endif
ifneq (,$(filter $(DEB_BUILD_ARCH),$(SLOW_ARCHITECTURES)))
	rm -f testsuite/tests/misc-unsafe/almabench.ml
endif
ifeq (,$(DEB_TEST_BUILD_PREFIX))
	OCAML_TEST_SIZE=1 make tests $(IGNORE_TESTS_FAILURE)
endif
endif

.PHONY: override_dh_installdocs
override_dh_installdocs:
	dh_installdocs --package=ocaml-base --doc-main-package=ocaml
	dh_installdocs --remaining-packages

override_dh_autoreconf:
	./tools/autogen
