#! /usr/bin/make -f

DEB_BUILD_MAINT_OPTIONS = hardening=+all
# b2 compiled the libraries as variant=release, which implies -DNDEBUG, while
# the CMake build type is None.  Keep the generated code the same.
DEB_CPPFLAGS_MAINT_APPEND = -DNDEBUG
DEB_CXXFLAGS_MAINT_APPEND = -Wno-unused-local-typedefs

DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/default.mk

# Boost is configured and built several times over (shared, static, and one of
# each per extra Python interpreter); with debhelper's default VERBOSE=1 that
# prints every compiler invocation and floods the Salsa CI log.  "terse" makes
# dh_auto_configure/dh_auto_build quiet instead.
export DEB_BUILD_OPTIONS += terse

SOVERSION := $(firstword $(subst ~, ,$(subst +, ,$(DEB_VERSION_UPSTREAM))))
PKGVERSION := $(basename $(SOVERSION))
libdir := usr/lib/$(DEB_HOST_MULTIARCH)
tmplib := debian/tmp/$(libdir)

pyversions := $(shell py3versions -rv)
pydefault := $(shell py3versions -dv)
# Boost.Python is built once per interpreter; the default one comes out of the
# main build, the rest get a CMake pass of their own.
pyextra := $(filter-out $(pydefault),$(pyversions))
pyids := $(subst .,,$(pyversions))

# Boost components with a package of their own: a libboost-<c>$(SOVERSION)
# runtime package and a libboost-<c>$(PKGVERSION)-dev development package.
components := atomic charconv chrono cobalt container context contract	\
              coroutine date-time exception fiber filesystem graph	\
              graph-parallel iostreams json locale log math mpi		\
              mpi-python nowide process program-options python random	\
              regex serialization stacktrace test thread timer		\
              type-erasure url wave
ifneq ($(DEB_BUILD_ARCH), x32)
components += numpy
endif

# Components shipping libraries that are not simply named after the component.
# stacktrace_dump is a private helper library the other stacktrace backends
# link against, and their CMake configuration files require it.
libs_cobalt := cobalt cobalt_io
libs_log := log log_setup
libs_math := math_c99 math_c99f math_tr1 math_tr1f
libs_mpi-python := $(addprefix mpi_python,$(pyids))
libs_numpy := $(addprefix numpy,$(pyids))
libs_python := $(addprefix python,$(pyids))
libs_serialization := serialization wserialization
# The libbacktrace backend does not work on m68k, see #962072.
libs_stacktrace := stacktrace_dump stacktrace_noop stacktrace_addr2line \
                   $(if $(filter m68k,$(DEB_BUILD_ARCH)),,stacktrace_backtrace) stacktrace_basic
libs_test := prg_exec_monitor test_exec_monitor unit_test_framework

# Architectures where long double is not usable get no Boost.Math long double
# variants, and a few need the portable Boost.Context implementation.
ifeq (,$(filter $(DEB_HOST_ARCH), alpha arm armel armhf arm64 ppc64el hppa mips mipsel sh4 powerpc ppc64))
libs_math += math_c99l math_tr1l
else
CMAKE_ARCH_FLAGS += -DBOOST_MATH_HAS_LONG_DOUBLE=OFF
endif

ifneq (,$(filter $(DEB_HOST_ARCH), alpha hppa m68k ppc64 sh4 x32))
CMAKE_ARCH_FLAGS += -DBOOST_CONTEXT_IMPLEMENTATION=ucontext
endif

# Libraries that come as a static archive only.
static_only := exception test_exec_monitor

# Components built once per interpreter.  They install an unversioned CMake
# package as an alias for the one of the default interpreter.
py_components := python numpy mpi-python

# Components whose shared library names never match the name of the package
# shipping them, so lintian's package-name-doesnt-match-sonames has to be
# overridden.  For every other component the package name matches at least one
# of its sonames and the override would be unused.
soname_mismatch := math mpi-python numpy python stacktrace test

# Components whose shared libraries genuinely have no dependencies of their own
# apart from the C library, which lintian mistakes for a missing linker flag.
no_prerequisites := date-time stacktrace

# Input: component.  Return: the libboost_* base names it ships, the package
# names of its runtime and development package.
libs = $(or $(libs_$(1)),$(subst -,_,$(1)))
lib_pkg = libboost-$(1)$(SOVERSION)
dev_pkg = libboost-$(1)$(PKGVERSION)-dev

# Shell commands listing the files of one library in the .install files of the
# packages shipping them.  Input: component, library base name.
install_lib = \
	echo $(tmplib)/libboost_$(2).a >> debian/$(call dev_pkg,$(1)).install; \
	echo $(tmplib)/cmake/boost_$(2)-$(SOVERSION)-static >> debian/$(call dev_pkg,$(1)).install; \
	$(if $(filter $(2),$(static_only)),, \
		echo $(tmplib)/libboost_$(2).so.$(SOVERSION) >> debian/$(call lib_pkg,$(1)).install; \
		echo $(tmplib)/libboost_$(2).so >> debian/$(call dev_pkg,$(1)).install; \
		echo $(tmplib)/cmake/boost_$(2)-$(SOVERSION)-shared >> debian/$(call dev_pkg,$(1)).install;)

exampledir = debian/libboost$(PKGVERSION)-doc/usr/share/doc/libboost$(PKGVERSION)-doc/examples

# libboost_stacktrace_from_exception has never been shipped, see #1102107.
CMAKE_FLAGS = \
	-DBOOST_INSTALL_LAYOUT=system \
	-DBUILD_TESTING=OFF \
	-DBOOST_ENABLE_MPI=ON \
	-DBOOST_ENABLE_PYTHON=ON \
	-DBOOST_MATH_BUILD_WITH_LEGACY_FUNCTIONS=ON \
	-DBOOST_STACKTRACE_ENABLE_FROM_EXCEPTION=OFF \
	$(CMAKE_ARCH_FLAGS)

# The extra interpreters only need Boost.Python, Boost.NumPy and the Python
# bindings of Boost.MPI; everything else comes out of the main build.
CMAKE_PYTHON_FLAGS = -DBOOST_INCLUDE_LIBRARIES="python;mpi"

# Input: build directory suffix, extra CMake arguments
cmake_configure = dh_auto_configure --builddirectory=obj-$(1) -- $(CMAKE_FLAGS) $(2)

%:
	dh $@ --with python3 --buildsystem=cmake

# Boost is built twice, once shared and once static, because a single CMake
# tree only ever produces one of the two variants.
override_dh_auto_configure-arch:
	$(call cmake_configure,shared,-DBUILD_SHARED_LIBS=ON -DPython_EXECUTABLE=/usr/bin/python$(pydefault))
	$(call cmake_configure,static,-DBUILD_SHARED_LIBS=OFF -DPython_EXECUTABLE=/usr/bin/python$(pydefault))
	set -e ; for v in $(pyextra); do \
		$(call cmake_configure,py$$v-shared,-DBUILD_SHARED_LIBS=ON $(CMAKE_PYTHON_FLAGS) -DPython_EXECUTABLE=/usr/bin/python$$v); \
		$(call cmake_configure,py$$v-static,-DBUILD_SHARED_LIBS=OFF $(CMAKE_PYTHON_FLAGS) -DPython_EXECUTABLE=/usr/bin/python$$v); \
	done

override_dh_auto_build-arch: debhelper-files
	dh_auto_build --builddirectory=obj-shared
	dh_auto_build --builddirectory=obj-static
	set -e ; for v in $(pyextra); do \
		dh_auto_build --builddirectory=obj-py$$v-shared; \
		dh_auto_build --builddirectory=obj-py$$v-static; \
	done

override_dh_auto_install-arch:
	# The main build goes last so that the unversioned Boost::python,
	# Boost::numpy and Boost::mpi_python CMake packages end up pointing at
	# the default interpreter.
	set -e ; for v in $(pyextra); do \
		dh_auto_install --builddirectory=obj-py$$v-static; \
		dh_auto_install --builddirectory=obj-py$$v-shared; \
	done
	dh_auto_install --builddirectory=obj-static
	dh_auto_install --builddirectory=obj-shared
	# Windows debugger visualisers and libraries Debian does not ship.
	rm -rf debian/tmp/usr/share/boost-$(SOVERSION)
	rm -f debian/tmp/$(libdir)/libboost_fiber_numa.*
	rm -rf debian/tmp/$(libdir)/cmake/boost_fiber_numa-*
	# b2 installed only the headers, CMake copies the whole include tree
	find debian/tmp/usr/include -type f \
		! -name '*.hpp' ! -name '*.ipp' ! -name '*.h' ! -name '*.inc' -delete
	# placeholders such as boost/headers/.gitkeep
	find debian/tmp -type f -empty -delete
	find debian/tmp -type d -empty -delete
	# b2 has no CMake build of its own, and bcp and quickbook are linked
	# against the static libraries, as they were with b2.
	cd tools/build && bison -y -d -o src/engine/jamgram.cpp src/engine/jamgram.y
	./bootstrap.sh || { cat bootstrap.log; exit 1; }
	SOURCE_DATE_EPOCH=$$(dpkg-parsechangelog -STimestamp) \
		help2man --name 'software build tool' --no-info ./b2 > b2.1
	set -e ; for t in bcp quickbook; do \
		dh_auto_configure --sourcedirectory=tools/$$t --builddirectory=obj-$$t -- \
			-DCMAKE_PREFIX_PATH=$(CURDIR)/debian/tmp/usr -DBoost_USE_STATIC_LIBS=ON; \
		dh_auto_build --builddirectory=obj-$$t; \
	done

# Nothing is compiled for the architecture independent packages: the
# documentation and the examples are shipped as they come in the tarball.
# The test suite is not run at build time either.
override_dh_auto_configure-indep override_dh_auto_install-indep override_dh_auto_test:

# The -doc package has generated debhelper input files as well, so they have to
# be written even when only the architecture independent packages are built.
override_dh_auto_build-indep: debhelper-files

