#!/usr/bin/make -f

include /usr/share/dpkg/architecture.mk

# We do not care about distro's LTO preferences.
DEB_BUILD_MAINT_OPTIONS += optimize=-lto

HALIDE_VERSION = 17

HALIDE_SOVERSION = 2

COMPILER_LLVM_VERSION = 18

HALIDE_LLVM_VERSION = 17
HALIDE_LLVM_CMAKE_VERSION = 17

WITH_PYTHON = ON
WITH_LTO = OFF
WITH_TESTS = ON
WITH_PGO = OFF
WITH_LLD = OFF

ifeq ($(DEB_HOST_ARCH),amd64)
	WITH_LTO = ON
	WITH_TESTS = ON
	WITH_PGO = ON
	WITH_LLD = ON
endif

ifeq ($(DEB_HOST_ARCH),i386)
# The Python bindings aren't supported (or tested) on any 32-bit target.
# https://github.com/halide/Halide/issues/7679#issuecomment-1632872124
	WITH_PYTHON = OFF

	WITH_LTO = ON
	WITH_TESTS = ON
	WITH_PGO = ON
	WITH_LLD = ON
endif

ifeq ($(DEB_HOST_ARCH),arm64)
	WITH_LTO = ON
	WITH_TESTS = ON
	WITH_PGO = ON
	WITH_LLD = ON
endif

ifneq (,$(filter nolto,$(DEB_BUILD_OPTIONS)))
	# Respect nolto.
	WITH_LTO = OFF
endif

ifneq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
	# Respect nocheck.
	WITH_TESTS = OFF
	# If we aren't allowed to run tests, then certainly no PGO either.
	WITH_PGO = OFF
endif

ifneq (,$(filter nopgo,$(DEB_BUILD_OPTIONS)))
	# Respect nopgo.
	WITH_PGO = OFF
endif

CC = clang-$(COMPILER_LLVM_VERSION)
CXX = clang++-$(COMPILER_LLVM_VERSION)

SOURCE_DIR = $(CURDIR)
BUILDSPACE = $(SOURCE_DIR)-build

BUILD_STAGE ?= 2
STAGE_COMPILE_FLAGS ?=

CFLAGS = -g

# DWZ supports, at most, DWARF4, while the default is DWARF5.
CFLAGS += -fdebug-default-version=4

CFLAGS += $(STAGE_COMPILE_FLAGS)

ifneq ($(WITH_LLD),OFF)
	CFLAGS += -fuse-ld=lld-$(COMPILER_LLVM_VERSION) -Wl,--build-id=sha1
endif

CXXFLAGS = $(CFLAGS)

PROFILE_DIR = $(BUILDSPACE)/profile
PROFILE_TMP_DIR = $(PROFILE_DIR)/raw
LLVM_PROFILE_FILE = "$(PROFILE_TMP_DIR)/stage-$(BUILD_STAGE)-%p-%m.profraw"
PROFILE = $(PROFILE_DIR)/default.profdata

BUILD_DIR_PREFIX = $(BUILDSPACE)/build

STAGE_BUILD_DIR_PREFIX = $(BUILD_DIR_PREFIX)/stage-$(BUILD_STAGE)
BUILD_DIR = $(STAGE_BUILD_DIR_PREFIX)/halide
INSTALL_DIR = $(STAGE_BUILD_DIR_PREFIX)/halide-install
APPS_BUILD_DIR = $(STAGE_BUILD_DIR_PREFIX)/halide-test-apps

# Certain halide tests are sensitive to system load, and may be flaky.
TEST_GROUPS_MULTITHREADED = multithreaded
TEST_GROUPS_PERFORMANCE = performance
TEST_GROUPS_FLAKY = auto_schedule
CTEST_OPTIONS = --timeout 2400 --repeat until-pass:5 --output-on-failure

%:
ifneq ($(WITH_PYTHON),OFF)
	dh $@ --with python3 --buildsystem=cmake+ninja
else
	dh $@                --buildsystem=cmake+ninja
endif

