#!/usr/bin/make -f

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

SHELL    := bash -e

# This influences dpkg-buildflags to specify better linker
# options.  See https://wiki.debian.org/Hardening
# Apparently some of these might incur silent breakage
#   https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=939560#5
# but we don't think this is relevant to us.
#
# Note that we don't use the dpkg-buildflags output for the
# hypervisor build.  This because I haven't investigated which
# of them are sane to use in the hypervisor context, rather than
# simply in userland binaries.
#
# Inexplicably, if you tell make `export V=value' and `$(shell ...)'
# it does not pass V to the shell.  WTF.  So we set a variable
# dbmo which we include in the relevant $(shell ...) invocations.
dbmo= DEB_BUILD_MAINT_OPTIONS=hardening=+all

# Architecture handling.
#
# We need to explicitly specify the architecture because the Xen
# upstream build system likes to use `uname' which can produce wrong
# answers it other-bitness chroots, and because we need to build a
# 64-bit hypervisor even on i386 (since there is no 32-bit hypervisor
# anymore).

# Also there is terminological confusion.  The DEB_* variables follow
# GNU GCC terminology:
#
# dpkg / GNU    Xen         Meaning
#  BUILD         COMPILE     Host: where this build is running
#  HOST          TARGET      Target: where the binaries we build now will run

include /usr/share/dpkg/architecture.mk

# Xen has its own different architecture names, which are nither
# Debian nor GNU names.

flavour_amd64 = amd64
flavour_i386  = amd64
flavour_armhf = armhf
flavour_arm64 = arm64

xen_arch_amd64 = x86_64
xen_arch_i386  = x86_32
xen_arch_armhf = arm32
xen_arch_arm64 = arm64

flavour=$(flavour_$(DEB_HOST_ARCH))

# Much of the work here is to make different upstream versions of Xen
# coinstallable, and arrange to run which ever version of the tools
# corresponds to the running hypervisor.
#
# This packaging produces one version.  The nominal upstream version
# represents the control ABI used by hypervisor management utilities.
#
# In this package that version number appears in (i) debian/control
# and (ii) the first two numbers in the package version in
# debian/changelog.  These must both be updated when a new major
# upstream version is packaged (eg 4.10 -> 4.11).
# (Everywhere else, it is handled dynamically.)
#
upstream_version := \
 $(shell dpkg-parsechangelog -SVersion | sed 's/\(\.[0-9]*\)\..*/\1/' )

# Many of the debhelper files are most conveniently provided as
# templates which depend on the flavour and the upstream version.
# Since even some package names depend on the version, so do some
# dh input filenames.  We support this as follows:
#
# These runes take all files named   debian/*.vsn-in
# and do these three things:
#  1. in the file contents
#    (a) substitute @version@ @flavour@
#    (b) interpret lines like
#		? flavour = <value> [ | <other-value> ...]
#		? flavour != <value> [ | <other-value> ...]
#     as conditional output lasting until the next ? on is own.
#  2. replace any V in the file *name* with that same version
#     and any F with the flavour
#  3. strip .vsn-in from the end
# The resulting files are then consumed by dh.
#
# (debhelper has a shell script control file facility, but that cannot
# handle the need to vary the actual filename seen by debhelper.)

