#!/usr/bin/make -f
# Build script for GPRBuild in Debian.
# Copyright (c) 2009-2012 Stephen Leake <stephen_leake@stephe-leake.org>
# Copyright (c) 2013-2020 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.

######################################################################
# Read some variables from the Debian control file.
# To debug, replace eval with error.
$(foreach line,$(shell sed -n ' \
  s/^Package: \(libgnatprj\([0-9.]\+\)\)$$/ \
    gnatprj_LIB_PKG:=\1 \
    gnatprj_SONAME:=libgnatprj.so.\2 \
   /p;\
  s/^Package:\s*\(libgnatprj[0-9.]\+-dev\)$$/ \
    gnatprj_DEV_PKG:=\1 \
   /p;\
  s/^ gnat-\([0-9.]\+\),\?$$/ \
    GNAT_VERSION:=\1 \
   /p;\
  s/^ \(libxmlada-\([a-z]\+\)[0-9.]\+-dev\)\( (.*)\)\?,\?$$/ \
    xmlada_\2_DEV_PKG:=\1 \
   /p;\
  ' debian/control),$(eval $(line)))

DEB_BUILD_MAINT_OPTIONS := hardening=+all
DEB_ADAFLAGS_MAINT_APPEND := -gnatwa -Wall -gnatn
DEB_LDFLAGS_MAINT_APPEND := \
  -Wl,--no-undefined \
  -Wl,--no-copy-dt-needed-entries \
  -Wl,--no-allow-shlib-undefined
include /usr/share/dpkg/architecture.mk
include /usr/share/dpkg/buildflags.mk
include $(wildcard /usr/share/ada/debian_packaging-$(GNAT_VERSION).mk)
# wildcard in case only Build-Depends-Indep are installed.

# gprbuild.gpr selects inlining.
# 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>

######################################################################
%:
	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.

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

# For source directories (-aI) and ALI directories (-aO), blindly list
# all build dependencies and append each library once it is
# built. This does not hurt, and covers all direct and indirect
# dependencies.

# For installed shared libraries (-l) and locally built shared
# objects), the same strategy works thanks to --as-needed, which is
# the default since gcc-9, provided a proper ordering.

# Libraries provided by Ada -dev packages in Build-Depends.
ada_build_deps := xmlada_schema xmlada_dom xmlada_sax xmlada_input xmlada_unicode

ada_build_deps_includes := $(foreach l,$(ada_build_deps),-aI/$(ADS_DIR)/$(l) -aO/$(ALI_DIR)/$(l))
ada_build_deps_ldlibs := $(addprefix -l,$(ada_build_deps) gnarl-$(GNAT_VERSION) gnat-$(GNAT_VERSION))

# These lists grow at the end of the template.
includes_so_far :=
shared_objects_so_far :=

define library_template
# Parameters:
# _SRCDIR: directory containing the sources files
# _SONAME : shared object name (libNAME.so.VERSION)
# _DEV_PKG, _LIB_PKG: as in policy
# For installed projects and ada:Depends, we need an explicit list of
# the dependencies that the library *directly* reference.
# _deps_int_direct: among the local libraries built so far
# _deps_ext_direct: among ada_build_deps (each one must have a _DEV_PKG)

  # Remove pure specifications and separate compilation units.
  $(library)_unit_bodies := $(shell grep -L '^separate ' $($(library)_SRCDIR)/*.adb)

  $(library)_c_sources := $(wildcard $($(library)_SRCDIR)/*.c)

  # Build dynamic library.
  override_dh_auto_build-arch: obj/shared/$($(library)_SONAME)
  obj/shared/$($(library)_SONAME): \
        $$(patsubst $($(library)_SRCDIR)/%.c,obj/shared_$(library)_obj/%.o,$$($(library)_c_sources)) \
        $(shared_objects_so_far) \
        | obj/shared 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) $(includes_so_far) $(ada_build_deps_includes) \
	  -cargs $(ADAFLAGS) -fPIC
	gcc-$(GNAT_VERSION) $(LDFLAGS) -shared \
	  -o $$@ \
	  -Wl,-soname,$($(library)_SONAME) \
	  obj/shared_$(library)_obj/*.o \
	  $(shared_objects_so_far) $(ada_build_deps_ldlibs)
  # 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/*
  # Work-around until BUILD_PATH_PREFIX_MAP is accepted in GCC.
	sed -i '/^A -f[a-z]+-prefix-map=/d' obj/shared_$(library)_ali/*

  # Build static library.
  override_dh_auto_build-arch: obj/static/lib$(library).a
  # There is no link step, but listing shared objects built so far as
  # prerequisites forces Make to first build their .ali, so that this
  # gnatmake run does not compile them.
  obj/static/lib$(library).a: \
         $$(patsubst $($(library)_SRCDIR)/%.c,obj/static_$(library)_obj/%.o,$$($(library)_c_sources)) \
         $(shared_objects_so_far) \
        | obj/static obj/static_$(library)_ali obj/static_$(library)_obj
	gnatmake -c $$($(library)_unit_bodies) -D obj/static_$(library)_obj \
	  $(BUILDER_OPTIONS) $(includes_so_far) $(ada_build_deps_includes) \
	  -cargs $(ADAFLAGS)
	ar rc $$@ obj/static_$(library)_obj/*.o
	ranlib $$@

  obj/shared_$(library)_obj/%.o: $($(library)_SRCDIR)/%.c | obj/shared_$(library)_obj
	gcc-$(GNAT_VERSION) -c $(CFLAGS) $(CPPFLAGS) $$< -o $$@ -fPIC
  obj/static_$(library)_obj/%.o: $($(library)_SRCDIR)/%.c | obj/static_$(library)_obj
	gcc-$(GNAT_VERSION) -c $(CFLAGS) $(CPPFLAGS) $$< -o $$@

  obj/shared_$(library)_ali obj/shared_$(library)_obj obj/static_$(library)_ali obj/static_$(library)_obj: | obj
	mkdir $$@

  execute_after_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] $$($(library)_c_sources) \
	  $(ADS_DIR)/$(library)
  # Substitution variables for the control file.
	echo 'ada:Depends=gnat, gnat-$(GNAT_VERSION), \
	  $(foreach l, $($(library)_deps_int_direct), $($(l)_DEV_PKG) (=$$$${binary:Version}),) \
	  $(foreach l, $($(library)_deps_ext_direct), $($(l)_DEV_PKG),) \
	  $($(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 l, $($(library)_deps_int_direct) \
	                    $($(library)_deps_ext_direct) \
	         ,with "$(l).gpr";\n)/; \
	    s/\n /\n/g; }; \
	  $(foreach v,library SO_DIR ADS_DIR ALI_DIR,s|@$(v)@|$($(v))|;) \
	  ' $$< > $$@
  execute_after_dh_install::
	dh_install --package=$($(library)_DEV_PKG) \
	  obj/$(library).gpr \
	  $(GPR_DIR)

  includes_so_far += -aI$($(library)_SRCDIR) -aOobj/shared_$(library)_ali
  shared_objects_so_far := obj/shared/$($(library)_SONAME) $(shared_objects_so_far)
endef

gnatprj_SRCDIR := gpr/src
gnatprj_deps_ext_direct := xmlada_schema xmlada_dom xmlada_sax xmlada_input

# To debug an instantiation, replace eval with error:
$(foreach library, \
  gnatprj \
  ,$(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

$(EXECUTABLES): $(shared_objects_so_far) | obj
	gnatmake $@$(MAIN_EXT).adb -aIsrc -D obj -o obj/$@ \
	  $(BUILDER_OPTIONS) $(includes_so_far) $(ada_build_deps_includes) \
	  -cargs $(ADAFLAGS) \
	  -largs $(LDFLAGS) $(shared_objects_so_far) $(ada_build_deps_ldlibs)

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

override_dh_auto_build-indep:
  ifeq (,$(filter nodoc,$(DEB_BUILD_OPTIONS)))
    # Replace sphinx.sty copy with with packaged one.
	ln -fs /usr/share/sphinx/texinputs/sphinx.sty doc/share/sphinx.sty
	$(MAKE) -Cdoc html pdf txt
  endif
override_dh_auto_clean::
	$(MAKE) -Cdoc clean
	rm -f doc/share/sphinx.sty

# Compatibility project with upstream name GPR.
execute_after_dh_install::
	dh_install --package=$(gnatprj_DEV_PKG) debian/gpr.gpr $(GPR_DIR)
