#! /usr/bin/make -f

DEB_BUILD_MAINT_OPTIONS = hardening=+all

# Boost libraries for which we want separate packages
# context is conditionally compiled because it is not supported yet on several architectures
# coroutine, and fiber depend on context, so they are also conditionally compiled
boost_libs := atomic chrono container contract date-time exception filesystem	\
              graph graph-parallel iostreams locale log math mpi	\
              mpi-python program-options python random regex	\
              serialization signals stacktrace system test thread timer \
              type-erasure wave

# these are special cases, where /usr/lib name differs from Boost library name
boost_lib_log := log log_setup
boost_lib_math := math_c99 math_c99f math_tr1 math_tr1f
boost_lib_math_long_double := math_c99l math_tr1l
boost_lib_serialization := serialization wserialization
boost_lib_stacktrace := stacktrace_noop stacktrace_addr2line stacktrace_backtrace stacktrace_basic
boost_lib_test := prg_exec_monitor test_exec_monitor unit_test_framework

py2versions = $(shell pyversions -rv)
py3versions = $(shell py3versions -rv)
py2verids = $(subst .,,$(py2versions))
py3verids = $(subst .,,$(py3versions))
pyversions = $(py2versions) $(py3versions)
pyverids = $(py2verids) $(py3verids)

# These are special cases for suffixes.  Generally come from --python-buildid, so begin with a dash.
boost_suffixes_python := $(pyverids)
boost_suffixes_numpy := $(pyverids)
boost_suffixes_mpi-python := $(pyverids)

py2default = $(subst .,,$(shell pyversions -dv))
py3default = $(subst .,,$(shell py3versions -dv))

# Files that are generated by filtering a template
filtered_files =

DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/buildflags.mk
include /usr/share/dpkg/architecture.mk

# set the number of build jobs
ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
  JOBS := -j$(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
endif

version_full := $(shell dpkg-parsechangelog | grep Version | cut -d' ' -f2)
version_upstream := $(shell echo $(version_full) | cut -d'-' -f1)
version_major := $(shell echo $(version_upstream) | cut -d'.' -f1,2)

PKGVERSION = $(version_major)
SOVERSION = $(version_upstream)

icuabi = $(shell apt show libicu-dev 2>/dev/null | sed -n 's/Depends: .*libicu\([0-9]*\) .*/\1/p')
regexicuabi = libboost-regex$(SOVERSION)-icu$(icuabi)

# Function to map Boost component name to set of shared library names
# Input: Boost component name
# Return: shared library names for the given Boost library
boost_lib = $(if $(boost_lib_$(1)), $(boost_lib_$(1)), $(1))

# Function to map Boost component name to set of suffixes for the library
# Input: Boost component name
# Return: suffixes for the given Boost component
boost_suffixes = $(if $(boost_suffixes_$(1)), $(boost_suffixes_$(1)),"")

# Helpers to make basic and decorated library names
# Input: library, suffix
# Return: base library filename for short or full name
mk_base_name = usr/lib/$(DEB_HOST_MULTIARCH)/libboost_$(subst -,_,$(1))$(2)

# Input: component
# Return: package name for shared library or development
mk_pkg_lib = libboost-$(1)$(SOVERSION)
mk_pkg_dev = libboost-$(1)$(PKGVERSION)-dev

# Helpers to generate debhelper input filenames.
# Input: component
# Return: prefix to debhelper filenames
mk_deb_lib = debian/$(call mk_pkg_lib,$(1))
mk_deb_dev = debian/$(call mk_pkg_dev,$(1))

# Helpers that update debhelper .install or .links files
# Input: component, library, suffix
# Output: none
mk_so_files = $(shell echo debian/tmp/$(call mk_base_name,$(2),$(3)).so.$(SOVERSION) >> $(call mk_deb_lib,$(1)).install)
mk_a_files = $(shell echo debian/tmp/$(call mk_base_name,$(2),$(3)).a >> $(call mk_deb_dev,$(1)).install)
mk_ln_files = $(shell echo $(call mk_base_name,$(2),$(3)).so.$(SOVERSION) $(call mk_base_name,$(2),$(3)).so >> $(call mk_deb_dev,$(1)).links)

# Specify the type of files/links to install.
# Special cases first, then general rule
boost_filetypes_exception = a
boost_filetypes_test_exec_monitor = a
boost_filetypes = $(if $(boost_filetypes_$(1)), $(boost_filetypes_$(1)),a so ln)

# Function that updates debhelper files for a given library
# Input: component, library, suffix
# Output: none
mk_files = $(foreach fn,$(call boost_filetypes,$(2)),$(call mk_$(fn)_files,$(1),$(2),$(3)))

# helpers to make and install lintian override files

# Input: package, override
add_override = echo $(1): $(2) >> debian/$(1).lintian-overrides;

# Input: override
add_dev_override = $(call add_override,libboost$(PKGVERSION)-dev,$(1))
add_doc_override = $(call add_override,libboost$(PKGVERSION)-doc,$(1))

# Input: component, lintian-warning
add_lib_override = $(call add_override,$(call mk_pkg_lib,$(1)),$(2))
add_libdev_override = $(call add_override,$(call mk_pkg_dev,$(1)),$(2))

# Input: package-name-base, versioned-package-name
cp_debhelper = set -e ; for s in doc-base examples postinst prerm README.Debian; do \
	if test -f debian/$(1).$$s; then cp -f debian/$(1).$$s debian/$(2).$$s; fi; done

# Function that updates debhelper files for all libraries shipped.
mk_debhelper_files = \
	$(call add_dev_override,extra-license-file) \
	$(call add_doc_override,extra-license-file) \
	$(foreach l, $(boost_libs), \
		echo "making debhelper files for $(l)..."; \
		$(call add_lib_override,$(l),package-name-doesnt-match-sonames) \
		$(foreach ll, $(call boost_lib,$(l)), \
			$(foreach suf, $(call boost_suffixes,$(l)), \
				$(call mk_files,$(l),$(ll),$(suf)) \
			) \
		) \
	)

TOOLSET_CONFIG = 'using gcc : : : <compileflags>"$(CPPFLAGS)" <cflags>"$(CFLAGS)" <cxxflags>"$(CXXFLAGS) -Wno-unused-local-typedefs" <linkflags>"$(LDFLAGS)" ;'
BUILD_CONTEXT = yes
BUILD_LONG_DOUBLE = yes

DEB_BUILD_ARCH ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH)

