#!/usr/bin/make -f
# -*- makefile -*-
# Build mingw-w64.

empty:=
space:=$(empty) $(empty)
xsedx:=$(shell printf '\027')

# Silence huge amount of warnings in "arch:all" build
mute_warn := expansion-to-defined
cpp_nowarn := $(foreach w,$(mute_warn),-Wno-$(w))
export DEB_CPPFLAGS_MAINT_APPEND = $(cpp_nowarn)

# Hardening is for host binaries only (no support in targets for now)
export DEB_BUILD_MAINT_OPTIONS := hardening=+all optimize=+lto
TARGET_DEB_BUILD_OPTIONS := hardening=-all optimize=-lto

ifeq (,$(filter terse,$(DEB_BUILD_OPTIONS)))
export DH_VERBOSE := 1
endif

include /usr/share/dpkg/default.mk

build  := $(CURDIR)/build
stamp  := $(build)/stamp
tmpdst := $(build)/tmp

# Target architectures
target32 := i686-w64-mingw32
target64 := x86_64-w64-mingw32
targets := $(target32) $(target64)

# Host architecture
host = $(DEB_HOST_GNU_TYPE)

# Host-based tools
tools_host := gendef genidl genlib genpeimg
# Targetted tools
tools_target := widl

# Targetted projects
# Nota bene: crt is built before libraries
lib_target := winpthreads
lib_target32 :=

ifeq ($(filter stage1,$(DEB_BUILD_PROFILES)),)
lib_target += winstorecompat
lib_target32 += pseh
endif

%:
	dh $@

.NOTPARALLEL:

override_dh_update_autotools_config:

override_dh_autoreconf:

# General rules
# Format: host~target~source~folder
# E.g. i486-linux-gnu~i686-w64-mingw32~tools~widl to build a 32-bit
# Linux-hosted widl targeting 32-bit Windows
rule_words = $(subst ~,$(space),$(1))
rule_host = $(word 1,$(call rule_words,$(1)))
rule_target = $(word 2,$(call rule_words,$(1)))
rule_path = $(subst $(space),/,$(wordlist 3,$(words $(call rule_words,$(1))),$(call rule_words,$(1))))
source_folder = $(CURDIR)/mingw-w64-$(call rule_path,$(1))
build_folder = $(build)/$(call rule_host,$(1))_$(call rule_target,$(1))_$(subst /,-,$(call rule_path,$(1)))
build_flags = $(call build_folder,$(1)).flags
build_ldspec = $(call build_folder,$(1)).ldspecs

######################################################################
# Tools

# gendef requires libmangle
$(stamp)/$(host)~$(host)~tools~gendef~configure: \
  $(stamp)/%~tools~gendef~configure: \
  $(stamp)/%~libraries~libmangle~install \
  $(stamp)/%~tools~gendef~preconf
#
	cd '$(call build_folder,$(*)~tools~gendef)' ; \
	. '$(call build_flags,$(*)~tools~gendef)' ; \
	'$(call source_folder,$(*)~tools~gendef)/configure' \
	  --host=$(call rule_host,$(*)~tools~gendef) \
	  --target=$(call rule_target,$(*)~tools~gendef) \
	  --prefix=/usr \
	  --with-mangle='$(tmpdst)/usr'
	touch '$(stamp)/$(*)~tools~gendef~configure'

# genlib requires libmangle and is installed as mingw-genlib
# to avoid a conflict with alliance
$(stamp)/$(host)~$(host)~tools~genlib~configure: \
  $(stamp)/%~tools~genlib~configure: \
  $(stamp)/%~libraries~libmangle~install \
  $(stamp)/%~tools~genlib~preconf
#
	cd '$(call build_folder,$(*)~tools~genlib)' ; \
	. '$(call build_flags,$(*)~tools~genlib)' ; \
	'$(call source_folder,$(*)~tools~genlib)/configure' \
	  --host=$(call rule_host,$(*)~tools~genlib) \
	  --target=$(call rule_target,$(*)~tools~genlib) \
	  --program-prefix=mingw- \
	  --prefix=/usr \
	  --with-mangle'=$(tmpdst)/usr'
	touch '$(stamp)/$(*)~tools~genlib~configure'

######################################################################
# Libraries

# Override the header configuration
$(stamp)/%~headers~configure: \
  $(stamp)/%~headers~preconf
#
	cd '$(call build_folder,$(*)~headers)' ; \
	. '$(call build_flags,$(*)~headers)' ; \
	'$(call source_folder,$(*)~headers)/configure' \
	  --host=$(call rule_host,$(*)~headers) \
	  --target=$(call rule_target,$(*)~headers) \
	  --prefix=/usr/$(call rule_target,$(*)~headers)
	touch '$(stamp)/$(*)~headers~configure'