TEMPLATE_FILES := $(wildcard debian/*.vsn-in)

define template_rule_template =
 TEMPLATED_FILES += $(2)
 $(2): $(1) debian/rules debian/changelog debian/template-subst
	debian/template-subst $(upstream_version) $(flavour) <$$< >$$@.tmp \
	&& mv -f $$@{.tmp,}
endef

$(foreach t,$(TEMPLATE_FILES), $(eval 					\
	$(call 								\
		template_rule_template, $t, 				\
		$(subst F,$(flavour),					\
		 $(subst V,$(upstream_version),				\
		  $(basename $t)					\
		 ))							\
	)))

templated-files: $(TEMPLATED_FILES)
	:

# Work around bug in dpkg-buildpackage: between dpkg 1.14.17 and 1.16.1
# it exports these.  This is a problem because we need to pass different
# options to the hypervisor build - the default options from dpkg
# et al are suitable for dom0 binaries but not for the hypervisor.
undefine CFLAGS
undefine CXXFLAGS
undefine FFLAGS
undefine CPPFLAGS
undefine LDFLAGS

# The Xen build system likes to download things at build-time.  We
# think we have disabled all of that with appropriate configure
# options.  But, set these too, so we spot if we miss any.
export WGET=/bin/false GIT=/bin/false

# Other build flags etc.

t=$(CURDIR)/debian/tmp

dpkg_CFLAGS   := $(shell $(dbmo) dpkg-buildflags --get CFLAGS)
dpkg_CPPFLAGS := $(shell $(dbmo) dpkg-buildflags --get CPPFLAGS)
dpkg_LDFLAGS  := $(shell $(dbmo) dpkg-buildflags --get LDFLAGS)

make_args_common := \
	XEN_COMPILE_ARCH=$(xen_arch_$(DEB_BUILD_ARCH))

make_args_xen := $(make_args_common) \
	XEN_TARGET_ARCH=$(xen_arch_$(flavour))
# (Xen upstream does not offer a separate CPPFLAGS,
# so we pass those in CFLAGS.)

make_args_tools := $(make_args_common) \
	XEN_TARGET_ARCH=$(xen_arch_$(DEB_HOST_ARCH)) \
	EXTRA_CFLAGS_XEN_TOOLS='$(dpkg_CFLAGS) $(dpkg_CPPFLAGS)' \
	PREPEND_LDFLAGS_XEN_TOOLS='$(dpkg_LDFLAGS)'

export PYBUILD_NAME=xen
export PYBUILD_DISABLE=test
export PYBUILD_SYSTEM=distutils

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

# Without this, something on stretch passes CFLAGS in the environment
# to the Xen build system, which then (with 4.11) chokes printing
#   /bin/sh: 1: Syntax error: Unterminated quoted string
# probably because the CFLAGS value contains multiple options and
# therefore spaces.  See also the note by `undefine CFLAGS', above.
override_dh_auto_clean:
	rm -f debian/xen-tools-built.stamp
	$(MAKE) -j1 distclean

# To avoid that the build dirties the tree, our delta queue deletes
# config.sub and config.guess.  dh_update_autotools_config can get
# us fresh ones for each build, but it expects to find some there
# already with some weird properties.  Instead, just copy them
# from /usr/share/misc (which is where it gets them anyway)
override_dh_update_autotools_config:
	cp /usr/share/misc/{config.sub,config.guess} .

# Upstream has both a kconfig style configure for the hypervisor
# and autoconfery for the tools (what we call the `utils').
override_dh_auto_configure:
	cp debian/xen-kconfig xen/.config
	make -C xen olddefconfig $(make_args_xen)
	:
	$(make_args_tools) ./configure \
		--disable-stubdom \
		--prefix=/usr \
		--includedir=/usr/include \
		--libdir=/usr/lib/$(DEB_HOST_MULTIARCH) \
		--with-libexec-libdir-suffix=/$(DEB_HOST_MULTIARCH) \
		--host=$(DEB_HOST_MULTIARCH) \
		--mandir=/usr/share/man \
		--infodir=/usr/share/info \
		--sysconfdir=/etc \
		--localstatedir=/var \
		--with-libexec-leaf-dir=xen-$(upstream_version) \
		--disable-blktap1 \
		--disable-blktap2 \
		--disable-qemu-traditional --disable-rombios \
		--with-system-qemu=/usr/bin/qemu-system-i386 \
		--enable-ovmf --with-system-ovmf=/usr/share/ovmf/OVMF.fd \
		--with-system-seabios=/usr/share/seabios/bios-256k.bin

# tools/firmware/xen-dir is the `shim' used for booting PV guests
# in an HVM container, for security (particularly, for meltdown/spectre
# mitigation).  It's actually a hypervisor.  On i386 it is not built
# by `make tools' because run that with XEN_COMPILE_ARCH=x86_32 which
# is no longer a supported hypervisor architecture.  And we want to
# build it with $(make_args_xen) not $(make_args_tools).  So do it
# separately.
override_dh_auto_build:
	$(MAKE) $(make_args_xen) xen
	$(MAKE) $(make_args_tools) tools docs CONFIG_PV_SHIM=n
	case $(flavour) in \
	amd64|i386) \
		$(MAKE) $(make_args_xen) -C tools/firmware/xen-dir ;; \
	esac
	touch debian/xen-tools-built.stamp

# We keep the amount of fixup and messing about with debian/tmp/
# to a minimum, because when working it is easier to rerun the
# later parts of the build than the whole of the two upstream make installs.
# However, there are three sets of fixes we must make:
override_dh_auto_install: $(TEMPLATED_FILES)
	$(MAKE) $(make_args_xen) DESTDIR=$t install-xen
	$(MAKE) $(make_args_tools) DESTDIR=$t \
		install-{tools,docs} CONFIG_PV_SHIM=n
	:
	@# shim install target needs to be run separately because we
	@# need to pass it the make_args_xen settings, in particular
	@# on i386 bwe need to pass x86_64 here to actually build it.
	@# Luckily this target, unlike the build, is a noop on
	@# shimless arches, so it does not need to be conditional.
	$(MAKE) $(make_args_xen) DESTDIR=$t $(make_args_xen) \
		-C tools/firmware install-shim
	:
	@# Inexplicably, upstream puts the efi binares in usr/lib64
	case $(flavour) in \
		armhf) ;; \
		*) mv $t/usr/lib64/efi/* $t/boot/. ;; \
	esac
	:
	@# This file contains an arch-specific path and we put it
	@# in xen-utils-common, an arch-all package.  But the
	@# path is only used to put the libdir on LD_LIBRARY_PATH
	@# in the hotplug scripts.  We have a patch to drop that.
	sed -i '/^libdir=/d' $t/etc/xen/scripts/hotplugpath.sh

# libxenfsimage has an unstable ABI.  Our makefile patch puts it in a
# different directory and fixes up the rpath; this rules code excludes the
# header files.
dh_install_excludes += -Xinclude/xenfsimage

# The upstream build produces these.
dh_install_excludes += -X'*.pyc'

# The upstream docs build erroneously ships .deps into the html output.
dh_install_excludes += -X/.deps

# Upstream puts pygrub in its lib directory which is in our per-version
# package, and leaves a symlink in /usr/bin.  Exclude the symlink.
# We don't want this in /usr/bin anyway.
dh_install_excludes += -Xusr/bin/pygrub

# We want the xenstore utilities in their own package.  The general
# install does everything from /usr/bin and /usr/share/man, so we
# need to exclude them.  debhelpers's -X option is ... odd.  Not
# suitable, anyway.  So we rm them after running dh_install.
# The installation is done separately via xenstore-utils.install.
xenstore_rm = $(addprefix debian/xen-utils-common/,		\
		$(foreach utility, xenstore xenstore-*,		\
			usr/bin/$(utility)			\
			usr/share/man/man1/$(utility).1		\
		))

override_dh_install:
	debian/shuffle-binaries $(upstream_version) $(flavour)
	:
	debian/shuffle-boot-files $(upstream_version) $(flavour)
	:
	dh_install $(dh_install_excludes)
	if test -d debian/xen-utils-common; then rm -v $(xenstore_rm); fi
	:
	debian/installsharedlibs

# dh_python3 does not know to look in the funny directory where
# we put the versioned /usr/lib files including some python scripts.
override_dh_python3:
	dh_python3
	dh_python3 -pxen-utils-$(upstream_version) \
		usr/lib/xen-$(upstream_version)/bin

# We have two init scripts.  (There used to be xend too.)
override_dh_installinit:
	dh_installinit --name xen --no-start -- defaults
	dh_installinit --name xendomains --no-start -- defaults

# dh_strip in dh compat 10 and earlier (which we are at so this
# package builds on stretch) looks at filenames and modes to decide
# what to process.  hvmloader doesn't match, so we must trick it.
# It is sufficient to make it executable.  And we have to undo
# that again, then.  This all happens after dh_install so we operate
# on the package-specific file.
override_dh_strip:
	find debian/xen-utils-* -name hvmloader | xargs -r chmod -v +x
	dh_strip
	find debian/xen-utils-* -name hvmloader | xargs -r chmod -v -x

# Hardlink the various xenstore-* programs together.  This is an
# argv[0]-using binary of which we can have only one copy.  We need to
# do this late, because dh_strip breaks hardlinks.
#
# The debug files are fairly large, fairly rarely used,
# and not compressed by the upstream build system.
override_dh_compress:
	rdfind -makehardlinks true -makeresultsfile false \
		debian/xenstore-utils/usr/bin
	:
	dh_compress
	find debian/xen-hypervisor-*/usr/lib/debug -type f -print0 \
		| xargs -0r gzip -9vn

# By default, files in debian/tmp which are not handled by anything
# in rules are ignored.  This makes them into errors.
override_dh_missing:
	dh_missing --fail-missing


# We are dropping the config file /etc/default/xen which appeared in
# earlier versions.  See ./ucf-remove-fixup for more details.
override_dh_ucf:
	dh_ucf