ifeq ($(DEB_BUILD_ARCH), alpha)
BUILD_CONTEXT = no
else ifeq ($(DEB_BUILD_ARCH), arm)
BUILD_LONG_DOUBLE = no
else ifeq ($(DEB_BUILD_ARCH), armel)
BUILD_LONG_DOUBLE = no
else ifeq ($(DEB_BUILD_ARCH), armhf)
BUILD_LONG_DOUBLE = no
else ifeq ($(DEB_BUILD_ARCH), arm64)
BUILD_LONG_DOUBLE = no
JAM_OPT += pch=off
else ifeq ($(DEB_BUILD_ARCH), hppa)
BUILD_LONG_DOUBLE = no
BUILD_CONTEXT = no
else ifeq ($(DEB_BUILD_ARCH), ia64)
BUILD_CONTEXT = no
else ifeq ($(DEB_BUILD_ARCH), m68k)
BUILD_CONTEXT = no
else ifeq ($(DEB_BUILD_ARCH), mips)
BUILD_LONG_DOUBLE = no
else ifeq ($(DEB_BUILD_ARCH), mipsel)
BUILD_LONG_DOUBLE = no
else ifeq ($(DEB_BUILD_ARCH), mips64)
BUILD_CONTEXT = no
else ifeq ($(DEB_BUILD_ARCH), mips64el)
BUILD_CONTEXT = no
else ifeq ($(DEB_BUILD_ARCH), powerpcspe)
BUILD_CONTEXT = no
else ifeq ($(DEB_BUILD_ARCH), ppc64)
BUILD_CONTEXT = yes
else ifeq ($(DEB_BUILD_ARCH), ppc64el)
BUILD_CONTEXT = yes
else ifeq ($(DEB_BUILD_ARCH), s390)
BUILD_CONTEXT = no
else ifeq ($(DEB_BUILD_ARCH), s390x)
BUILD_CONTEXT = no
else ifeq ($(DEB_BUILD_ARCH), sh4)
BUILD_LONG_DOUBLE = no
BUILD_CONTEXT = no
else ifeq ($(DEB_BUILD_ARCH), sparc)
BUILD_CONTEXT = no
else ifeq ($(DEB_BUILD_ARCH), sparc64)
BUILD_CONTEXT = no
else ifeq ($(DEB_BUILD_ARCH), x32)
BUILD_CONTEXT = no
endif

ifneq ($(DEB_HOST_ARCH), i386)
boost_libs += numpy
endif

ifeq ($(BUILD_CONTEXT), yes)
boost_libs += context coroutine fiber
else
JAM_WITHOUT += --without-context --without-coroutine --without-fiber
endif

