#    GMPAda, binding to the Ada Language for the GNU MultiPrecision library.
#    Copyright (C) 2007-2015 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
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 -Wformat -Wformat-security -g
  ADAFLAGS += -Wall -Wextra -g -gnataEfoqQ -gnatVa -gnatw.eH.Y \
  -gnatyBdIoOSuxy -fstack-check -Wunused -Wuninitialized
  LDFLAGS += -Wl,--as-needed -Wl,-z,defs
  GNATMAKE_OPTIONS += -s -v -we
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

LDLIBS := -lgmp -lmpfr

##############################
# 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/ada/adainclude
# 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_SOURCES     := $(wildcard src/*.ad[bs]) src/gmp-constants.ads
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_SOURCES) $(C_OBJ_DYNAMIC)
	gnatmake -c src/*.ad[bs] -D obj-dynamic $(GNATMAKE_OPTIONS) \
          -cargs $(ADAFLAGS) -fPIC
	gcc -shared -o $@ -Wl,-soname,lib$(LIB_NAME).so.$(SOVERSION) \
          obj-dynamic/*.o $(LDFLAGS) $(LDLIBS) -lgnat-$(subst gcc-,,$(CC))

obj/lib$(LIB_NAME).a: $(ADA_SOURCES) $(C_OBJ_STATIC)
	gnatmake -c src/*.ad[bs] -D obj-static $(GNATMAKE_OPTIONS) \
          -cargs $(ADAFLAGS)
	ar cr $@ obj-static/*.o
	ranlib $@

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

$(C_OBJ_STATIC): obj-static/%.o: src/%.c
	$(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-constants.ads: obj/generate_constants
	$< > $@
  # If caller has set SOURCE_DATE_EPOCH, avoid generating
  # unreproducible timestamps in ALI files.
  ifdef SOURCE_DATE_EPOCH
	touch -d "@$(SOURCE_DATE_EPOCH)" $@
  endif

obj/generate_constants: generate_constants.c
	$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $< $(LDLIBS) -o $@

clean::
	rm -f src/gmp-constants.ads obj/* obj-dynamic/* obj-static/*
	find -name "*~" -delete

######################################################################
.PHONY: test
test:
	mkdir -p demo-install
	$(MAKE) install DESTDIR=demo-install

	gnatmake demo/demo.adb -o demo/obj-dynamic/demo -D demo/obj-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/obj-dynamic/demo

  # This test will fail once gnatmake drops project support, but for
  # now we can test projects without gprbuild.
	gnatmake -aPdemo-install/$(GPR_DIR) -Pdemo/demo.gpr
	LD_LIBRARY_PATH=demo-install/$(LIB_DIR) demo/obj-project/demo

	gnatmake demo/demo.adb -o demo/obj-static/demo -D demo/obj-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/obj-static/demo

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

clean::
	rm -f demo/obj-dynamic/* demo/obj-project/* demo/obj-static/*
	rm -fr demo-install

######################################################################
.PHONY: install
install: build
	install --directory $(DESTDIR)/$(SRC_DIR)/$(LIB_NAME)
	install --mode=644 src/*.ad[sb] src/*.[ch] $(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