override_dh_auto_clean: clean-debhelper-files
	rm -rf obj-*
	rm -f tools/build/src/engine/jamgram.cpp tools/build/src/engine/jamgram.hpp
	rm -f tools/build/src/engine/b2 tools/build/src/engine/bjam
	rm -f b2 bjam b2.1 bootstrap.log project-config.jam project-config.jam.[0-9]*

override_dh_compress-indep:
	dh_compress -Xlibboost$(PKGVERSION)-doc/doc

override_dh_install-arch:
	# The CMake packages of the header only libraries have no shared or
	# static variant and belong to libboost-dev, except for the Python ones,
	# which are aliases claimed by their own -dev packages.
	find $(tmplib)/cmake -mindepth 1 -maxdepth 1 \
		-name 'boost_*-$(SOVERSION)' \
		$(foreach c,$(py_components),! -name 'boost_$(subst -,_,$(c))-$(SOVERSION)') \
		-printf '$(libdir)/cmake/%P\n' \
		>> debian/libboost$(PKGVERSION)-dev.install

	# Boost.Python and friends provide one virtual package per interpreter.
	$(foreach c,$(filter $(components),$(py_components)), \
		echo 'boost:Provides=$(foreach v,$(pyids),$(call lib_pkg,$(c))-py$(v),)' \
			>> debian/$(call lib_pkg,$(c)).substvars;)

	find debian/tmp -iname '*.so.*' -type f -print0 | xargs -0 -r chrpath --delete
	dh_install

# The examples keep the directory layout they have in the source tree, which
# dh_installexamples cannot do, so they are copied by hand.  dh_fixperms leaves
# usr/share/doc/*/examples alone, hence the chmod.
override_dh_install-indep:
	mkdir -p $(exampledir)
	xargs -a debian/example-files cp -a --parents --target-directory=$(exampledir)
	find $(exampledir) -type f -exec chmod 644 {} +

override_dh_makeshlibs:
	dh_makeshlibs
	# The libraries built per interpreter also satisfy the -py<version>
	# virtual packages, so their shlibs have to mention those as well.
	$(foreach c,$(filter $(components),$(py_components)), \
		sed -i -r 's/^(libboost_$(subst -,_,$(c))([0-9]+) \S+ (\S+).*)$$/\1, \3-py\2/' \
			debian/$(call lib_pkg,$(c))/DEBIAN/shlibs;)

override_dh_gencontrol:
	dh_gencontrol -- -V'gxx:major=$(shell dpkg-query -f '$${version}' -W g++ | sed 's/.*://;s/\..*//')'

# The debhelper input files below depend on the Boost version and on the set of
# Python interpreters, so they are generated rather than kept in the package.
# Everything generated carries the Boost version in its name; the templates it
# is copied from are the same names without the version.
dh_suffixes := install lintian-overrides docs links manpages examples README.Debian
dh_templates := libboost-dev.examples libboost-doc.README.Debian \
                libboost-tools-dev.install libboost-tools-dev.links \
                libboost-tools-dev.manpages
clean-debhelper-files:
	rm -f $(addprefix debian/*$(PKGVERSION)*., $(dh_suffixes))

debhelper-files: clean-debhelper-files
	@echo 'libboost$(PKGVERSION)-dev: extra-license-file' > debian/libboost$(PKGVERSION)-dev.lintian-overrides
	@$(foreach c,$(filter $(components),$(no_prerequisites)), \
		echo '$(call lib_pkg,$(c)): shared-library-lacks-prerequisites' >> debian/$(call lib_pkg,$(c)).lintian-overrides;)
	@$(foreach c,$(filter $(components),$(soname_mismatch)), \
		echo '$(call lib_pkg,$(c)): package-name-doesnt-match-sonames' >> debian/$(call lib_pkg,$(c)).lintian-overrides;)
	@$(foreach c,$(filter $(components),$(py_components)), \
		echo $(tmplib)/cmake/boost_$(subst -,_,$(c))-$(SOVERSION) >> debian/$(call dev_pkg,$(c)).install;)
	@$(foreach c,$(components),$(foreach l,$(call libs,$(c)),$(call install_lib,$(c),$(l))))
	@echo debian/tmp/usr/include/boost >> debian/libboost$(PKGVERSION)-dev.install
	@echo $(tmplib)/cmake/Boost-$(SOVERSION) >> debian/libboost$(PKGVERSION)-dev.install
	@echo libs/date_time/data >> debian/$(call dev_pkg,date-time).docs
	@echo doc >> debian/libboost$(PKGVERSION)-doc.docs
	@# a constant symlink to the latest documents and examples
	@echo usr/share/doc/libboost$(PKGVERSION)-doc/doc usr/share/doc/libboost-doc/doc \
		>> debian/libboost$(PKGVERSION)-doc.links
	@echo usr/share/doc/libboost$(PKGVERSION)-doc/examples usr/share/doc/libboost-doc/examples \
		>> debian/libboost$(PKGVERSION)-doc.links
	@set -e ; for t in $(dh_templates); do \
		cp debian/$$t debian/libboost$(PKGVERSION)$${t#libboost}; \
	done

.PHONY: debhelper-files clean-debhelper-files