ifeq ($(BUILD_LONG_DOUBLE), yes)
boost_lib_math += $(boost_lib_math_long_double)
else
JAM_OPT += --disable-long-double
endif

exampledir = debian/libboost$(PKGVERSION)-doc/usr/share/doc/libboost$(PKGVERSION)-doc/examples
bjam = $(CURDIR)/bjam
bbv2dir = $(CURDIR)/tools/build

# With --ignore-site-config, can probably drop Build-Conflicts on boost-build.
JAM = $(bjam) $(JOBS) -q -d2 $(JAM_OPT) --layout=system --ignore-site-config --user-config=$(CURDIR)/user-config.jam debug-symbols=on
JAM_DOC = $(bjam) $(JOBS) -q -d2 --ignore-site-config --user-config=$(CURDIR)/user-config-doc.jam

%:
	dh $@ --with python2 --with python3

override_dh_auto_configure: user-config.jam make-debhelper
ifeq ($(DEB_BUILD_ARCH), x32)
	cp tools/build/src/tools/gcc.jam tools/build/src/tools/gcc.jam.bak
	sed -i -e 's|^.*compile-link-flags.*-m32.*|#\0|g' tools/build/src/tools/gcc.jam
endif

override_dh_auto_build-common: $(bjam) b2.1 bjam.1
	$(JAM) $(JAM_WITHOUT) --without-python
	set -e ; for pyver in $(pyversions); do \
		echo "Building Boost.Python for python version $$pyver"; \
		$(JAM) --build-dir=build-$$pyver --stagedir=stage-$$pyver --user-config=$(CURDIR)/user-config-$$pyver.jam --with-python --with-mpi python=$$pyver; \
	done

	cd $(bbv2dir) && ./bootstrap.sh --with-toolset=gcc
	cd tools/bcp && $(JAM)
	cd tools/inspect/build && $(JAM)
	cd tools/quickbook && $(JAM)

	touch $@

override_dh_auto_build-arch: override_dh_auto_build-common

# Unfortunately documentation is built from headers generated by bjam
# during compilation, so we need to run compilation before generating
# documentation
override_dh_auto_build-indep: $(bjam) override_dh_auto_build-common
ifneq (,$(filter nodoc,$(DEB_BUILD_OPTIONS)))
	mkdir -p doc
else
	$(JAM_DOC) --build-dir=build-doc doc
endif

testsuite:
	cd status && $(JAM) $(JAM_WITHOUT)

override_dh_auto_clean: clean-debhelper
	-cd tools && $(JAM) clean
	-$(JAM) clean
ifeq ($(DEB_BUILD_ARCH), x32)
	-mv tools/build/src/tools/gcc.jam.bak tools/build/src/tools/gcc.jam
endif
	rm -rf tools/jam/src/bootstrap
	rm -rf tools/jam/src/bin.*
	rm -ff tools/jam/src/bjam
	rm -rf tools/regression/build/bin
	rm -rf bin.v2 dist
	rm -rf user-config.jam
	rm -rf build-* user-config-*.jam stage-*
	rm -rf b2.1 bjam.1
	rm -rf override_dh_auto_build-common override_dh_install-common
	dh_auto_clean

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

override_dh_install-common:
	# Install Boost.Build v2 & jam
	cd $(bbv2dir) && ./bjam install --prefix=$(CURDIR)/debian/tmp/usr --libdir=$(CURDIR)/debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH)
	mv debian/tmp/usr/share/boost-build/example debian/boost-build-examples

	touch $@

override_dh_install-arch: override_dh_install-common
	$(JAM) --prefix=$(CURDIR)/debian/tmp/usr $(JAM_WITHOUT) \
		--libdir=$(CURDIR)/debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH) \
		--without-python install
	set -e ; for pyver in $(pyversions); do \
		$(JAM) --build-dir=build-$$pyver --stagedir=stage-$$pyver --user-config=$(CURDIR)/user-config-$$pyver.jam --prefix=$(CURDIR)/debian/tmp/usr \
			--libdir=$(CURDIR)/debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH) \
			install --with-python --with-mpi python=$$pyver; \
	done

	find debian/tmp/usr/include debian/tmp/usr/share/boost-build -type f | xargs chmod 644
	find debian/tmp -name .cvsignore | xargs rm -f
	find debian -empty -type f | xargs rm -f

	# Write substvars for Python packages
	echo 'boost:Provides=' $(foreach verid,$(pyverids),libboost-python$(SOVERSION)-py$(verid),) >> debian/libboost-python$(SOVERSION).substvars
	echo 'boost:Provides=' $(foreach verid,$(pyverids),libboost-mpi-python$(SOVERSION)-py$(verid),) >> debian/libboost-mpi-python$(SOVERSION).substvars
	echo 'boost:Provides=' $(foreach verid,$(pyverids),libboost-numpy$(SOVERSION)-py$(verid),) >> debian/libboost-numpy$(SOVERSION).substvars
	# Write substvars for Regex (icu abi)
	echo 'boost:Provides=$(regexicuabi)' >> debian/libboost-regex$(SOVERSION).substvars

	# package libboost$(PKGVERSION)-dev
	dh_install -plibboost$(PKGVERSION)-dev \
	   debian/tmp/usr/include/boost \
	   usr/include
	dh_install -plibboost$(PKGVERSION)-tools-dev \
	   debian/tmp/usr/bin/bjam \
	   dist/bin/bcp \
	   dist/bin/inspect \
	   dist/bin/quickbook \
	   usr/bin
	dh_link -plibboost$(PKGVERSION)-tools-dev usr/bin/bjam usr/bin/b2
	dh_installman -plibboost$(PKGVERSION)-tools-dev b2.1 bjam.1 debian/bcp.1 debian/inspect.1 debian/quickbook.1
	dh_install -plibboost$(PKGVERSION)-tools-dev tools/boostbook/xsl/* usr/share/boostbook/xsl
	dh_install -plibboost$(PKGVERSION)-tools-dev tools/boostbook/dtd/* usr/share/boostbook/dtd
	dh_install -plibboost$(PKGVERSION)-tools-dev debian/tmp/usr/share/boost-build

	# package libboost-date-time$(PKGVERSION)-dev
	dh_installdocs -plibboost-date-time$(PKGVERSION)-dev libs/date_time/data

# Debian decorates the python-using libraries with a python version suffix ("-py27")
# Create symlinks for the upstream name to the default python version.
# There is a separate set of links for each Python major version.

	# Python2 compatibility links
	dh_link -plibboost-numpy$(PKGVERSION)-dev \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_numpy$(py2default).a \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_numpy.a
	dh_link -plibboost-numpy$(PKGVERSION)-dev \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_numpy$(py2default).so \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_numpy.so

	dh_link -plibboost-python$(PKGVERSION)-dev \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_python$(py2default).a \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_python.a
	dh_link -plibboost-python$(PKGVERSION)-dev \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_python$(py2default).so \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_python.so

	dh_link -plibboost-mpi-python$(PKGVERSION)-dev \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_mpi_python$(py2default).a \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_mpi_python.a
	dh_link -plibboost-mpi-python$(PKGVERSION)-dev \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_mpi_python$(py2default).so \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_mpi_python.so

	# Python3 compatibility links
	dh_link -plibboost-numpy$(PKGVERSION)-dev \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_numpy$(py3default).a \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_numpy3.a
	dh_link -plibboost-numpy$(PKGVERSION)-dev \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_numpy$(py3default).so \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_numpy3.so

	dh_link -plibboost-python$(PKGVERSION)-dev \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_python$(py3default).a \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_python3.a
	dh_link -plibboost-python$(PKGVERSION)-dev \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_python$(py3default).so \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_python3.so

	dh_link -plibboost-mpi-python$(PKGVERSION)-dev \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_mpi_python$(py3default).a \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_mpi_python3.a
	dh_link -plibboost-mpi-python$(PKGVERSION)-dev \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_mpi_python$(py3default).so \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_mpi_python3.so

	# Python3 old debian compat links
	dh_link -plibboost-python$(PKGVERSION)-dev \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_python$(py3default).a \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_python3-py$(py3default).a
	dh_link -plibboost-python$(PKGVERSION)-dev \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_python$(py3default).so \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_python3-py$(py3default).so

	dh_link -plibboost-mpi-python$(PKGVERSION)-dev \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_mpi_python$(py3default).a \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_mpi_python3-py$(py3default).a
	dh_link -plibboost-mpi-python$(PKGVERSION)-dev \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_mpi_python$(py3default).so \
	   usr/lib/$(DEB_HOST_MULTIARCH)/libboost_mpi_python3-py$(py3default).so

	# package libboost-mpi-python$(SOVERSION)
	dh_install -plibboost-mpi-python$(SOVERSION)

	# python2 install
	dh_installdirs -plibboost-mpi-python$(SOVERSION) usr/lib/python2.7/dist-packages/boost
	dh_install -plibboost-mpi-python$(SOVERSION) libs/mpi/build/__init__.py usr/lib/python2.7/dist-packages/boost/
	cp stage-2.7/lib/mpi.so debian/libboost-mpi-python$(SOVERSION)/usr/lib/python2.7/dist-packages/boost/ || true

	# python3 install
	dh_installdirs -plibboost-mpi-python$(SOVERSION) usr/lib/python3/dist-packages/boost
	dh_install -plibboost-mpi-python$(SOVERSION) libs/mpi/build/__init__.py usr/lib/python3/dist-packages/boost/
	cp stage-3*/lib/mpi.*.so debian/libboost-mpi-python$(SOVERSION)/usr/lib/python3/dist-packages/boost/ || true

	find debian -iname '*.so.*' -type f -print0 | xargs -0 chrpath --delete
	dh_install --list-missing

override_dh_install-indep: override_dh_install-common
	# package libboost-doc
	mkdir -p debian/libboost$(PKGVERSION)-doc/usr/share/doc/libboost$(PKGVERSION)-doc
	cp -a doc debian/libboost$(PKGVERSION)-doc/usr/share/doc/libboost$(PKGVERSION)-doc
	# provide a constant symlink to the latest documents and examples
	dh_link -plibboost$(PKGVERSION)-doc \
	   usr/share/doc/libboost$(PKGVERSION)-doc/doc \
	   usr/share/doc/libboost-doc/doc
	dh_link -plibboost$(PKGVERSION)-doc \
	   usr/share/doc/libboost$(PKGVERSION)-doc/examples \
	   usr/share/doc/libboost-doc/examples

	dh_installexamples -plibboost$(PKGVERSION)-doc debian/boost-build-examples
	mkdir -p $(exampledir)
	cat debian/example-files | xargs cp -a --parents --target-directory=$(exampledir)
	find $(exampledir) -type f | xargs chmod 644

override_dh_strip:
	dh_strip --dbgsym-migration='libboost1.55-dbg, libboost1.58-dbg, libboost1.61-dbg'

override_dh_makeshlibs:
	dh_makeshlibs -plibboost-regex$(SOVERSION) -V '$(regexicuabi)'
	dh_makeshlibs --remaining-packages
	sed -i -r 's/^(libboost_python([0-9]{2}) \S+ (\S+).*)$$/\1, \3-py\2/' debian/libboost-python$(SOVERSION)/DEBIAN/shlibs
	sed -i -r 's/^(libboost_mpi_python([0-9]{2}) \S+ (\S+).*)$$/\1, \3-py\2/' debian/libboost-mpi-python$(SOVERSION)/DEBIAN/shlibs
ifneq ($(DEB_HOST_ARCH), i386)
	sed -i -r 's/^(libboost_numpy([0-9]{2}) \S+ (\S+).*)$$/\1, \3-py\2/' debian/libboost-numpy$(SOVERSION)/DEBIAN/shlibs
endif

$(bjam):
	./bootstrap.sh --with-icu=/usr --prefix=$(CURDIR)/debian/tmp/usr \
		--libdir=$(CURDIR)/debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH) \
	  || cat bootstrap.log

b2.1 bjam.1: $(bjam)
	help2man --name 'software build tool' --no-info ./bjam > $@

user-config.jam:
	echo $(TOOLSET_CONFIG) > $@
	echo "using mpi ;"     >> $@
	set -e ; for pyver in $(pyversions); do \
		cp $@ user-config-$$pyver.jam; \
		echo "using python : $$pyver : /usr ;" >> user-config-$$pyver.jam; \
	done
	echo "using boostbook ;" > user-config-doc.jam
	echo "using quickbook ;" >> user-config-doc.jam
	echo "using doxygen ;" >> user-config-doc.jam

$(filtered_files): % : %.in
	sed -e 's/@PKGVERSION@/$(PKGVERSION)/g' < $< > $@

clean-debhelper:
	rm -rf debian/*.install
	rm -rf debian/*.links
	rm -rf debian/*.lintian-overrides

# Make all the generated debhelper files.
make-debhelper: clean-debhelper $(filtered_files)
	@$(call mk_debhelper_files)
	@$(call cp_debhelper,libboost-dev,libboost$(PKGVERSION)-dev)
	@$(call cp_debhelper,libboost-doc,libboost$(PKGVERSION)-doc)
	@$(call cp_debhelper,libboost-python-dev,libboost-python$(PKGVERSION)-dev)
	@$(call cp_debhelper,libboost-mpi-python-dev,libboost-mpi-python$(PKGVERSION)-dev)
