########################################################
# Configuration variables

PYTHON ?= python3
PYVENV ?= .venv
STIMULUS ?= $(PYVENV)/bin/stimulus

all: pre_build

########################################################
# Main package

top_srcdir=cigraph
VERSION=$(shell tools/getversion.sh)

# We put the version number in a file, so that we can detect
# if it changes

version_number: force
	@echo '$(VERSION)' | cmp -s - $@ || echo '$(VERSION)' > $@

# Source files from the C library
CORESRC := $(shell cd $(top_srcdir) ; git ls-files --full-name src | \
	      grep -v '\.txt$$' | grep -v "COPYING$$" | grep -v "README" | \
		  grep -v "src/config.h.in" )

# Vendored dependencies of the C library. We don't need BLAS / LAPACK
# because they are included in R. We don't need F2C either because we
# will use the original Fortran sources for ARPACK. We also rely on an
# external GLPK instead of the one vendored in igraph because the
# vendored GLPK does not fit well in the build process of the R interface.
VENDORSRC := $(shell cd $(top_srcdir) ; git ls-files --full-name vendor | \
	      grep -v "^vendor/lapack/" | grep -v "^vendor/f2c" | \
	      grep -v "^vendor/glpk/" | \
	      grep -v '\.txt$$' | grep -v "COPYING$$" | grep -v "README" )

# Include files from the C library
CINC := $(shell cd $(top_srcdir) ; git ls-files --full-name include)
CINC := $(patsubst include/%, src/include/%, $(CINC))

# Transform CORESRC and VENDORSRC to their target folders in src/
CORESRC := $(patsubst src/%, src/core/%, $(CORESRC))
VENDORSRC := $(patsubst vendor/%, src/vendor/%, $(VENDORSRC))

# Rules that copy the sources from cigraph/ to src/
$(CORESRC): src/core/%: $(top_srcdir)/src/%
	mkdir -p $(@D) && cp $< $@
$(VENDORSRC): src/vendor/%: $(top_srcdir)/vendor/%
	mkdir -p $(@D) && cp $< $@
$(CINC): src/include/%: $(top_srcdir)/include/%
	mkdir -p $(@D) && cp $< $@

# Files generated by flex/bison

PARSER := $(shell cd $(top_srcdir) ; git ls-files --full-name src | \
	    grep -E '\.(l|y)$$')
PARSER1 := $(patsubst src/%.l, src/core/%.c, $(PARSER))
PARSER2 := $(patsubst src/%.y, src/core/%.c, $(PARSER1))

YACC=bison -b yy -d
LEX=flex

%.c: %.y
	$(YACC) $<
	mv -f yy.tab.c $@
	mv -f yy.tab.h $(@:.c=.h)

%.c: %.l
	$(LEX) -o $@ --header-file=$(@:.c=.h) $<

# Create Python virtualenv for Stimulus

venv: $(PYVENV)/stamp

$(PYVENV)/stamp: tools/build-requirements.txt
	$(PYTHON) -m venv $(PYVENV)
	$(PYVENV)/bin/pip install -r $<
	touch $(PYVENV)/stamp

# Apply possible patches

