# Makefile for optim package for Octave
#
# Copyright (C) 2016-2019 Olaf Till <i7tiol@t-online.de>
#
# 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/>.


# before cross building, pre-build at least $(TEXIFILE) natively,
# e.g. with targets 'doc', 'html', or 'prebuild'


CXXCPP = @CXXCPP@

MKOCTFILE ?= @MKOCTFILE@
ifndef CXXFLAGS
CXXFLAGS := $(shell $(MKOCTFILE) -p CXXFLAGS) -Wall
endif

# intentionally doesn't consider environment variables
OCTAVE_LAPACK_LIBS := $(shell $(MKOCTFILE) -p LAPACK_LIBS)
# reported necessary for Apple's VecLib framework by Carlo de Falco
# <carlo.defalco@gmail.com>
OCTAVE_BLAS_LIBS := $(shell $(MKOCTFILE) -p BLAS_LIBS)
## The above libs were formerly passed to mkoctfile by appending them
## to LFLAGS. This possibility is going to disappear, it's still
## present in 5.1, but with a deprecation warning. So these libs have
## to be specified on the commandline of mkoctfile. This was formerly
## not possible for -framework, but seemingly is now since
## 4.4. Versions <4.4 are at the loss for -framework, sorting this out
## here would be a mess. I hope this won't be a problem.

INFOFILE := ../doc/optim.info
TEXIFILE := $(addsuffix .texi,$(basename $(INFOFILE)))
TXIFILE := $(addsuffix .txi,$(basename $(INFOFILE)))
HTMLDIR := ../doc/html/
OCTFILES := __bfgsmin.oct numgradient.oct numhessian.oct __disna_optim__.oct

OCTSOURCEFILES := $(addsuffix .cc,$(basename $(OCTFILES)))
DSFILES := $(addsuffix .docstrings,$(OCTSOURCEFILES))
MFILES := $(wildcard *.m) $(wildcard ../inst/*.m)

.PHONY: all clean distclean doc prebuild html

.INTERMEDIATE: MFDOCSTRINGS $(DSFILES)

all: doc $(OCTFILES)

prebuild: doc html

error-helpers.o: error-helpers.cc error-helpers.h
	CXXFLAGS="$(CXXFLAGS)" $(MKOCTFILE) -c error-helpers.cc

# __disna_optim__ should be linked to the same Lapack library as used by Octave
__disna_optim__.oct: __disna_optim__.cc error-helpers.h config.h error-helpers.o
	CXXFLAGS="$(CXXFLAGS)" $(MKOCTFILE) $(OCTAVE_LAPACK_LIBS) $(OCTAVE_BLAS_LIBS) __disna_optim__.cc error-helpers.o

%.oct: %.cc error-helpers.h config.h error-helpers.o
	CXXFLAGS="$(CXXFLAGS)" $(MKOCTFILE) $< error-helpers.o

doc: $(INFOFILE)

$(INFOFILE): $(TEXIFILE)
	makeinfo $(TEXIFILE) -o $(INFOFILE)

html: $(TEXIFILE)
	makeinfo --html -o $(HTMLDIR) $(TEXIFILE)

$(TEXIFILE): $(TXIFILE) MFDOCSTRINGS $(DSFILES) munge-texi.pl
	./munge-texi.pl MFDOCSTRINGS $(DSFILES) < $(TXIFILE) > $(TEXIFILE)

MFDOCSTRINGS: $(MFILES) mkdoc.pl
	./mkdoc.pl $(MFILES) > MFDOCSTRINGS

# take long CPP macro names, unlikely to be present in package code
# (which is checked) or to be defined by Octave (which can't be
# checked)
RDEFUN_DLD := DEFUN_DLD_REPLACEMENT_FOR_PACKAGE_DOCS
RDEFUNX_DLD := DEFUNX_DLD_REPLACEMENT_FOR_PACKAGE_DOCS
# Docstrings defined as C strings are obtained from a compiled C
# program. This should be the cleanest way to correctly get all
# special characters defined in these strings.
%.cc.docstrings: %.bin
	(echo "### This file is generated automatically from the"; echo "### corresponding .cc file by a Makefile rule."; echo ""; ./$<) > $@
# Explanation of the command after the checks: Macro names are changed
# by `sed' so that a different definition can be given to them on the
# `cpp' commandline. After running the `cpp' command, one can be sure
# that there are not more than one `$(RDEFUN_DLD)' resulting from a
# DEFUN(X)_DLD invocation in the original code at one line, that every
# occurance of `$(RDEFUN_DLD)' indeed corresponds to an original macro
# invocation, and not to `DEFUN(X)_DLD' within a comment or a string,
# and that we have all necessary information within one line of
# text. The package code is expected to give the function
# documentation as a string constant directly in the macro invocation,
# as is normally done.
%.bin: %.cc
	if grep -q $(RDEFUN_DLD) $<; then echo "The string '$(RDEFUN_DLD)' must not be present in source code, but is in $<."; exit 1; fi
	if grep -q $(RDEFUNX_DLD) $<; then echo "The string '$(RDEFUNX_DLD)' must not be present in source code, but is in $<."; exit 1; fi
	(echo "#include <stdio.h>"; echo "int main () {"; sed -e s/DEFUN_DLD/$(RDEFUN_DLD)/g -e s/DEFUNX_DLD/$(RDEFUNX_DLD)/g $< | $(CXXCPP) `$(MKOCTFILE) -p INCFLAGS` -x c++ -iquote '.' -D'$(RDEFUN_DLD)(name,args,nargout,doc)=$(RDEFUN_DLD)(name,doc)' -D'$(RDEFUNX_DLD)(name,fname,gname,args,nargout,doc)=$(RDEFUN_DLD)(name,doc)' - | sed -e '/.*$(RDEFUN_DLD)/!D'; echo "}";) | $(CXX) -x c++ -D'$(RDEFUN_DLD)(name,doc)=printf("%c" #name "\n@c " #name " $<\n" doc "\n\n", 0x1D);' -o $@ -

clean:
	$(RM) *.o octave-core *.oct *.cc.docstrings MFDOCSTRINGS *~

distclean:
	$(RM) *.o octave-core *.oct *.cc.docstrings config.h config.log config.status MFDOCSTRINGS *~

maintainer-clean:
	$(RM) *.o *.oct octave-core *.cc.docstrings config.h config.log config.status MFDOCSTRINGS *~ $(INFOFILE) $(TEXIFILE)
