#!/usr/bin/make -f

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

SHELL    := bash -e

# support parallel build
ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
    NUMJOBS = $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
    MAKEFLAGS += -j$(NUMJOBS)
endif

# This gives us DEB_VERSION_UPSTREAM and DEB_VERSION (used by our delta queue)
include /usr/share/dpkg/pkg-info.mk
export DEB_VERSION

# DEB_MAINTAINER is used by our delta queue
export DEB_MAINTAINER := $(shell sed -ne 's/^Maintainer: \(.*\)$$/\1/p' debian/control)

# 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 in other-bitness chroots.

# 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_arm64 = arm64

xen_arch_amd64 = x86_64
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 echo $(DEB_VERSION_UPSTREAM) | 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.
# This is still needed post bookworm.
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 := \
	CC=$(DEB_HOST_GNU_TYPE)-gcc \
	LD=$(DEB_HOST_GNU_TYPE)-ld \
	XEN_COMPILE_ARCH=$(xen_arch_$(DEB_BUILD_ARCH)) \
	V=1

# Passing -ffile-prefix-map is needed for reproducible builds.
# Additionally passing -fdebug-prefix-map in necessary to work around a gcc bug
# where -ffile-prefix-map is ignored with assembly files. See
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93371
# This should be fixed with gcc-13, i.e. trixie onwards
make_args_xen := $(make_args_common) \
	XEN_TARGET_ARCH=$(xen_arch_$(flavour)) \
	EXTRA_CFLAGS_XEN_CORE='-ffile-prefix-map=$(shell pwd)=. -fdebug-prefix-map=$(shell pwd)=.'

# (Xen upstream does not offer a separate CPPFLAGS,
# so we pass those in CFLAGS.)
# The BUILD_PATH_PREFIX_MAP is needed for ocaml to reproducibly build
# oxenstored
# Debug is disabled in xen release branches, but explicitly disable it here so
# we can also package unstable branches without debugging enabled.
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)' \
	BUILD_PATH_PREFIX_MAP='.=$(shell pwd)' \
	debug=n

%:
	dh $@ --with=python3

# 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/libexec/xen-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. It's only built for amd64.
# Since we want to build it with $(make_args_xen) not $(make_args_tools),
# do it separately.
override_dh_auto_build:
	$(MAKE) $(make_args_xen) xen
	$(MAKE) $(make_args_tools) tools CONFIG_PV_SHIM=n
	# The docs fail on parallel build, so build linear
	$(MAKE) $(make_args_tools) docs CONFIG_PV_SHIM=n -j1
	case $(flavour) in \
	amd64) \
		$(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.
	@# 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 \
		-C tools/firmware install-shim
	:
	@# Inexplicably, upstream puts the efi binares in usr/lib64
	find "$t"/usr/lib*/efi -mindepth 1 -maxdepth 1 -print0 | xargs -r -0 mv -t "$t/boot"
	:
	@# 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.
#
# We ignore xenstore-control here, as this should be shipped in
# xen-utils-common. See the comment on override_dh_install. Note our !(control)
# syntax used here needs bash with the extglob option.
xenstore_rm = $(addprefix debian/xen-utils-common/,		\
		$(foreach utility, xenstore xenstore-!(control),\
			usr/bin/$(utility)			\
			usr/share/man/man1/$(utility).1		\
		))

# Starting with bookworm the xenstore-control binary is now linked against
# unstable xen api libraries (libxenguest.so and libxenctrl.so) which are
# included in the libxenmiscV package.
# Because of the additional shared library dependencies our shuffle-binaries
# script kicks in and sets up the xen-utils-wrapper for xenstore-control. So
# don't ship xenstore-control in xenstore-utils (which intentionally has no
# dependency on xen-utils-V), but move it to xen-utils-common to avoid a broken
# symlink when only the xenstore-utils package, but not the xen-utils-common
# package is installed. See #1036601 and also the comment for xenstore_rm.
override_dh_install:
	debian/shuffle-binaries $(upstream_version)
	:
	debian/shuffle-boot-files $(upstream_version) $(flavour)
	:
	dh_install -pxenstore-utils $(dh_install_excludes) \
		-Xusr/bin/xenstore-control \
		-Xusr/share/man/man1/xenstore-control.1
	dh_install --remaining-packages $(dh_install_excludes)
	bash -e -O extglob -c \
	        '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
	dh_python3 -pxen-utils-$(upstream_version) \
		usr/lib/xen-$(upstream_version)/lib/python

# 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

override_dh_installsystemd:
	dh_installsystemd --name xen --no-start --no-stop-on-upgrade
	dh_installsystemd --name xendomains --no-start --no-stop-on-upgrade

# We want to ship xen-shim-syms in a -dbg package, but if we just add a
# xen-utils-V-dbg package for it, lintian will complain with the following
# warning:
# W: xen changes: package-builds-dbg-and-dbgsym-variants xen-utils-V-dbg xen-utils-V-dbgsym
# So we disable the generation of an automatic dbgsym packages for xen-utils-V
# and ship the automatically generated files in our xen-utils-V-dbg package.
#
# Don't strip the .note section from xen-shim. See also
# debian/xen-utils-V.lintian-overrides.vsn-in
#
# Finally, don't strip anything in the -dbg packages
override_dh_strip:
	dh_strip --package=xen-utils-$(upstream_version) \
		--dbg-package=xen-utils-$(upstream_version)-dbg \
		--exclude=xen-shim
	dh_strip --remaining-packages \
		--no-package=xen-utils-$(upstream_version)-dbg \
		--no-package=xen-hypervisor-$(upstream_version)-$(flavour)-dbg

# 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.
override_dh_compress:
	rdfind -makehardlinks true -makeresultsfile false \
		debian/xenstore-utils/usr/bin
	:
	dh_compress -Xusr/share/doc/xen/html

# dh_dwz may fail with the output "dwz: Too few files for multifile
# optimization" which breaks the build. As the use of dh_dwz is limited anyhow
# (see #1016563), we disable it here.
override_dh_dwz:
