#    GMPAda, binding to the Ada Language for the GNU MultiPrecision library.
#    Copyright (C) 2007-2022 Nicolas Boulenguez <nicolas.boulenguez@free.fr>
#
#    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.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

########################
# Global configuration #
########################

LIB_NAME := gmpada

################################
# Build and test configuration #
################################

# For build flags:
# * settings from the environment are appended and take precedence.
# * Settings from the command line fully replace the default.

# Option for the Ada compiler
ADAFLAGS := -g -O2 -gnataEfnoqQ -gnatVa -Wall -Wextra -gnatw.eH.Y \
  -gnatyBdIoOSuxy $(ADAFLAGS)

# Options for the C and C++ preprocessors
CPPFLAGS ?=

# Options for the C compiler
CFLAGS := -g -O2 -Wall -Wextra -pedantic $(CFLAGS)

# Options for the C++ compiler
CXXFLAGS := -Wall -Wextra $(CXXFLAGS)

# Options for the linker
LDFLAGS := -Wl,--as-needed -Wl,--no-allow-shlib-undefined \
  -Wl,--no-copy-dt-needed-entries -Wl,--no-undefined $(LDFLAGS)

# Options for gnatmake
GNATMAKE_OPTIONS ?=

# A -j option in GNATMAKEFLAGS will be more efficient and produce
# readable logs. Never allow make -j to interfer.
.NOTPARALLEL:

# We want the same compiler for C, C++ and Ada, so the default value
# from Make is not sufficient.  The following works on Debian but will
# probably require a command line override in other contexts.
GNATMAKE            := gnatmake
gnat_version := $(shell $(GNATMAKE) --version | sed 's/.* \([0-9]\+\).*/\1/;q')
CC                  := gcc-$(gnat_version)
CXX                 := g++-$(gnat_version)

# Objects for the linker (FOO.o, libFOO.a, libFOO.so or -lFOO)
# The order may matter with --as-needed.
LDLIBS := -lgmp $(LDLIBS)

##############################
# Installation configuration #
##############################

prefix              := /usr
datarootdir         := $(prefix)/share
libdir              := $(prefix)/lib

# The sources files are installed into a LIB_NAME subdirectory of
SRC_DIR             := $(datarootdir)/ada/adainclude

# A LIB_NAME.gpr project convenient for library usage is installed into
gnat_project        := $(LIB_NAME).gpr
GPR_DIR             := $(datarootdir)/gpr

# The content of this file ignores DESTDIR.
# The GNAT ALI files are installed into a LIB_NAME subdirectory of
ALI_DIR             := $(libdir)/ada/adalib

# The static archive is installed into
static_library      := lib$(LIB_NAME).a
A_DIR               := $(libdir)

# The shared library is installed into
SOVERSION           := 2
shared_object_name  := lib$(LIB_NAME).so.$(SOVERSION)
shared_library      := $(shared_object_name)
development_link    := lib$(LIB_NAME).so
SO_DIR              := $(libdir)

# DESTDIR allows staged installs. It is prefixed to actual
# installation paths but ignored otherwise.

#########
# Rules #
#########

ada_units := $(wildcard src/*.adb) \
 src/gmp.ads \
 src/gmp-h.ads \
 src/gnu_multiple_precision-text_io.ads \
 src/gnu_multiple_precision-wide_text_io.ads \
 src/gnu_multiple_precision-wide_wide_text_io.ads

# Default target is:
.PHONY: build
build: obj/$(shared_library) obj/$(static_library) obj/$(gnat_project)

# Phony so that GNATMAKE deals with Ada dependencies, not MAKE.
.PHONY: obj/$(shared_library)
obj/$(shared_library): src/gmp-h.ads obj-dynamic/gmp_macros.o | obj obj-dynamic
	$(GNATMAKE) -c $(ada_units) -D obj-dynamic $(GNATMAKE_OPTIONS) \
          -cargs $(ADAFLAGS) -fPIC
	$(CC) -shared -o $@ -Wl,-soname,$(shared_object_name) \
	  obj-dynamic/*.o $(LDFLAGS) -lgnat $(LDLIBS)

.PHONY: obj/$(static_library)
obj/$(static_library): src/gmp-h.ads obj-static/gmp_macros.o | obj obj-static
	$(GNATMAKE) -c $(ada_units) -D obj-static $(GNATMAKE_OPTIONS) \
          -cargs $(ADAFLAGS)
	ar cr $@ obj-static/*.o
	ranlib $@

obj-dynamic/gmp_macros.o: src/gmp_macros.c | obj-dynamic
	$(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@ -fPIC

obj-static/gmp_macros.o: src/gmp_macros.c | obj-static
	$(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@

obj/$(gnat_project): template_for_installed_project | obj
	sed \
          -e '/@LDLIBS@/{s||$(patsubst %,"%",$(LDLIBS))|;s/" "/", "/g}' \
	  $(foreach v,ALI_DIR LIB_NAME SO_DIR SRC_DIR,-e "s|@$(v)@|$($(v))|") \
          $< > $@

src/gmp-h.ads: gmp-h.ads.sed | obj
	echo '#include <gmp.h>' > obj/tmp.h
	cd obj && $(CXX) $(CPPFLAGS) $(CXXFLAGS) --dump-ada-spec tmp.h
	sed -f $< obj/*_gmp_h.ads > $@
  # Uncomment this when debugging a new version
  #	diff -u obj/*_gmp_h.ads $@ | less

obj obj-dynamic obj-static:
	mkdir $@
clean::
	rm -f src/gmp-h.ads
	rm -fr obj obj-dynamic obj-static
	find -name "*~" -delete

######################################################################
.PHONY: test
test: | demo-dynamic demo-static
	$(MAKE) install DESTDIR=demo-install

	$(GNATMAKE) demo.adb \
	  -o demo-dynamic/demo -D demo-dynamic $(GNATMAKE_OPTIONS) \
	  -aIdemo-install$(SRC_DIR)/$(LIB_NAME) \
	  -aOdemo-install$(ALI_DIR)/$(LIB_NAME) \
	  -cargs $(ADAFLAGS) -gnata \
	  -largs $(LDFLAGS) demo-install$(SO_DIR)/$(development_link) $(LDLIBS)
	LD_LIBRARY_PATH=demo-install$(SO_DIR) demo-dynamic/demo

	$(GNATMAKE) demo.adb \
	  -o demo-static/demo -D demo-static $(GNATMAKE_OPTIONS) \
	  -aIdemo-install$(SRC_DIR)/$(LIB_NAME) \
	  -aOdemo-install$(ALI_DIR)/$(LIB_NAME) \
	  -cargs $(ADAFLAGS) -gnata \
	  -largs $(LDFLAGS) demo-install$(A_DIR)/$(static_library) $(LDLIBS)
	demo-static/demo

	$(MAKE) uninstall DESTDIR=demo-install
	test `find demo-install -type f | wc -l` = 0

demo-dynamic demo-static:
	mkdir $@
clean::
	rm -f b~demo.adb b~demo.ads b~demo.ali b~demo.o
	rm -fr demo-dynamic demo-install demo-static

######################################################################
.PHONY: install
install: build
	install -m644 -Dt$(DESTDIR)$(SRC_DIR)/$(LIB_NAME) src/*
	install -m644 -Dt$(DESTDIR)$(GPR_DIR) obj/$(gnat_project)
	install -m444 -Dt$(DESTDIR)$(ALI_DIR)/$(LIB_NAME) obj-dynamic/*.ali
	install -m644 -Dt$(DESTDIR)$(A_DIR) obj/$(static_library)
	install -m644 -Dt$(DESTDIR)$(SO_DIR) obj/$(shared_library)
	ln -fs $(shared_library) $(DESTDIR)$(SO_DIR)/$(development_link)

.PHONY: uninstall
uninstall:
	rm -fr $(DESTDIR)$(SRC_DIR)/$(LIB_NAME) \
	       $(DESTDIR)$(ALI_DIR)/$(LIB_NAME)
	rm -f  $(DESTDIR)$(GPR_DIR)/$(gnat_project) \
	       $(DESTDIR)$(A_DIR)/$(static_library) \
	       $(DESTDIR)$(SO_DIR)/$(shared_library) \
	       $(DESTDIR)$(SO_DIR)/$(development_link)

######################################################################
.PHONY: clean