perform_stage_build:
	LLVM_PROFILE_FILE=$(LLVM_PROFILE_FILE) dh_auto_configure --sourcedir=$(SOURCE_DIR) --builddir=$(BUILD_DIR) -- \
	-DCMAKE_C_COMPILER=$(CC) \
	-DCMAKE_CXX_COMPILER=$(CXX) \
	-DCMAKE_C_FLAGS="$(CFLAGS)" \
	-DCMAKE_CXX_FLAGS="$(CXXFLAGS)" \
	-DCMAKE_BUILD_TYPE=Release \
	-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=$(WITH_LTO) \
	-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
	-DHalide_ENABLE_RTTI=ON \
	-DHalide_ENABLE_EXCEPTIONS=ON \
	-DWITH_PYTHON_BINDINGS=$(WITH_PYTHON) \
	-DFLATBUFFERS_USE_FETCHCONTENT=OFF \
	-DPYBIND11_USE_FETCHCONTENT=OFF \
	-DHalide_REQUIRE_LLVM_VERSION=$(HALIDE_LLVM_CMAKE_VERSION) \
	-DLLVM_DIR=/usr/lib/llvm-$(HALIDE_LLVM_VERSION)/lib/cmake/llvm \
	-DHalide_SOVERSION_OVERRIDE=$(HALIDE_SOVERSION) \
	-DHalide_SHARED_LLVM=ON \
	-DTARGET_WEBASSEMBLY=OFF \
	-DWITH_TESTS=$(WITH_TESTS) \
	-DWITH_TEST_FUZZ=OFF \
	-DWITH_TEST_PYTHON=$(WITH_TESTS) \
	-DWITH_DOCS=ON \
	-DCMAKE_INSTALL_LIBDIR=lib/$(DEB_HOST_MULTIARCH)/ \
	-DHalide_INSTALL_PLUGINDIR=lib/$(DEB_HOST_MULTIARCH)/halide$(HALIDE_VERSION)/ \
	-DCMAKE_INSTALL_INCLUDEDIR=include/halide$(HALIDE_VERSION)/ \
	-DHalide_INSTALL_CMAKEDIR=lib/$(DEB_HOST_MULTIARCH)/cmake/Halide$(HALIDE_VERSION)/ \
	-DHalide_INSTALL_HELPERSDIR=lib/$(DEB_HOST_MULTIARCH)/cmake/HalideHelpers$(HALIDE_VERSION)/ \
	-DCMAKE_INSTALL_BINDIR=lib/$(DEB_HOST_MULTIARCH)/halide$(HALIDE_VERSION)/ \
	-DHalide_INSTALL_TOOLSDIR=src/halide$(HALIDE_VERSION)/ \
	-DHalide_INSTALL_PYTHONDIR=lib/python3/dist-packages/ \
	-DCMAKE_INSTALL_DOCDIR=share/doc/halide$(HALIDE_VERSION)/

	LLVM_PROFILE_FILE=$(LLVM_PROFILE_FILE) dh_auto_build --builddir=$(BUILD_DIR)

	# Remove files that won't be needed anymore.
	# This reduces the total amount of disk space used during build.
	# NOTE: we must spare the static libraries that were intentionally created by the build system!
	find $(BUILD_DIR) \( -name '*.o' -or -name '*.a' \) -not -name 'libHalidePyStubs$(HALIDE_VERSION).a' -delete

ifneq ($(WITH_TESTS),OFF)
	# WARNING: running multi-threaded halide tests in parallel is unsupported!
	# Non-multithreaded non-performance non-flaky tests.
	LLVM_PROFILE_FILE=$(LLVM_PROFILE_FILE) ctest $(CTEST_OPTIONS) -j$(shell nproc --all) --label-exclude "$(TEST_GROUPS_MULTITHREADED)|$(TEST_GROUPS_PERFORMANCE)|$(TEST_GROUPS_FLAKY)"                   --test-dir $(BUILD_DIR)
	# Multi-threaded tests (excluding performance and/or flaky tests).
	LLVM_PROFILE_FILE=$(LLVM_PROFILE_FILE) ctest $(CTEST_OPTIONS) -j1                    --label-regex   "$(TEST_GROUPS_MULTITHREADED)" --label-exclude "$(TEST_GROUPS_PERFORMANCE)|$(TEST_GROUPS_FLAKY)" --test-dir $(BUILD_DIR)
	# All flaky tests (including multi-threaded tests, but excluding performance tests).
	LLVM_PROFILE_FILE=$(LLVM_PROFILE_FILE) ctest $(CTEST_OPTIONS) -j1                    --label-regex   "$(TEST_GROUPS_FLAKY)" --label-exclude "$(TEST_GROUPS_PERFORMANCE)"                              --test-dir $(BUILD_DIR)
	# Performance "tests". These are basically unreliable, so they may fail.
	LLVM_PROFILE_FILE=$(LLVM_PROFILE_FILE) ctest $(CTEST_OPTIONS) -j1                    --label-regex   "$(TEST_GROUPS_PERFORMANCE)"                                                                     --test-dir $(BUILD_DIR) || /bin/true
endif

	dh_auto_install --builddir=$(BUILD_DIR) --destdir=$(INSTALL_DIR)

	# Remove the whole build directory. We no longer need it.
	rm -rf $(BUILD_DIR)

ifneq ($(WITH_TESTS),OFF)
	LLVM_PROFILE_FILE=$(LLVM_PROFILE_FILE) dh_auto_configure --sourcedir=$(SOURCE_DIR)/apps/ --builddir=$(APPS_BUILD_DIR) -- \
	-DCMAKE_C_COMPILER=$(CC) -DCMAKE_CXX_COMPILER=$(CXX) \
	-DCMAKE_C_FLAGS="$(CFLAGS)" -DCMAKE_CXX_FLAGS="$(CXXFLAGS)" \
	-DCMAKE_BUILD_TYPE=Release -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=$(WITH_LTO) \
	-DENABLE_APPS_HANNK=OFF \
	-DHalide_DIR=$(INSTALL_DIR)/usr/lib/$(DEB_HOST_MULTIARCH)/cmake/Halide$(HALIDE_VERSION)/ \
	-DHalideHelpers_DIR=$(INSTALL_DIR)/usr/lib/$(DEB_HOST_MULTIARCH)/cmake/HalideHelpers$(HALIDE_VERSION)/

	LLVM_PROFILE_FILE=$(LLVM_PROFILE_FILE) dh_auto_build --builddir=$(APPS_BUILD_DIR)

	# Remove files that won't be needed anymore.
	# This reduces the total amount of disk space used during build.
	find $(APPS_BUILD_DIR) \( -name '*.o' -or -name '*.a' \) -delete

	# WARNING: running multi-threaded halide tests in parallel is unsupported!
	LLVM_PROFILE_FILE=$(LLVM_PROFILE_FILE) ctest $(CTEST_OPTIONS) -j1 --test-dir $(APPS_BUILD_DIR)

	# Remove the whole build directory. We no longer need it.
	rm -rf $(APPS_BUILD_DIR)
endif

override_dh_auto_configure:
	# Nothing to do. Because of multi-stage build, everything happens in override_dh_auto_build.

override_dh_auto_build:
ifneq ($(WITH_PGO),OFF)
	BUILD_STAGE=0 STAGE_COMPILE_FLAGS="-fprofile-generate -Xclang -mllvm -Xclang -vp-counters-per-site=10.0" $(MAKE) -f debian/rules perform_stage_build
	rm -rf $(BUILD_DIR_PREFIX)
	llvm-profdata-$(COMPILER_LLVM_VERSION) merge -output=$(PROFILE) $(PROFILE_TMP_DIR)
	rm -rf $(PROFILE_TMP_DIR)

	BUILD_STAGE=1 STAGE_COMPILE_FLAGS="-fprofile-use=$(PROFILE) -fcs-profile-generate -Xclang -mllvm -Xclang -vp-counters-per-site=100.0" $(MAKE) -f debian/rules perform_stage_build
	rm -rf $(BUILD_DIR_PREFIX)
	mv $(PROFILE) $(PROFILE).old
	llvm-profdata-$(COMPILER_LLVM_VERSION) merge -output=$(PROFILE) $(PROFILE_TMP_DIR) $(PROFILE).old
	rm -rf $(PROFILE_TMP_DIR)
	rm -rf $(PROFILE).old

	STAGE_COMPILE_FLAGS="-fprofile-use=$(PROFILE)" $(MAKE) -f debian/rules perform_stage_build
else
	$(MAKE) -f debian/rules perform_stage_build
endif

override_dh_auto_test:
	# Nothing to do. Because of multi-stage build, everything happens in override_dh_auto_build.

override_dh_auto_install:
	# Nothing to do. Because of multi-stage build, everything happens in override_dh_auto_build.

override_dh_install:
	dh_install --sourcedir=$(INSTALL_DIR)

override_dh_clean:
	dh_clean
	rm -rf $(BUILDSPACE)
