#    GMPAda, binding to the Ada Language for the GNU MultiPrecision library.
#    Copyright (C) 2007-2017 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

SOVERSION := 2

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

# Use environment variables if available, this is common practice for
# CFLAGS and LDFLAGS.
CPPFLAGS ?=
CFLAGS   ?= -O2
CXXFLAGS ?=
ADAFLAGS ?= -O2 -gnatn
# Inlining helps a lot for the thin binding.
LDFLAGS  ?=

.NOTPARALLEL:
GNATMAKE_OPTIONS := -j$(shell getconf _NPROCESSORS_ONLN)

ifdef ALL_CHECKS
  CFLAGS += -Wall -Wextra -pedantic -Wformat-security -g
  ADAFLAGS += -Wall -Wextra -g -gnataEfoqQ -gnatVa -gnatw.eH.Y \
  -gnatyBdIoOSuxy -fstack-check
  LDFLAGS += -Wl,--as-needed -Wl,-z,defs
  GNATMAKE_OPTIONS := -s -v
endif

# We want the same compiler for C and Ada sources.
# Accept both gcc-4.9 and gcc-5.
CC := $(notdir $(shell which `gnatmake --version \
  | sed '1{s/^GNATMAKE \(\([0-9]\+\)\.[0-9]\+\).*/gcc-\1 gcc-\2/;q}'`))
ifneq ($(words $(CC)),1)
 $(error Failed to set CC from gnatmake output.)
endif
CXX := $(subst cc,++,$(CC))

LDLIBS := -lgmp

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

# Each of the following path should be prefixed with
DESTDIR :=

# The sources files are installed into a LIB_NAME subdirectory of
SRC_DIR := usr/share/ada/adainclude

# A LIB_NAME.gpr project convenient for library usage is installed into
GPR_DIR := usr/share/gpr
# The content of this file ignores DESTDIR.

# The GNAT ALI files are installed into a LIB_NAME subdirectory of
ALI_DIR := usr/lib/ada/adalib

# The static and dynamic library are installed into
LIB_DIR := usr/lib

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

ada_bodies      := $(wildcard src/*.adb)
ada_specs       := src/gmp-h.ads \
  $(filter-out src/gmp-h.ads,$(wildcard src/*.ads))
ada_units       := $(ada_bodies) $(filter-out $(ada_bodies:b=s),$(ada_specs))
C_SOURCES       := $(wildcard src/*.c)
C_OBJ_DYNAMIC   := $(patsubst src/%.c,obj-dynamic/%.o,$(C_SOURCES))
C_OBJ_STATIC    := $(patsubst src/%.c,obj-static/%.o, $(C_SOURCES))

# Default target is:
.PHONY: build
build: obj/lib$(LIB_NAME).so.$(SOVERSION) \
       obj/lib$(LIB_NAME).a \
       obj/$(LIB_NAME).gpr

obj/lib$(LIB_NAME).so.$(SOVERSION): $(ada_bodies) $(ada_specs) $(C_OBJ_DYNAMIC) | obj
	gnatmake -c $(ada_units) -D obj-dynamic $(GNATMAKE_OPTIONS) \
          -cargs $(ADAFLAGS) -fPIC
	$(CC) -shared -o $@ -Wl,-soname,lib$(LIB_NAME).so.$(SOVERSION) \
          obj-dynamic/*.o $(LDFLAGS) $(LDLIBS) -lgnat

obj/lib$(LIB_NAME).a: $(ada_bodies) $(ada_specs) $(C_OBJ_STATIC) | obj
	gnatmake -c $(ada_units) -D obj-static $(GNATMAKE_OPTIONS) \
          -cargs $(ADAFLAGS)
	ar cr $@ obj-static/*.o
	ranlib $@

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

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

obj/$(LIB_NAME).gpr: template_for_installed_project
	sed \
          -e s/@LIB_NAME@/$(LIB_NAME)/ \
          -e '/@LDLIBS@/{s||$(patsubst %,"%",$(LDLIBS))|;s/" "/", "/g}' \
          $(foreach d,SRC ALI LIB \
          ,-e "s|@$(d)_DIR@|`realpath -m $($(d)_DIR) --relative-to=$(GPR_DIR)`|") \
          $< > $@

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 > $@

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) \
          -largs $(LDFLAGS) -Ldemo-install/$(LIB_DIR) -l$(LIB_NAME) $(LDLIBS)
	LD_LIBRARY_PATH=demo-install/$(LIB_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) \
          -largs $(LDFLAGS) demo-install/$(LIB_DIR)/lib$(LIB_NAME).a $(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 -fr demo-dynamic demo-install demo-static

######################################################################
.PHONY: install
install: build
	install --directory $(DESTDIR)/$(SRC_DIR)/$(LIB_NAME)
	install --mode=644 $(ada_bodies) $(ada_specs) $(C_SOURCES) $(DESTDIR)/$(SRC_DIR)/$(LIB_NAME)
	install --directory $(DESTDIR)/$(GPR_DIR)
	install --mode=644 obj/$(LIB_NAME).gpr $(DESTDIR)/$(GPR_DIR)
	install --directory $(DESTDIR)/$(ALI_DIR)/$(LIB_NAME)
	install --mode=444 obj-dynamic/*.ali $(DESTDIR)/$(ALI_DIR)/$(LIB_NAME)
	install --directory $(DESTDIR)/$(LIB_DIR)
	install --mode=644 obj/lib$(LIB_NAME).a $(DESTDIR)/$(LIB_DIR)
	install --mode=644 obj/lib$(LIB_NAME).so.$(SOVERSION) $(DESTDIR)/$(LIB_DIR)
	ln --force --symbolic lib$(LIB_NAME).so.$(SOVERSION) $(DESTDIR)/$(LIB_DIR)/lib$(LIB_NAME).so

.PHONY: uninstall
uninstall:
	rm -rf $(DESTDIR)/$(SRC_DIR)/$(LIB_NAME)
	rm -f $(DESTDIR)/$(GPR_DIR)/$(LIB_NAME).gpr
	rm -rf $(DESTDIR)/$(ALI_DIR)/$(LIB_NAME)
	rm -f $(DESTDIR)/$(LIB_DIR)/lib$(LIB_NAME).a
	rm -f $(DESTDIR)/$(LIB_DIR)/lib$(LIB_NAME).so.$(SOVERSION)
	rm -f $(DESTDIR)/$(LIB_DIR)/lib$(LIB_NAME).so

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