#!/usr/bin/make -f
# Build script for GPRBuild in Debian.
# Copyright (c) 2009-2012 Stephen Leake <stephen_leake@stephe-leake.org>
# Copyright (c) 2013-2016 Nicolas Boulenguez <nicolas@debian.org>

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.

# On Debian systems, the full text of the GPL is in the file
# /usr/share/common-licenses/GPL-3.


# NOTE:
# In order to prevent a circular build-dependency, the Debian packages
# for XML/Ada and GPRBuild bother to build without project support.
# Please keep the two debian/rules files similar enough to ease
# backport of good ideas.

# For example, splitting build-arch and build-indep targets or using a
# library template is not useful (to say the least) but it makes the
# comparison.

######################################################################
# *_DEV_PKG, *_LIB_PKG and *_SONAME are read from the control file.
# To debug, replace eval with error.
define new_line :=


endef
$(eval $(addsuffix $(new_line),$(shell sed -n ' \
  s/^Package:\s*\(lib\([a-z]\+\)\([0-9.]\+\)\)$$/ \
    \2_LIB_PKG:=\1 \
    \2_SONAME:=lib\2.so.\3 \
   /p;\
  s/^Package:\s*\(lib\([a-z]\+\)[0-9.]\+-dev\)$$/ \
    \2_DEV_PKG:=\1 \
   /p;\
  s/^ gnat, gnat-\([0-9.]\+\),\?$$/ \
    GNAT_VERSION:=\1 \
   /p;\
  ' debian/control)))

DEB_BUILD_MAINT_OPTIONS := hardening=+all
include /usr/share/dpkg/default.mk
include /usr/share/ada/debian_packaging-$(GNAT_VERSION).mk

DEB_DATE := $(shell dpkg-parsechangelog -S date)

# gprbuild.gpr selects inlining.
ADAFLAGS += -gnatn
# It also selects -E -static binder options, but:
# #666106 affects only kfreebsd-i386, where storing tracebacks in
# exception occurrences causes a segmentation fault.  This prevents
# handling of any exceptions.  gprconfig relies on handling exceptions
# when parsing compilers.xml.
# Author: Ludovic Brenta <lbrenta@debian.org>

######################################################################
POLICY_TARGETS := binary binary-arch binary-indep build build-arch \
  build-indep clean
.PHONY: $(POLICY_TARGETS)
$(POLICY_TARGETS):
	dh $@

# Rewrite upstream configure/make build system.
.PHONY: $(addprefix override_dh_auto_, \
  configure build-arch build-indep test install clean)

# Rewrite upstream targets without gprbuild or gprclean.
# gnatmake does not support projects anymore, we cannot use xmlada.gpr.

# If you intend to use autoconf...
# Set target from DEB_HOST_GNU_TYPE instead of config.sub, which adds
# a vendor and does not match "gcc -dumpmachine" at run time.
# The problem is hidden on usual architectures by hand-crafted
# renamings in share/gprconfig/targetset.xml.
# See share/gprconfig/compilers.xml, debian/patches/gprconfig.diff.

######################################################################
# Regenerate gpr-snames.ad[bs].
obj/shared/$(gpr_SONAME) obj/static/libgpr.a: gpr/src/gpr-snames.ads

obj/xsnames: gpr/xsnames.adb | obj
	gnatmake gpr/xsnames.adb -D obj -o $@ \
	  $(BUILDER_OPTIONS) \
	  -cargs $(ADAFLAGS) \
	  -largs $(LDFLAGS)

gpr/src/gpr-snames.ads: obj/xsnames \
                        gpr/snames.list \
                        gpr/snames_spec_init.txt \
                        gpr/snames_spec_init.txt
	cd gpr; ../$<
	mv gpr/gpr-snames.ad[bs] gpr/src
override_dh_auto_clean::
	rm -f gpr/src/gpr-snames.ad[bs]

######################################################################
ADS_DIR := usr/share/ada/adainclude
GPR_DIR := usr/share/ada/adainclude
ALI_DIR := usr/lib/$(DEB_HOST_MULTIARCH)/ada/adalib
SO_DIR  := usr/lib/$(DEB_HOST_MULTIARCH)
A_DIR   := usr/lib/$(DEB_HOST_MULTIARCH)

# All libraries built so far will be prepended to that list, for -aI
# -aO and -l options. The order matters for -l, and redundancy does
# not because we link with --as-needed.
LIBS :=

define library_template

  # *_LIBS is used to generate the list of imported projects and -dev
  # packages. It must be an (unsorted) subset  of the current value of LIBS.
  # Read the list from upstream project.
  $(library)_LIBS :=

  # Remove pure specifications and separate compilation units.
  $(library)_unit_bodies := $(foreach s, \
    $(wildcard $($(library)_SRCDIR)/*.adb) \
    ,$(if $(shell grep -l '^separate ' $(s)),,$(s)))

  # Build dynamic library.
  override_dh_auto_build-arch: obj/shared/$($(library)_SONAME)
  obj/shared/$($(library)_SONAME): | obj/shared
    # Ensure deterministic timestamps in patched or generated ALI files.
	find $($(library)_SRCDIR) -name "*.ad[bs]" -a -newermt '$(DEB_DATE)' -print0 | \
	  xargs -0r touch --no-dereference --date='$(DEB_DATE)'
	mkdir -p obj/shared_$(library)_ali obj/shared_$(library)_obj
    # -fPIC/-shared overrides -fPIE/-pie in ADAFLAGS/LDFLAGS.
	gnatmake -c $$($(library)_unit_bodies) -D obj/shared_$(library)_obj \
          $(BUILDER_OPTIONS) \
	  $(foreach l,$(LIBS),-aI$($(l)_SRCDIR) -aOobj/shared_$(l)_ali) \
          -cargs $(ADAFLAGS) -fPIC
	gcc-$(GNAT_VERSION) $(LDFLAGS) -shared \
	  -o $$@ \
	  -Wl,-soname,$($(library)_SONAME) \
	  obj/shared_$(library)_obj/*.o \
	  -Lobj/shared $(addprefix -l,$(LIBS)) -lgnat-$(GNAT_VERSION)
  # Create development link so that the other libraries may link with it.
	ln -fs $($(library)_SONAME) obj/shared/lib$(library).so
  # Move ALI files to library directory and mark them read-only.
	mv obj/shared_$(library)_obj/*.ali obj/shared_$(library)_ali
	chmod 444 obj/shared_$(library)_ali/*

  # Build static library.
  override_dh_auto_build-arch: obj/static/lib$(library).a
  obj/static/lib$(library).a: | obj/static
	mkdir -p obj/static_$(library)_ali obj/static_$(library)_obj
	gnatmake -c $$($(library)_unit_bodies) -D obj/static_$(library)_obj \
          $(BUILDER_OPTIONS) \
	  $(foreach l,$(LIBS),-aI$($(l)_SRCDIR) -aOobj/static_$(l)_ali) \
	  -cargs $(ADAFLAGS)
	ar rc $$@ obj/static_$(library)_obj/*.o
	ranlib $$@
  # Move ALI files to library directory and mark them read-only.
	mv obj/static_$(library)_obj/*.ali obj/static_$(library)_ali
	chmod 444 obj/static_$(library)_ali/*.ali

  # We can now extend the LIBS list for following iterations.
  LIBS := $(library) $(LIBS)

  override_dh_install::
  # dynamic library
	dh_install --package=$($(library)_LIB_PKG) \
	  obj/shared/$($(library)_SONAME) \
	  $(SO_DIR)
  # static library
	dh_install --package=$($(library)_DEV_PKG) \
	  obj/static/lib$(library).a \
	  $(A_DIR)
  # development symbolic link
	dh_link --package=$($(library)_DEV_PKG) \
	  $(SO_DIR)/$($(library)_SONAME) \
	  $(SO_DIR)/lib$(library).so
  # ALI files
	dh_install --package=$($(library)_DEV_PKG) \
	  obj/shared_$(library)_ali/*.ali \
	  $(ALI_DIR)/$(library)
  # Sources
	dh_install --package=$($(library)_DEV_PKG) \
	  $($(library)_SRCDIR)/*.ad[bs] \
	  $(ADS_DIR)/$(library)
  # Substitution variables for the control file.
	echo 'ada:Depends=gnat, gnat-$(GNAT_VERSION), \
          $$(foreach l,$$($(library)_LIBS),$$($$(l)_DEV_PKG) (= $$$${binary:Version}),)$($(library)_LIB_PKG)' \
	  >> debian/$($(library)_DEV_PKG).substvars

  # Externally built project installed for end users.
  override_dh_auto_build-arch: obj/$(library).gpr
  obj/$(library).gpr: debian/template.gpr | obj
	sed ' \
	  /@IMPORTS@/ { \
	    s//$$(foreach d,$$($(library)_LIBS),with "$$(d).gpr";\n)/; \
	    s/\n /\n/g; }; \
	  $(foreach v,library SO_DIR ADS_DIR ALI_DIR,s|@$(v)@|$($(v))|;) \
	  ' $$< > $$@
  override_dh_install::
	dh_install --package=$($(library)_DEV_PKG) \
	  obj/$(library).gpr \
	  $(GPR_DIR)

endef


gpr_SRCDIR := gpr/src

# To debug an instantiation, replace eval with error:
$(foreach library, \
  gpr \
  ,$(eval $(call library_template)))

######################################################################
EXECUTABLES := gprbind gprbuild gprclean gprconfig gprinstall gprlib gprls gprname gprslave

override_dh_auto_build-arch: $(EXECUTABLES)

# Gnatmake knows better than Make if something is up to date.
.PHONY: $(EXECUTABLES)

# Some main units are poorly named.
gprbind gprlib gprslave: MAIN_EXT :=
gprbuild gprclean gprconfig gprinstall gprls gprname: MAIN_EXT := -main

# Each executable may not require each library, but there should be no
# consequence with --as-needed linker flag.
normal_libs := xmlada_schema xmlada_dom xmlada_sax xmlada_input xmlada_unicode
$(EXECUTABLES): obj/gpr_imports.o obj/shared/$(gpr_SONAME) | obj
	gnatmake $@$(MAIN_EXT).adb -aIsrc -D obj -o obj/$@ \
          $(BUILDER_OPTIONS) \
	  $(foreach l,$(LIBS),-aI$($(l)_SRCDIR) -aOobj/shared_$(l)_ali) \
	  $(addprefix -aI/$(ADS_DIR)/,$(normal_libs)) \
	  $(addprefix -aO/$(ALI_DIR)/,$(normal_libs)) \
          -cargs $(ADAFLAGS) \
          -largs $(LDFLAGS) \
	  obj/gpr_imports.o \
	  -Lobj/shared $(addprefix -l,$(LIBS) $(normal_libs))

obj/gpr_imports.o: src/gpr_imports.c | obj
	gcc-$(GNAT_VERSION) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

obj obj/shared obj/static:
	mkdir -p $@
override_dh_auto_clean::
	rm -fr obj

# Remaining install tasks.
.PHONY: override_dh_install
override_dh_install::
	dh_install --remaining-packages