# Override CRT configuration to avoid multilib builds
$(foreach t,$(targets),$(stamp)/$(t)~$(t)~crt~configure): \
  $(stamp)/%~crt~configure: \
  $(stamp)/%~headers~install \
  $(stamp)/%~crt~preconf
#
	cd '$(call build_folder,$(*)~crt)' ; \
	. '$(call build_flags,$(*)~crt)' ; \
	'$(call source_folder,$(*)~crt)/configure' \
	  --host=$(call rule_host,$(*)~crt) \
	  --target=$(call rule_target,$(*)~crt) \
	  --prefix=/usr/$(call rule_target,$(*)~crt) \
	  --$(if $(filter $(call rule_target,$(*)~crt),$(target64)),enable,disable)-lib64 \
	  --$(if $(filter $(call rule_target,$(*)~crt),$(target32)),enable,disable)-lib32
	touch '$(stamp)/$(*)~crt~configure'

# Special target to call autoreconf only and only when required
$(stamp)/%~autoreconf:
	cd '$(call source_folder,$(*))' ; \
	[ -x configure ] || autoreconf -fiv
	touch '$(stamp)/$(*)~autoreconf'

$(stamp)/%~ldspecs: $(stamp)/%~autoreconf
	if [ '$(host)' != '$(call rule_host,$(*))' ] ; then \
		sed 's$(xsedx)@@PATH@@$(xsedx)$(tmpdst)/usr/$(call rule_host,$(*))/lib$(xsedx)g' \
		  < debian/specs.in \
		  > '$(call build_ldspec,$(*))' ; \
	fi
	touch '$(stamp)/$(*)~ldspecs'

$(stamp)/%~builddir: $(stamp)/%~ldspecs
	mkdir -p '$(call build_folder,$(*))'
	touch '$(stamp)/$(*)~builddir'

# No hardening support for now, except in the tools (override_dh_auto_build-arch)
$(stamp)/%~flags: $(stamp)/%~builddir
	if [ '$(host)' != '$(call rule_host,$(*))' ] ; then \
		export DEB_BUILD_MAINT_OPTIONS='$(TARGET_DEB_BUILD_OPTIONS)' ; \
		export DEB_CPPFLAGS_MAINT_PREPEND='-I$(tmpdst)/usr/$(call rule_target,$(*))/include' ; \
		export DEB_LDFLAGS_MAINT_PREPEND='-L$(tmpdst)/usr/$(call rule_target,$(*))/lib' ; \
	fi ; \
	dpkg-buildflags --export=sh > '$(call build_flags,$(*))'
# Add -f*-prefix-map flag for build directory
	sed -i -E '/-f.+-prefix-map/{s$(xsedx)"$$$(xsedx) -ffile-prefix-map=$(call build_folder,$(*))=/build"$(xsedx)}' \
	  '$(call build_flags,$(*))'
# Add -f*-prefix-map flag for staging directory
	sed -i -E '/-f.+-prefix-map/{s$(xsedx)"$$$(xsedx) -ffile-prefix-map=$(tmpdst)/=/"$(xsedx)}' \
	  '$(call build_flags,$(*))'
# Adjust CFLAGS to pass --debug-prefix-map for `as'
# ref: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93371
	. '$(call build_flags,$(*))' ; \
	for o in $${CFLAGS} ; do \
	case "$$o" in \
	-f*-prefix-map=*) \
		map=$${o#*=} ; \
		sed -i -E '/^export CFLAGS=/{s$(xsedx)"$$$(xsedx) -Wa,--debug-prefix-map,'"$${map}"'"$(xsedx)}' \
		  '$(call build_flags,$(*))' ; \
	;; \
	esac ; \
	done
# Adjust flags for target:
# - correct -specs in LDFLAGS
# - provide RCFLAGS (fixes "stage1" build)
	if [ '$(host)' != '$(call rule_host,$(*))' ] ; then \
		sed -i -E '/^export LDFLAGS=/{s$(xsedx)-specs=[^"[:space:]]+$(xsedx)$(xsedx)}' \
		  '$(call build_flags,$(*))' ; \
		sed -i -E '/^export LDFLAGS=/{s$(xsedx)"$$$(xsedx) -specs=$(call build_ldspec,$(*))"$(xsedx)}' \
		  '$(call build_flags,$(*))' ; \
		RCFLAGS="-I$(tmpdst)/usr/$(call rule_target,$(*))/include$${RCFLAGS:+ }$${RCFLAGS}" ; \
		printf 'export RCFLAGS="%s"\n' "$${RCFLAGS}" >> '$(call build_flags,$(*))' ; \
	fi
	touch '$(stamp)/$(*)~flags'

$(stamp)/%~preconf: $(stamp)/%~flags
	touch '$(stamp)/$(*)~preconf'

# If we're targetting the build host, configure for hardening
# If we're targetting the target host, disable hardening (see above),
# change the prefix and use the new headers and libraries
$(stamp)/%~configure: $(stamp)/%~preconf
	cd '$(call build_folder,$(*))' ; \
	. '$(call build_flags,$(*))' ; \
	if [ '$(host)' = '$(call rule_host,$(*))' ] ; then \
		'$(call source_folder,$(*))/configure' \
		  --host=$(call rule_host,$(*)) \
		  --target=$(call rule_target,$(*)) \
		  --prefix=/usr \
		; \
	else \
		'$(call source_folder,$(*))/configure' \
		  --host=$(call rule_host,$(*)) \
		  --target=$(call rule_target,$(*)) \
		  --prefix=/usr/$(call rule_target,$(*)) \
		  --with-widl-includedir=/usr/$(call rule_target,$(*))/include \
		; \
	fi
	touch '$(stamp)/$(*)~configure'

$(stamp)/%~postconf: $(stamp)/%~configure
	touch '$(stamp)/$(*)~postconf'

$(stamp)/%~build: $(stamp)/%~postconf
	. '$(call build_flags,$(*))' ; \
	dh_auto_build --sourcedir='$(call source_folder,$(*))' --builddir='$(call build_folder,$(*))'
	touch '$(stamp)/$(*)~build'

$(stamp)/%~install: $(stamp)/%~build
	dh_auto_install --sourcedir='$(call source_folder,$(*))' --builddir='$(call build_folder,$(*))' --destdir='$(tmpdst)'
	touch '$(stamp)/$(*)~install'

execute_before_dh_auto_configure:
# perform source cleanup from tarball to repository state (close enough)
	for n in aclocal.m4 'build-aux/*' config.h.in configure Makefile.in ; do \
		find -wholename "*/$$n" -type f -delete ; \
	done
# remove extra libtool/m4 files
	for n in libtool ltoptions ltsugar ltversion 'lt~obsolete' ; do \
		find -wholename "*/$$n.m4" -type f -delete ; \
	done
	mkdir -p '$(build)' '$(stamp)' '$(tmpdst)'

override_dh_auto_configure-arch: $(foreach x,$(tools_host),$(stamp)/$(host)~$(host)~tools~$(x)~install)

override_dh_auto_configure-indep: $(foreach t,$(targets),$(stamp)/$(t)~$(t)~crt~install)

override_dh_auto_build-arch: $(foreach x,$(tools_target),$(foreach t,$(targets),$(stamp)/$(host)~$(t)~tools~$(x)~install))

override_dh_auto_build-indep: $(foreach x,$(lib_target),$(foreach t,$(targets),$(stamp)/$(t)~$(t)~libraries~$(x)~install))
override_dh_auto_build-indep: $(foreach x,$(lib_target32),$(stamp)/$(target32)~$(target32)~libraries~$(x)~install)

# Nothing to test here yet
override_dh_auto_test:

override_dh_auto_install-indep:
# Move DLLs to lib, drop .la files
	d='$(tmpdst)/usr' ; \
	for T in $(targets) ; do \
	    find "$$d/$$T/lib/" -name '*.la' -delete ; \
	    find "$$d/$$T/bin/" -name '*.dll' -exec mv -nt "$$d/$$T/lib" '{}' '+' ; \
	done
# Move duplicate files to mingw-w64-common
	s='$(tmpdst)/usr' ; \
	d='usr/share/mingw-w64' ; \
	refT='$(word 1,$(targets))' ; \
	testT='$(wordlist 2,$(words $(targets)),$(targets))' ; \
	for file in $$(cd "$$s/$$refT" ; find . -type f ! -name '*.a' -printf '%P\n') ; do \
		dupT="$$refT" ; \
		for target in $$testT ; do \
			[ -f "$$s/$$target/$$file" ] || continue ; \
			if cmp -s "$$s/$$refT/$$file" "$$s/$$target/$$file" ; then \
				dupT="$$dupT $$target" ; \
			fi ; \
		done ; \
		if [ "$$dupT" = "$$refT" ] ; then continue ; fi ; \
		mkdir -p "debian/mingw-w64-common/$$d/$$(dirname $$file)" ; \
		cp "$$s/$$refT/$$file" "debian/mingw-w64-common/$$d/$$file" ; \
		for duptarget in $$dupT ; do \
			rm -f "$$s/$$duptarget/$$file" ; \
			ln -sf "/$$d/$$file" "$$s/$$duptarget/$$file" ; \
		done ; \
	done

override_dh_auto_install-arch:
# Remove mingw-w64 libmangle artifacts (if any)
	rm -f \
	  '$(tmpdst)/usr/include/libmangle.h' \
	  '$(tmpdst)/usr/lib/libmangle.a'

execute_after_dh_auto_install:
# Move files to appropriate location for debhelper
	mkdir -p debian/tmp
	mv -t debian/tmp '$(tmpdst)/'*