patches: $(CORESRC) $(VENDORSRC) $(CINC) $(PARSER2)
	if [ -d "patches" ]; then \
		find patches -type f -name '*.patch' -print0 | sort -z | xargs -t -0 -n 1 tools/apply-patch.sh; \
	fi
	-rm -f src/*.orig
	tools/fix-lexers.sh

# C files generated by C configure

CGEN = src/include/igraph_export.h src/include/igraph_threading.h src/include/igraph_version.h

src/include/igraph_export.h: tools/stimulus/igraph_export.h
	mkdir -p src/include
	cp $< $@

src/include/igraph_threading.h: $(top_srcdir)/include/igraph_threading.h.in
	mkdir -p src
	sed 's/#cmakedefine01 IGRAPH_THREAD_SAFE/#define IGRAPH_THREAD_SAFE 0/g' $< >$@

src/include/igraph_version.h: $(top_srcdir)/include/igraph_version.h.in
	mkdir -p src/include
	cp $< $@

# R source and doc files

RSRC := $(shell git ls-files R doc inst demo NEWS cleanup.win configure.win)

# ARPACK Fortran sources

ARPACK := $(shell git ls-files vendor/arpack)
ARPACK2 := $(patsubst vendor/arpack/%, src/vendor/arpack/%, $(ARPACK))

$(ARPACK2): src/vendor/arpack/%: vendor/arpack/%
	mkdir -p $(@D) && cp $< $@

# libuuid

UUID := $(shell git ls-files vendor/uuid)
UUID2 := $(patsubst vendor/uuid/%, src/vendor/uuid/%, $(UUID))

$(UUID2): src/vendor/uuid/%: vendor/uuid/%
	mkdir -p $(@D) && cp $< $@

# Simpleraytracer

RAY := $(shell git ls-files vendor/simpleraytracer)
RAY2 := $(patsubst vendor/simpleraytracer/%, src/vendor/simpleraytracer/%, $(RAY))

$(RAY2): src/vendor/%: vendor/%
	mkdir -p $(@D) && cp $< $@

# R files that are generated/copied

RGEN = R/aaa-auto.R src/rinterface.c \
	configure src/config.h.in src/Makevars.in src/Makevars.win src/Makevars.ucrt

# Files generated by stimulus

src/rinterface.c: \
		$(top_srcdir)/interfaces/functions.yaml \
		$(top_srcdir)/interfaces/types.yaml \
		tools/stimulus/rinterface.c.in  \
		tools/stimulus/functions-R.yaml \
		tools/stimulus/types-RC.yaml
	$(STIMULUS) \
           -f $(top_srcdir)/interfaces/functions.yaml \
           -f tools/stimulus/functions-R.yaml \
           -i tools/stimulus/rinterface.c.in \
           -o src/rinterface.c \
           -t $(top_srcdir)/interfaces/types.yaml \
           -t tools/stimulus/types-RC.yaml \
           -l RC

R/aaa-auto.R: \
		$(top_srcdir)/interfaces/functions.yaml \
		$(top_srcdir)/interfaces/types.yaml \
		tools/stimulus/aaa-auto.R.in \
		tools/stimulus/functions-R.yaml \
		tools/stimulus/types-RR.yaml
	$(STIMULUS) \
           -f $(top_srcdir)/interfaces/functions.yaml \
           -f tools/stimulus/functions-R.yaml \
           -i tools/stimulus/aaa-auto.R.in \
           -o R/aaa-auto.R \
           -t $(top_srcdir)/interfaces/types.yaml \
           -t tools/stimulus/types-RR.yaml \
           -l RR

# configure files

configure src/config.h.in: configure.ac
	autoheader; autoconf
	# CMake needs HAVE_ISFINITE but configure.ac generates HAVE_DECL_ISFINITE
	echo "#define HAVE_ISFINITE HAVE_DECL_ISFINITE" >>src/config.h.in

# This is the list of all object files in the R package,
# we write it to a file to be able to depend on it.
# Makevars.in, Makevars.win and Makevars.ucrt are only regenerated if
# the list of object files changes.

OBJECTS := $(shell echo $(CORESRC) $(VENDORSRC) $(ARPACK) $(RAY) $(UUID) | \
		tr ' ' '\n' | \
        grep -E '\.(c|cpp|cc|f|l|y)$$' | \
		sed 's/\.[^\.][^\.]*$$/.o/' | \
		sed 's,^src/,,' \
		) rinterface.o rinterface_extra.o rrandom.o lazyeval.o init.o cpp11.o cpprinterface.o

object_files: force
	@echo '$(OBJECTS)' | cmp -s - $@ || echo '$(OBJECTS)' > $@

src/Makevars.win src/Makevars.ucrt src/Makevars.in: src/%: tools/stimulus/% \
		object_files
	cp $< $@
	printf "%s" "OBJECTS=" >> $@
	# Can't insert newlines, not all make variants accept them
	cat object_files >> $@

pre_build: venv patches $(CSRC) $(CINC2) $(PARSER2) $(RSRC) $(RGEN) \
	$(CGEN) $(RAY2) $(ARPACK2) $(UUID2)

clean:
	rm -rf src/core src/vendor src/include src/Makevars.in src/Makevars.ucrt src/Makevars.win src/config.h.in src/rinterface.c R/aaa-auto.R

.PHONY: all igraph force clean check check-cran check-rhub check-links install test

.NOTPARALLEL:
