# ESA (C) 2000-2022
#
# This file is part of ESA's XMM-Newton Scientific Analysis System (SAS).
#
#    SAS 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.
#
#    SAS 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 SAS.  If not, see <http://www.gnu.org/licenses/>.
#
# Each Makefile should include this file. 
#
# The following targets exist:
#   all (default)   builds packages. Produces an HTML
#                   result page. Non-zero exit code in case of an error
#   check           inspects, builds and tests packages
#   incheck         inspects, builds and tests packages: only ps doc, leaves
#                   object files so as to allow one to make incremental
#                   builds.
#   depend          construct dependencies
#   bin             create everything needed to run the software
#   clean           remove all but configuration, executables and documentation
#   clobber         remove all that is not part of original distribution
#   tests           compile test programs
#   test            run all tests; exits != 0 if one or more failed
#   data            run data generating scripts
#   ps              produces PostScript documentation
#   html            produces HTML documentation
#   doc             produce PostScript and HTML documentation
#   dist            make a tgz file of a package
#   upload          package the directory and send it to the SOC
#   distcheck       run the distribution check for the package
#   depcheck        run the dependency check for the package
#
# The following variables can be defined in a Makefile that includes this file:
#   BINS            binaries that are to be compiled
#   LIBS            libraries that are to be constructed
#   COMBILIBS       library that is constructed from a list of other libraries
#   TASKS           tasks to be constructed from a Fortran module
#   SCRIPTS         scripts that should be publicly accessible
#   DATACRIPTS      scripts that are executed for target 'data'
#   FMODS           fortran modules that are not part of a library
#   LINKS           extra symbolic links; a rule has to be provided as well
#   EXTERNALS       extra linker/compiler flags related to external packages
#   CONFIGFILES     configuration files
#   USEDLIBS        list of all libraries to be included and linked
#   a_OBJS          objects to link with target a
#   TEXDOCS         tex documents
#   TEXFORM         format of tex documents (book|package[=default])
#   TESTBINS        binaries that are to be compiled for testing
#   TESTS           executables that should exit with status 0
#   MKDIRS          directories to be created during make
#   DOCS            HTML pages that are entry points into the documentation
#   DOCDIRS         HTML subdirectories
#   INTERFACES      Files to export to 'include' directory (default is the directory)
#   INTERNALS       Package subdirectories to be used to search for headers/modules
#   DEVBINS         development binaries. As BINS but placed in bin/devel
#   DEVSCRIPTS      development scripts. As SCRIPTS but placed in bin/devel
#   DEVTASKS        development tasks. As TASKS but placed in bin/devel
#   DATADIRS        directories to be linked under lib/data
#   ODFDIRS         directories to be linked under lib/testodf
#   PERLDIRS        directories with Perl code to be linked directly under lib/perl5
#   PERLMODS        for individual modules that must be placed under lib/perl5
#   EXTPERLMODS     list of external perl modules to be built for a specific perl task
#   EXTPERLDIR      directory containing the external perl modules EXTPERLMODS
#   EXTPERLSCRIPT   script to build sequentially EXTPERLMODS
#   PYTHONMODS      for individual python modules which must be placed under lib/python
#   PYTHONDIRS      directories with python code to be linked directly under lib/python
#
# The following environment variables have to be set:
#   SAS_DIR         the location of the toplevel of the official SAS distribution
#   SAS_PATH        a list of directories containing SAS packages.
#

SHELL := /bin/bash
GNUTAR := /usr/bin/gtar
GNUFIND := /usr/bin/find

SHARED = yes

SHAREDVERSION = yes

TARGETOS := x86_64-pc-linux-gnu

TARGET_OS := RHEL8.10

TRACE = no

DEBUG = yes

VERBOSE = no

PROFILE = no

RELEASETYPE = user

SLOPPY = yes

STRICTCPP = no

RUNTESTS = yes
FULLDOC = yes

OPTIMIZATION = no
OLEVEL := 2
F90OLEVEL := 2
CXXOLEVEL := $(OLEVEL)

SAS_PERL := /sasbuild/tools/perl/bin/perl

PYTHON := /usr/bin/python

#
# Profiling requires DEBUG=yes, SHARED=no and SHAREDVERSION=no
#

ifeq ($(PROFILE), yes)
  DEBUG = yes
  SHARED = no
  OPTIMIZATION = no
endif


#
# Get rid of the several entering/leaving directory messages
#

MAKEFLAGS := --no-print-directory


#
# Compilation flags determined by configure.
# They may be modified later.
#

CXXFLAGS := -Wall -DGFORTRAN -std=gnu++14
CFLAGS := -Wall -std=gnu++14
F90FLAGS := -fimplicit-none -fno-range-check -DGFORTRAN -fallow-argument-mismatch
FFLAGS := -fno-range-check -DGFORTRAN -fallow-argument-mismatch


#
# Linker flags determined by configure
#

LDFLAGS :=  -Wl,-rpath,\$$ORIGIN/../lib -Wl,-rpath,\$$ORIGIN/../libextra


#
# Path names
#

#
# Directory with utilities under the sas package
#

SASBIN := $(SAS_DIR)/packages/sas/bin
SASBINDEV := $(SAS_DIR)/bin/devel


#
# TOPDIR is that component of the SAS_PATH that we're in right now.
# Evaluate it only in the toplevel make and pass it down to recursive makes.
#
ifeq (0,$(MAKELEVEL))
  TOPDIR := $(shell $(SASBIN)/whichpart $(SAS_PATH))
  MAKE += "TOPDIR=$(TOPDIR)"
endif

#
# SASDIRS is the space separated list of directories in SAS_PATH
# Defer evaluation by sing = instead of :=
#

SASDIRS = $(shell $(SASBIN)/saspath $(SAS_PATH))

#
# RELATDIR is the relative path to TOPDIR
#

REFERDIR := $(patsubst /%,%,$(subst $(shell cd $(TOPDIR);pwd),,$(shell pwd)))
RELATDIR := $(subst . .,./.,$(patsubst %,..,$(subst /, ,$(REFERDIR))))

# 
# Basic SAS directories
#

LIBDIR := $(TOPDIR)/lib

PERLLIBDIR := $(LIBDIR)/perl5

PYTHONLIBDIR := $(LIBDIR)/python

PYTHONLIBDISTSDIR := $(PYTHONLIBDIR)/dists

PYTHONLIBPYSASDIR := $(PYTHONLIBDIR)/pysas

INCDIR := $(TOPDIR)/include

BINDIR := $(TOPDIR)/bin
DEVBINDIR := $(TOPDIR)/bin/devel

CONFIGDIR := $(TOPDIR)/config

DOCDIR := $(TOPDIR)/doc
DATADIR := $(TOPDIR)/lib/data
DATADIRTMP := $(TOPDIR)/lib/data/tmp
ODFDIR := $(TOPDIR)/lib/testodf

#
# List of all directories that contain SAS libraries
#

LIBDIRS += $(addsuffix /lib,$(SASDIRS))


#
#    V A R I A B L E S 
#


#
# In this directory we make combilibs.
#

COMBIDIR := __combidir__

#
# AKA and RELEASE 
#

AKA := 22.0.0

ifneq (,$(wildcard RELEASE))
  RELEASE := $(strip $(shell cat RELEASE))
  MAKE += RELEASE=$(RELEASE)
endif


#
# The package's version is equal to the contents 
# of the VERSION file encountered within it
#

ifneq (,$(wildcard VERSION))
  VERSION := $(strip $(shell cat VERSION))
  PKGDIR  := $(shell pwd)
  PACKAGE := $(notdir $(shell pwd))
  MAKE += PKGDIR=$(PKGDIR) VERSION=$(VERSION) PACKAGE=$(PACKAGE)

#
# Create a VERSION tag for the libraries
#
  ifeq ($(SHARED),yes)
   ifeq ($(SHAREDVERSION),yes)
     MAJOR_VERSION :=$(strip $(shell cat VERSION | cut -d. -f1))
     MINOR_VERSION :=$(strip $(shell cat VERSION | cut -d. -f2))

#
# From now on we can test against SO_VERSION, to determine usage of
# shared version numbering

     SO_VERSION := $(MAJOR_VERSION).$(MINOR_VERSION)
     MAKE += SO_VERSION=$(SO_VERSION)

   endif
  endif

endif

#
# document format: (package[default], book)
#
ifeq (,$(TEXFORM))
  TEXFORM := package
endif


#
# The default suffix of shared libraries as given by configure
#

SO := so

#
# This makes the list of packages topologically sorted according to dependencies
# This determines the package's building order 
#

PKGLIST = $(shell $(SASBIN)/mkpkglist)

#
# If tracing is on (yes) we add -DTRACE to C++ flags
#

ifeq ($(TRACE),yes)
  CPPFLAGS += -DTRACE
endif


#
# These links must be registered before DEVTASKS and TASKS are 
# actually merged below. Go via an intermediate variable to prevent
# recursive expansion, given that the two variables are merged.
#

task_links := $(strip \
		$(addprefix $(BINDIR)/,$(TASKS)) \
		$(addprefix $(DEVBINDIR)/,$(DEVTASKS)))

LINKS += $(task_links)


#
# from now on there is no difference between TASKS and DEVTASKS
#

TASKS += $(DEVTASKS)


#
# Check which part of the infrastructure is used.
#

#
# Currently *all* tasks must include metatask :-(
# Someday that should be FIXED.
#

ifneq ($(TASKS),)
  ifneq (metatask,$(filter metatask,$(USEDLIBS)))
    USEDLIBS := metatask $(USEDLIBS) metatask
  endif
endif

#
# This is ugly, but cal and oal should be combilibs (someday to be FIXED)
#
# Must use sort to eliminate duplicates, or the hack does not work
# param -> qt needed, dal needed

#
# If param is used, then link in qt. This must not make
# used of EXTERNALS = qt because otherwise every task becomes a
# QtApplication, and this makes it difficult to run tasks in the
# background
#
ifeq (param,$(sort $(filter param,$(USEDLIBS))))
    USEDLIBS := $(USEDLIBS:param=param selector caloalutils dal slatec)
####    EXTERNALS += qt
    INCS += -I/sasbuild/tools/qt-x11-free/include
    LDLIBS += -L/sasbuild/tools/qt-x11-free/lib -lqt 
endif

ifeq (cal,$(sort $(filter cal,$(USEDLIBS))))
    USEDLIBS := $(USEDLIBS:cal=cal selector caloalutils selector slatec)
    CPPFLAGS += -DUSE_CAL
endif

ifeq (oal,$(sort $(filter oal,$(USEDLIBS))))
    USEDLIBS := $(USEDLIBS:oal=oal dal caloalutils slatec)
    CPPFLAGS += -DUSE_OAL
endif

ifeq (dal,$(sort $(filter dal,$(USEDLIBS))))
  CPPFLAGS += -DUSE_DAL
endif


#
# qt
#

ifeq (qt,$(sort $(filter qt,$(EXTERNALS))))
  CPPFLAGS += -DUSE_QT
endif


#
# cfitsio
#

ifeq (cfitsio,$(sort $(filter cfitsio,$(EXTERNALS))))
  CPPFLAGS += -DUSE_CFITSIO
endif

#
# Determine the type of tasks
#
# Look for anything with .pl and get rid of the .pl part
# Look for anything with .cc and get rid of the .cc part
# Look for anything with _mod.f90 and get rid of the _mod.f90 part
# Look for anything with .py and get rid of the .py part
#

PERLTASKS=$(strip $(subst .pl,,$(wildcard $(TASKS:=.pl))))
CXXTASKS=$(strip $(subst .cc,,$(wildcard $(TASKS:=.cc))))
FTASKS=$(strip $(subst _mod.f90,,$(wildcard $(TASKS:=_mod.f90))))
PYTHONTASKS=$(strip $(subst .py,,$(wildcard $(TASKS:=.py))))

#
# Tasks that main use of a c++ main
#
# Get out of TASKS the PERLTASKS and PYTHONTASKS
#

NEEDTASKMAIN = $(filter-out $(PERLTASKS) $(PYTHONTASKS), $(TASKS))

#
# Code that is to be generated automatically.
#

TASKHEADERS = $(addsuffix .h,$(NEEDTASKMAIN))
TASKHEADIMPS = $(addsuffix _h_imp.cc,$(NEEDTASKMAIN))
####TASKMODS = $(addsuffix _f_mod.f90,$(CXXTASKS)) $(addsuffix _f_mod.f90,$(PERLTASKS))
TASKMODS = $(addsuffix _f_mod.f90,$(CXXTASKS))
TASKMAINS = $(addsuffix _main.cc,$(NEEDTASKMAIN))
FTASKWRAPPERS = $(addsuffix _f.cc,$(CXXTASKS))
CXXTASKWRAPPERS = $(addsuffix _c.cc,$(FTASKS)) 
####FTASKWRAPPERS = $(addsuffix _f.cc,$(CXXTASKS)) $(addsuffix _f.cc,$(PERLTASKS))
####CXXTASKWRAPPERS = $(addsuffix _c.cc,$(FTASKS)) $(addsuffix _c.cc,$(PERLTASKS)) 
PERLTASKWRAPPERS =

#
#  
# On the road to a proper dependency mechanism at least for tex/ps
# documents, and in order to make incremental builds faster, the old
# dummy _ps rule (that is still available below) is no longer used
# in PSTARGETS. Rather we use .ps.gz.
#
####PSTARGETS += $(TEXDOCS:=_ps)
#

PSTARGETS += $(TEXDOCS:=.ps.gz)

#
# Since we do not have a proper dependency mechanism, we force making
# the documentation.
#

HTMLTARGETS += $(TEXDOCS:=_html)
DOCTARGETS += $(PSTARGETS) $(HTMLTARGETS)

#
# .prm files are no longer in use, but they appear in the make
# files. Convert .prm to .par. 
#

CONFIGFILES := $(CONFIGFILES:.prm=.par)

#
# List of all symbolic links to create before make depend or make all
# NOTE: the links for TASKS and DEVTASKS are registered earlier
#

LINKS += $(strip \
	$(addprefix $(LIBDIR)/,$(LIBFILES)) \
	$(addprefix $(LIBDIR)/,$(COMBILIBFILES)) \
	$(addprefix $(PERLLIBDIR)/,$(addsuffix .pl,$(PERLTASKS))) \
	$(addprefix $(PERLLIBDIR)/,$(PERLMODS)) \
	$(addprefix $(PERLLIBDIR)/,$(PERLDIRS)) \
	$(addprefix $(PYTHONLIBDIR)/,$(addsuffix .py,$(PYTHONTASKS))) \
	$(addprefix $(PYTHONLIBDIR)/, $(PYTHONMODS)) \
	$(addprefix $(PYTHONLIBDIR)/, $(PYTHONDIRS)) \
	$(addprefix $(BINDIR)/,$(BINS)) \
	$(addprefix $(BINDIR)/,$(SCRIPTS)) \
	$(addprefix $(DEVBINDIR)/,$(DEVBINS)) \
	$(addprefix $(DEVBINDIR)/,$(DEVSCRIPTS)) \
	$(addprefix $(CONFIGDIR)/,$(CONFIGFILES)) \
	$(addprefix $(DATADIR)/,$(DATADIRS)) \
	$(addprefix $(ODFDIR)/,$(ODFDIRS)) \
	$(addprefix $(DOCDIR)/,$(DOCDIRS)) \
	$(addprefix $(DOCDIR)/,$(TEXDOCS)) \
	$(addprefix $(DOCDIR)/,$(addsuffix .ps.gz,$(TEXDOCS))) \
	$(addprefix $(DOCDIR)/,$(addsuffix .pdf,$(TEXDOCS))) \
	$(addprefix $(DOCDIR)/,$(DOCS)))

#
# If INTERFACES is defined, create links to invidividual header files, 
# else create a link to the directory (with trailing '/' that can be 
# matched by a separate rule).
# Create an additional link to the ".mod" file, for each ".f90" file specified.
#

ifdef INTERFACES
LINKS += $(strip \
	$(addprefix $(INCDIR)/,$(INTERFACES)) \
	$(addprefix $(INCDIR)/,$(subst .f90,.mod,$(filter %.f90,$(INTERFACES)))))
else
LINKS += $(strip \
	$(addsuffix \/,$(addprefix $(INCDIR)/,$(COMBILIBS))) \
	$(addsuffix \/,$(addprefix $(INCDIR)/,$(LIBS))) \
	$(addsuffix \/,$(addprefix $(INCDIR)/,$(TASKS))))
endif

# 
# Define the list of files and directories to be cleaned
#

CLEANFILES += sasdoc_version.tex *.g90 gmon.out dataconv.out *.o *.M *% *~ .\#* *.idx *.dvi *.aux *.log *.bbl makedoc.log *.blg *.toc core core.* a.out $(TESTBINS) m_*.cc test.result $(TEXDOCS:=.tex) $(FTASKWRAPPERS) $(CXXTASKWRAPPERS) $(PERLTASKWRAPPERS) $(TASKMODS) $(TASKMAINS) ._.DS_Store .DS_Store

CLEANDIRS += Templates.DB autom4te.cache $(COMBIDIR)* __pychache__

#
# Define the list of files and directories to be clobbered
#

CLOBBERFILES += *.mod lib*.a lib*.so lib*.so.* lib*.dylib $(LINKS) $(BINS) $(DEVBINS) $(TASKS) $(TEXDOCS:=.ps.gz) *.pdf *.prm $(addprefix $(CONFIGDIR)/,$(CONFIGFILES)) *.tmp build_log_second *_log check.txt check.html build.txt build.html Make.depends $(TASKHEADERS) $(TASKHEADIMPS) *.out ._.DS_Store .DS_Store

CLOBBERDIRS += $(MKDIRS) $(TEXDOCS) __pycache__


#
# Define the PWD variable
#

PWD := $(shell pwd)


#
# Set the VPATH so that the -l dependencies to static libraries can be found
#

VPATH += $(LIBDIRS)

LIBBASES = $(strip $(LIBS) $(NEEDTASKMAIN))
LIBFILES = $(addprefix lib,$(addsuffix .a,$(LIBBASES)))

COMBILIBFILES = $(addprefix lib,$(addsuffix .a,$(COMBILIBS)))

#
# Set the proper debug flags if DEBUG is set.
#
# By default debugging is off for any building, which means that 
# --disable-debug is set at configure time.
# 
# Executables are stripped (-s option passed to ld), but this 
# option is not set here anymore. 
#

ifeq ($(DEBUG), yes)
  CFLAGS += -g
  CXXFLAGS += -g 

  F90FLAGS += -g
  FFLAGS += -g
endif

#
# Set the proper flags is PROFILE is set
#

ifeq ($(PROFILE), yes)
  CFLAGS += -pg
  CXXFLAGS += -pg
  F90FLAGS += -pg
  FFLAGS += -pg
  LDFLAGS += -pg
endif

#
# Set the proper flags when OPTIMIZATION is set
#

ifeq ($(OPTIMIZATION), yes)
  CFLAGS += -O$(CXXOLEVEL)
  CXXFLAGS += -O$(CXXOLEVEL)
  F90FLAGS += -O$(F90OLEVEL)
  FFLAGS += -O$(F90OLEVEL)
endif

#
# If SHARED (default), define USE_POPUP 
#

ifeq ($(SHARED), yes)
  CPPFLAGS += -DUSE_POPUP
endif

SHARED_LIBS_FLAGS = -shared -Wl,-h,$@ -Wl,-rpath,\$$ORIGIN -Wl,-rpath,\$$ORIGIN/../libextra

#
# If the $(SO_VERSION) is defined (not null), which means that both SHARED
# and SHAREDVERSION are set to yes, then set the proper order for shared 
# library numbering depending on whether we are in a Linux 
# or on a Mac OS X (Darwin) platform.
#

ifneq (,$(SO_VERSION))  
  ifeq ($(SO),dylib)
    # libFOO.M.m.dylib
    SO_FULL_EXT:=$(SO_VERSION).$(SO)
  endif
  ifeq ($(SO),so)
    # libFOO.so.M.m
    SO_FULL_EXT:=$(SO).$(SO_VERSION)
  endif
else
  SO_FULL_EXT:=$(SO)
endif



#
# C O N F I G U R A T I O N 
#

INSTALL := /usr/bin/install -c
CC      := gcc 
CPP     := gcc -E 
CXX     := g++
CXXCPP  := g++ -E
MOC	    := /sasbuild/tools/qt-x11-free/bin/moc

ECHO	:= /usr/bin/echo
ECHO_N  := -n
ECHO_C  := 

#
# Define a function that acts as echo -n
#

echon   = $(ECHO) $(ECHO_N) "$(1)$(ECHO_C)"


MV      := mv
MKDIR   := /usr/bin/mkdir

PREFIX  := /usr/local

LEX     := flex
YACC    := bison -y

#
# -->From here [until :-> below] the order is important
#
# If EXTERNALS includes any of the external tools below,
# then the proper flags are set.
#

#
# cfitsio
#

ifeq (cfitsio, $(findstring cfitsio,$(EXTERNALS)))
  LDLIBS += -lcfitsio
endif

#
# Qt
#

ifeq (qt, $(findstring qt,$(EXTERNALS)))
  INCS += -I/sasbuild/tools/qt-x11-free/include
  LDLIBS += -L/sasbuild/tools/qt-x11-free/lib -lqt 
endif

#
# Grace
#

ifeq (grace, $(findstring grace,$(EXTERNALS)))
  INCS += 
  LDLIBS += -lgrace_np
endif


#
# FTOOLS
#

ifeq (ftools, $(findstring ftools,$(EXTERNALS)))
  LDLIBS += -L/sasbuild/tools/headas/architecture/lib -lpow -ltcl8.0 -ltk8.0 -litcl3.0 -litk3.0
endif

#
# PGPLOT (will include X11)
#

ifeq (pgplot, $(findstring pgplot,$(EXTERNALS)))
  INCS += 
  LDLIBS += -lgfortran -lcpgplot  -lpng -lz -lpgplot   -lXaw -lXmu -lXt -lXext  -lX11 
endif

#
# X11
#
ifeq (X11, $(findstring X11,$(EXTERNALS)))
  INCS += 
  LDLIBS +=   -lXaw -lXmu -lXt -lXext  -lX11 
endif

#
# Perl
#

ifeq (perl, $(findstring perl,$(EXTERNALS)))
  INCS +=  -I/sasbuild/tools/perl-5.34.1/lib/5.34.1/x86_64-linux/CORE 
  LDLIBS += -Wl,-E  -fstack-protector-strong  -L/sasbuild/tools/perl-5.34.1/lib/5.34.1/x86_64-linux/CORE -lperl -lpthread -ldl -lm -lcrypt -lutil -lc
endif


#
# fftw 3 single precission
#

ifeq (fftw3f, $(findstring fftw3f,$(EXTERNALS)))
  INCS += 
  LDLIBS += -lfftw3f
endif

#
# fftw 3 double precission
#

ifeq (fftw3, $(findstring fftw3,$(EXTERNALS)))
  INCS += 
  LDLIBS += -lfftw3
endif


#
# Flags to generate position independent code
# At the moment this must be turned on explicitly.
#

ifeq ($(SHARED), yes)
  CFLAGS   += -fPIC

  # do not add -fPIC by default to CXXFLAGS since the main
  # program should not be compiled with -fPIC.

  CXXSHAREDFLAGS += -fPIC
  F90FLAGS += -fPIC
  FFLAGS   += -fPIC

  # lib.$(SO) is always a link to the actual library -- LIBFILES is added to 
  # LINKS. We do not use += because it create a space which we don't want

  LIBFILES := $(strip $(LIBFILES) $(addprefix lib,$(addsuffix .$(SO_FULL_EXT),$(LIBBASES))))
  COMBILIBFILES := $(strip $(COMBILIBFILES) $(addprefix lib,$(addsuffix .$(SO_FULL_EXT),$(COMBILIBS))))

  ifneq ($(SO),$(SO_FULL_EXT))
    # add links for versioned shared libraries
    LINKS+=$(addprefix $(LIBDIR)/lib,$(addsuffix .$(SO),$(LIBS)))
    LINKS+=$(addprefix $(LIBDIR)/lib,$(addsuffix .$(SO),$(COMBILIBS)))
    LINKS+=$(addprefix $(LIBDIR)/lib,$(addsuffix .$(SO),$(NEEDTASKMAIN)))
  endif

endif


#
# The list of targets when invoking 'make bin'
# Libraries are generated via a special rule since we have to remove VPATH=
# before doing the make.
#

TARGETS += $(strip $(FMODS:=.mod) extperlmods libs.here combilibs.here $(BINS) $(DEVBINS) $(TASKS) $(CONFIGFILES))



#
# Verbose flag
#

VERBOSE_FLAG =
ifeq ($(VERBOSE),yes)
  VERBOSE_FLAG = "-v"
endif


#
# Fortran compiler 
# 

F90 := gfortran
FC  := gfortran

#
# Includes
# 

INCS    += -I.


#
# More variables
#

AR	    := /usr/bin/ar
LN_S	:= ln -s
RANLIB	:= ranlib

#
# Down to here we have modified LDLIBS to take into account the
# EXTERNALS. Here LIBS_LDLIBS must be the same as LDLIBS.
# Make sure you use := and not = here!
#

LIBS_LDLIBS := $(LDLIBS)


# Here configure adds a few extra libraries, but on some machine these
# extra libraries must not be given when the shared libraries are
# created.
# Use this one when creating executables
#

LDLIBS += -lgfortran -lcfitsio -ldl -lm -L. 


#
# Use this one when creating libraries
#

LIBS_LDLIBS += -lgfortran -lcfitsio -ldl -lm -L. 


#
# The include files are determined by looking for the library directories in
# all include subdirectories of SAS_PATH.
# Make these recursively evaluated variable (= instead of :=) so that they
# are only evaluated where needed.
#
# This adds using namespace std to everything
#

ifeq ($(STRICTCPP), no)
  CPPFLAGS += -include $(SAS_DIR)/include/config-std.h
endif


CPPFLAGS += -imacros $(SAS_DIR)/config.h
CPPFLAGS += $(addprefix -I,$(addsuffix /include,$(SASDIRS)))
CPPFLAGS += $(addprefix -I,$(shell $(SASBIN)/findinclude $(sort $(USEDLIBS))))
CPPFLAGS += $(INCS) # $(X_CFLAGS)


#
# The include files are determined by looking for the library directories in
# all include subdirectories of SAS_PATH.
#

F90INCFLAGS += $(addprefix -I,$(addsuffix /include,$(SASDIRS)))
F90INCFLAGS += $(addprefix -I,$(shell $(SASBIN)/findinclude $(sort $(USEDLIBS))))


#
# Access to header files and modules that are not exported.
#

ifdef INTERNALS
  CPPFLAGS += $(addprefix -I$(PKGDIR)/,$(INTERNALS))
  F90INCSFLAGS += $(addprefix -I$(PKGDIR)/,$(INTERNALS))
endif

LDFLAGS += $(addprefix -L,$(addsuffix /lib,$(SASDIRS)))


#
# Variables to obtain dependencies
#

CXXDEPEND	= g++ -M $(CPPFLAGS) $(CXXFLAGS)
CDEPEND		= gcc  -M $(CPPFLAGS) $(CFLAGS)
F90DEPEND	= LANG=C $(SASBIN)/f90depend $(F90INCFLAGS) $(F90FLAGS)


#
# The default variables that are dump by running 'make infokey'
# Add further variables to get info on then
#

KEYS:=CFLAGS CPPFLAGS CXXFLAGS FFLAGS F90FLAGS LDFLAGS SHARED_LIBS_FLAGS
KEYVALS:=${foreach k,${KEYS},"${k}=${${k}}"}


#
# Define GCCVERS, MAJOR_GCCVERS and MINOR_GCCVERS
# These variables might be used in any package subdirectory Makefile
#

GCCVERS := $(word 3,$(shell gcc --version|grep GCC))
MAJOR_GCCVERS := $(shell gcc --version|grep GCC|awk '{print $$3}'|cut -d. -f1)
MINOR_GCCVERS := $(shell gcc --version|grep GCC|awk '{print $$3}'|cut -d. -f2)

export GCCVERS MAJOR_GCCVERS MINOR_GCCVERS


#
# R U L E S
#
#
# - P A T T E R N S
#

%.cc: %.l
	$(LEX) -t $< > $(<:.l=.cc)

%.cc: %.y
	$(YACC) -d -o $@ $(@:.cc=.y)
	mv "$(@:.cc=)".hh "$(@:.cc=)".h

%_main.o: %_main.cc
	$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) $<

%.o: %.cc
	$(CXX) -c $(CXXFLAGS) $(CXXSHAREDFLAGS) $(CPPFLAGS) $<

%.o: %.cpp
	$(CXX) -c $(CXXFLAGS) $(CXXSHAREDFLAGS) $(CPPFLAGS) $<

%.o: %.c
	$(CC) -c $(CFLAGS) $(CXXSHAREDFLAGS) $(CPPFLAGS) $<

m_%.cc m_%.cpp: %.h
	$(MOC) -o $@ $<

%.o: %.f90
	$(F90) -c $(F90FLAGS) $(F90INCFLAGS) $<

%.o: %.f95
	$(F90) -c $(F90FLAGS) $(F90INCFLAGS) $<

%.o : %.f
	$(FC) -c $(FFLAGS) $(FINCFLAGS) $<

%.prm: %.par
	$(SASBIN)/paramconv $*.par $@

#
# Cancel implicit rules for ".mod" (used by m2c)
#

%:   %.mod
%.o: %.mod

#
# Make a target here as well as in all subdirectories.
# The following complexity is because the Bourne shell's
# "for" function does not accept an empty list.
#

%: %.here
	@if [ -n "$(SUBDIRS)" ]; then \
	  ARGS="$(SUBDIRS)"; \
	  for n in $$ARGS; do $(MAKE) -C $$n $@ || exit; done; \
	fi

#
# Automatically generated source files.
#

# 
# The final perl tasks (without the .pl extension) are formed by 
# appending to the taskmain main.pl, the task themselves
# 
# SAS_PERL is defined above from the variable PERL passed by the configure
#

$(PERLTASKS): $(SAS_DIR)/packages/taskmain/src/main.pl
	T=$@ ;\
	PT=$(SAS_PERL);\
	sed "s?-sasperl-?$$PT?g;s/-taskname-/$$T/g; s/-release-/$(RELEASE)/g; s/-version-/$(VERSION)/g; s/-aka-/$(AKA)/g" $(SAS_DIR)/packages/taskmain/src/main.pl > $@ ;\
	cat $@.pl >> $@ ;\
	chmod +x $@

# Python based SAS tasks are built from their respective .py plus the main.py
# from taskmain. They do not need to set the she-bang to variable PYTHON as it is
# found from configure because we use the approach to set the she-bang via the
# /usr/bin/env shell built-in.

$(PYTHONTASKS): $(SAS_DIR)/packages/taskmain/src/main.py
	T=$@ ;\
	sed "s/-taskname-/$$T/g; s/-release-/$(RELEASE)/g; s/-version-/$(VERSION)/g; s/-aka-/$(AKA)/g" $(SAS_DIR)/packages/taskmain/src/main.py > $@ ;\
	cat $@.py >> $@ ;\
	chmod +x $@


# 
# The Fortran 95 c++ tasks are formed by appending to the taskmain  task_c.cc
# the tasks themselves
#

$(addsuffix _c.cc,$(FTASKS)): $(SAS_DIR)/packages/taskmain/src/task_c.cc
	T=$(subst _c.cc,,$@) ;\
	sed "s/taskname/$$T/g" $(SAS_DIR)/packages/taskmain/src/task_c.cc | sed "s/taskproc/$$T_mod_MP_$$T/g" > $@

#
# The C++ tasks are formed by appending to the taskmain task_f.cc
# the tasks themselves
#

$(addsuffix _f.cc,$(CXXTASKS)): $(SAS_DIR)/packages/taskmain/src/task_f.cc
	T=$(subst _f.cc,,$@) ;\
	sed "s/taskname/$$T/g" $(SAS_DIR)/packages/taskmain/src/task_f.cc | sed "s/taskproc/$$T_/g" > $@

#
# Creation of task headers
#

$(TASKHEADERS): $(SAS_DIR)/packages/taskmain/src/main.cc
	$(SASBIN)/sastaskhdr_gfortran  $(*F) $(VERSION) $(PACKAGE) $(RELEASE) > $@
	$(SASBIN)/sastaskhimp $(*F) $(VERSION) $(PACKAGE) $(RELEASE) > $(*F)_h_imp.cc


$(TASKMODS): $(SAS_DIR)/packages/taskmain/src/task_mod.f90
	T=$(subst _f_mod.f90,,$@) ;\
	sed "s/taskname/$$T/g" $(SAS_DIR)/packages/taskmain/src/task_mod.f90 > $@

$(TASKMAINS): $(SAS_DIR)/packages/taskmain/src/main.cc
	T=$(subst _main.cc,,$@) ;\
	sed "s/taskname/$$T/g" $(SAS_DIR)/packages/taskmain/src/main.cc | sed "s/VERSION/$(VERSION)/g; s/RELEASE/$(RELEASE)/g; s/PACKAGE/$(PACKAGE)/g" > $@


#
# Run the given test and report success or failure.
#

%_test: %
	@$(call echon,Testing $* ... )
	@$(SASBINDEV)/runtestwrap $* < /dev/null > test.result 2>&1 && \
	   ( $(ECHO) passed; $(RM) test.result ) || ( $(ECHO) FAILED; cat test.result )


#
# The PostScript target is _ps whereas a .ps.gz is made. This way the
# documentation is always remade with make doc. This is needed because
# there is no proper documentation dependency mechanism. The
# dependency assures that the toplevel document is automatically
# generated.  latex reads from /dev/null to prevent it from hanging if
# multiple errors are detected.  bibtex is run with a - because it
# generates an error if there is no citation in the document. This
# could be a bit more sophisticated, other errors are now also not
# caught.
#
# Note: See comments above where the variable PSTARGETS is set.
#

%_ps: %_tex
	latex $* < /dev/null > makedoc.log || ( cat makedoc.log ; exit 1 )
	-bibtex $* < /dev/null > makedoc.log
	latex $* < /dev/null > makedoc.log || ( cat makedoc.log ; exit 1 )
	latex $* < /dev/null > makedoc.log || ( cat makedoc.log ; exit 1 )
	dvips -o $*.ps $* > makedoc.log 2>&1 || ( cat makedoc.log ; exit 1 )
	gzip -f $*.ps



# The same target that generates the ps.gz produces the .pdf file as well.

%.ps.gz: %.tex
	latex $* < /dev/null > makedoc.log || ( cat makedoc.log ; exit 1 )
	-bibtex $* < /dev/null > makedoc.log
	latex $* < /dev/null > makedoc.log || ( cat makedoc.log ; exit 1 )
	latex $* < /dev/null > makedoc.log || ( cat makedoc.log ; exit 1 )
	dvips -o $*.ps $* > makedoc.log 2>&1 || ( cat makedoc.log ; exit 1 )
# replced exit 1 by continue here to avoid break before html files and specially labels.pl
# is produced, e.g. in cal, which is used by many other packages.
	dvipdf $* > makedoc.log 2>&1 || ( cat makedoc.log ; continue ) 
	gzip -f $*.ps

#
# Generate the toplevel LaTeX document that includes the package documentation.
# Use a dummy target so that the file is also created when it already existed.
#

%_tex: 
	sed -e "s/DOC/$*/" -e "s/TYPE/$(RELEASETYPE)/" < \
	$(SAS_DIR)/packages/sas/doc/lib/$(TEXFORM).tex | $(SASBIN)/texcombine | \
	$(SASBIN)/fixdoc -type=$(RELEASETYPE) $* $(VERSION) $(PACKAGE) $(RELEASE) > $*.tex

%.tex: %_description.tex $(SAS_DIR)/packages/sas/doc/lib/*.tex
	sed -e "s/DOC/$*/" -e "s/TYPE/$(RELEASETYPE)/" < \
	$(SAS_DIR)/packages/sas/doc/lib/$(TEXFORM).tex | $(SASBIN)/texcombine | \
	$(SASBIN)/fixdoc -type=$(RELEASETYPE) $* $(VERSION) $(PACKAGE) $(RELEASE) > $*.tex

#
# Provide the relative path to SAS_DIR to latex2html via an environment
# variable.
#
# Some versions of latex2html seem to forget a final
# '\n'. This breaks the grep '^Testing' checks, and reports a test
# failure. This happens only for packages that have one test.
#
# It should be:
#   latex2html output
#   Testing testname
#
# But it is:
#   latex2html outputTesting testname
#
# Forces the creation of the TeX file because that file is needed to 
# generate the HTML. 
#
# Modern versions of latex2html use pdflatex instead of latex plus dvi to generate images
# from those we want to include in the html document. However, pdflatex does not work.
# In order to keep the old system that used latex + dvi instead of pdflatex, we have
# included the switch -nouse_pdftex in the latex2html command.

%_html: %.tex $(PSTARGETS)
	SASRELDIR=$(RELATDIR) ;\
	export SASRELDIR ;\
	latex2html -nouse_pdftex -init_file $(SAS_DIR)/packages/sas/doc/lib/latex2html.init $* > /dev/null
	$(ECHO) ""
	mkpkgidx -t . > /dev/null || (rm -f $*/index.pl ; exit 1)
	pointer=$*/ChangeLog ; \
	target=$(RELATDIR)/packages/$(PACKAGE)/ChangeLog ; \
	if [ -f $$target -a \( ! -h $$pointer \) ] ; then \
	  $(LN_S) ../$$target $$pointer ; \
	fi

%_makedir:
	@if [ ! -d $* ]; then $(MKDIR) $*; fi




#
# T A R G E T S
#

# Targets that make an implicit clobber should not expect to write to
# files that will be deleted by the clobber.
# This explains the funny file suffixes, and the explicit use of $(RM)
# in some of the rules below.

# The @grep should be done before the make complete, as some complete
# steps require the build/check.txt files.


all:
	$(MAKE) build | tee build.tmp_
	@grep "[-+][-+]" build.tmp_ > build.txt
	$(RM) build.tmp_
	$(MAKE) complete
	$(SASBINDEV)/htmlReport build.txt 2 > build.html
	@if (`grep -- - build.txt > /dev/null`); then \
	  $(ECHO) "Build failed"; \
	  exit 1; \
	else \
	  $(ECHO) "Build succeeded"; \
	fi

incheck:
	@$(RM) *.tmp_
	@$(MAKE) runincheck | tee check.tmp_
	@grep "[-+][-+]" check.tmp_ > check.txt
	@$(RM) check.tmp_
	@$(MAKE) complete
	@$(SASBINDEV)/htmlReport check.txt 1 > check.html
	@if (`grep -- - check.txt > /dev/null`); then \
	  $(ECHO) "Check gave errors"; \
	  exit 1; \
	else \
	  $(ECHO) "Check succeeded"; \
	fi

check:
	@$(RM) *.tmp_
	@$(MAKE) runcheck | tee check.tmp_
	@grep "[-+][-+]" check.tmp_ > check.txt
	@$(RM) check.tmp_
	@$(MAKE) complete
	@$(SASBINDEV)/htmlReport check.txt > check.html
	@if (`grep -- - check.txt > /dev/null`); then \
	  $(ECHO) "Check gave errors"; \
	  exit 1; \
	else \
	  $(ECHO) "Check succeeded"; \
	fi

info:
	@echo --- Information on the selected variables -
	@echo 
	@echo Working directory=\"$(PWD)\"
	@echo REFERDIR=\"$(REFERDIR)\"
	@echo RELATDIR=\"$(RELATDIR)\"
	@echo FTASKS=\"$(FTASKS)\"
	@echo CXXTASKS=\"$(CXXTASKS)\"
	@echo PERLTASKS=\"$(PERLTASKS)\"
	@echo PYTHONTASKS=\"$(PYTHONTASKS)\"
	@echo LIBS=\"$(LIBS)\"
	@echo COMBILIBS=\"$(COMBILIBS)\"
	@echo LIBFILES=\"$(LIBFILES)\"
	@echo COMBILIBFILES=\"$(COMBILIBFILES)\"
	@echo TARGETS=\"$(TARGETS)\"
	@echo LINKS=\"$(LINKS)\"
	@echo CLOBBERFILES=\"$(CLOBBERFILES)\"
	@echo CLEANFILES=\"$(CLEANFILES)\"
	@echo CLOBBERDIRS=\"$(CLOBBERDIRS)\"
	@echo CLEANDIRS=\"$(CLEANDIRS)\"
	@echo LIBBASES=\"$(LIBBASES)\"
	@echo TASKS=\"$(TASKS)\"
	@echo NEEDTASKMAIN=\"$(NEEDTASKMAIN)\"
	@echo LIBDIR=\"$(LIBDIR)\"
	@echo LDLIBS=\"$(LDLIBS)\"
	@echo INTERFACES=\"$(INTERFACES)\"
	@echo USEDLIBS=\"$(USEDLIBS)\"
	@echo SHARED=\"$(SHARED)\"
	@echo RELEASE=\"$(RELEASE)\"
	@echo VERSION=\"$(VERSION)\"
	@echo MAJOR_VERSION=\"$(MAJOR_VERSION)\"
	@echo SO=\"$(SO)\"
	@echo SO_VERSION=\"$(SO_VERSION)\"
	@echo SO_FULL_EXT=\"$(SO_FULL_EXT)\"
	@echo PKGDIR=\"$(PKGDIR)\"
	@echo PACKAGE=\"$(PACKAGE)\"
	@echo OPTIMIZATION=\"$(OPTIMIZATION)\"
	@echo EXTPERLMODS=\"$(EXTPERLMODS)\"
	@echo EXTPELDIR=\"$(EXTPERLDIR)\"
	@echo EXTPERLSCRIPT=\"$(EXTPERLSCRIPT)\"


#
# Show key=val, for all keys specified by variable KEYS (see above)
#

infokey.here:
	@for n in ${KEYVALS} ; do echo "$$n" ; done

#
# To upgrade the parameter files
#

upgradeparfile.here:
	upgradeparam


#
# Provide an empty rule for complete. In the toplevel Makefile it will
# depend on some other rules so that operations are performed at the end
# of the build.

complete:

bin.here: $(TARGETS)

doc.here: $(DOCTARGETS)

ps.here: $(PSTARGETS)

html.here: $(HTMLTARGETS)

data.here:
	@if [ -n "$(DATASCRIPTS)" ]; then \
	  ARGS="$(DATASCRIPTS)"; \
	  for n in $$ARGS; do \
	    ./$$n; \
	  done; \
	fi

#
# Create directories and symbolic links. If INTERFACES is defined, delete old
# links in 'include' directory (which would prevent INTERFACES working properly).
#

links.here: make_dirs check_required_dirs $(LINKS) 
ifdef INTERFACES
	@if [ -n "$(strip $(BINS)$(LIBS)$(DEVBINS))" ]; then \
	ARGS="$(BINS) $(LIBS) $(DEVBINS)"; \
	cd $(INCDIR); \
	for n in $$ARGS; \
	do (test -h $$n && $(RM) $$n || true); done; \
	fi
endif

check_required_dirs:
	@result=0 ;\
	for d in $(LIBDIR) $(PERLLIBDIR) $(PYTHONLIBDIR) $(PYTHONLIBDISTSDIR) $(PYTHONLIBPYSASDIR) $(INCDIR) $(BINDIR) $(DEVBINDIR) $(CONFIGDIR) $(DOCDIR) $(DATADIR) $(DATADIRTMP) $(ODFDIR) ; do \
	  if [ ! -d $$d ] ; then\
	    echo WARNING $$d does not exist. ;\
	    result=1 ;\
	  fi ;\
	done ;\
	if [ $$result -ne 0 ] ; then \
	  echo ERROR: One of more required directories could not be found. This may prevent some of the symbolic links from being created correctly. This may also mean that you are in a directory that has nothing to do with the SAS, or that SAS_PATH is incorrectly configured. If you are in the right directory, you can create the missing directories by hand. Or type 'make required_dirs'. ;\
	  exit 1 ;\
	fi 

required_dirs:
	@for d in $(LIBDIR) $(PERLLIBDIR) $(PYTHONLIBDIR) $(PYTHONLIBDISTSDIR) $(PYTHONLIBPYSASDIR) $(INCDIR) $(BINDIR) $(DEVBINDIR) $(CONFIGDIR) $(DOCDIR) $(DATADIR) $(DATADIRTMP) $(ODFDIR) ; do \
	  if [ ! -d $$d ] ; then\
	    echo Creating $$d ;\
	    mkdir $$d || exit 1;\
	  fi \
	done ;\
	echo -n "Setting up Python environment ... " ;\
	$(SASBIN)/pyset.py ;\
	echo "done."


#
# Build the libraries with an empty VPATH, since otherwise make will
# try to overwrite the library in any of the directories in VPATH.
#

libs.here:
	@if [ -n "$(LIBFILES)" ]; then $(MAKE) VPATH= $(LIBFILES); fi

combilibs.here:
	@if [ -n "$(COMBILIBFILES)" ]; then $(MAKE) $(COMBILIBFILES); fi



#
# Soft links for VERSIONED shared libraries
# depending on the platform
#

ifeq ($(SO),$(SO_FULL_EXT))

# No versions
#
# libFOO.so -> PackageDir/libFOO.so
#

$(LIBDIR)/lib%.$(SO):
	@cd $(LIBDIR) && \
	  (test -h $(@F) || $(LN_S) ../$(REFERDIR)/$(@F) $(@F))
else

#
# Versioned libraries
#

#
# On Linux $(SO) = so
#
# We need two soft links in LIBDIR
#
# libFOO.so     -> libFOO.so.M.m
# libFOO.so.M.m -> YourPackageDir/libFOO.so.M.m
#

  ifeq (so,$(SO))

$(LIBDIR)/lib%.$(SO):
	@cd $(LIBDIR) && \
	  (test -h $(@F) || $(LN_S) $(@F).$(SO_VERSION) $(@F))

$(LIBDIR)/lib%.$(SO_FULL_EXT):
	@cd $(LIBDIR) && \
	  (test -h $(@F) || $(LN_S) ../$(REFERDIR)/$(@F) $(@F))  

  endif

# Mac OS X $(SO) = dylib 
#
# We need two soft links in LIBDIR
#
# libFOO.dylib     -> libFOO.M.m.dylib
# LibFOO.M.m.dylib -> YourPackageDir/libFOO.M.m.dylib
#
# But notice that lib%.$(SO) in LIBDIR matches both libFOO.M.n.dylib and 
# libFOO.dylib, so we need to reverse the order to find the two following targets
# otherwise the second target will never be done
# 

  ifeq (dylib,$(SO))

$(LIBDIR)/lib%.$(SO_FULL_EXT):
	@cd $(LIBDIR) && \
	  (test -h $(@F) || $(LN_S) ../$(REFERDIR)/$(@F) $(@F))  

$(LIBDIR)/lib%.$(SO):
	@cd $(LIBDIR) && \
	  (test -h $(@F) || $(LN_S) $(subst .dylib,,$(@F)).$(SO_VERSION).$(SO) $(@F))

  endif  

endif

#
# Links for static libraries
#

$(LIBDIR)/lib%.a:
	@(cd $(LIBDIR); test -h lib$*.a || $(LN_S) ../$(REFERDIR)/lib$*.a .)

#
# Links for perl modules close to the perl task
#

$(PERLLIBDIR)/%.pl:
	@(cd $(PERLLIBDIR); test -h $*.pl || $(LN_S) ../../$(REFERDIR)/$*.pl .)

#
# Links for python modules close to the python task

$(PYTHONLIBDIR)/%.py:
	@(cd $(PYTHONLIBDIR); test -h $*.py || $(LN_S) ../../$(REFERDIR)/$*.py .)


#
# Link to directory, when INTERFACES is not defined
#

$(INCDIR)/%\/:
	@(cd  $(INCDIR); test -h $* || $(LN_S) ../$(REFERDIR) $*)


#
# Link to individual files, when INTERFACES is defined
#

$(INCDIR)/%:
	@(cd  $(INCDIR); \
	test -h $(notdir $*) || $(LN_S) ../$(REFERDIR)/$(notdir $*) . )

$(DEVBINDIR)/%:
	@(cd  $(DEVBINDIR); test -h $* || $(LN_S) ../../$(REFERDIR)/$* .)

$(BINDIR)/%:
	@(cd  $(BINDIR); test -h $* || $(LN_S) ../$(REFERDIR)/$* .)

$(CONFIGDIR)/%.par:
	@(cd $(CONFIGDIR); test -h $*.par || $(LN_S) ../$(REFERDIR)/$*.par .)

$(CONFIGDIR)/%:
	@(cd $(CONFIGDIR); test -h $* || $(LN_S) ../$(REFERDIR)/$* .)


#
# test ! -r is needed as a compatibility measure for make files that have DOCS = a/a.html
#

$(DOCDIR)/%.html:
	@(cd $(DOCDIR); test -h $*.html  || test ! -r ../$(REFERDIR)/$*.html || $(LN_S) ../$(REFERDIR)/$*.html .)

$(DOCDIR)/%:
	@(cd $(DOCDIR); test -h $* || $(LN_S) ../$(REFERDIR)/$* .)

$(DATADIR)/%:
	@(cd $(DATADIR); test -h $* || $(LN_S) ../../$(REFERDIR)/$* .)

$(PERLLIBDIR)/%:
	@(cd $(PERLLIBDIR); test -h $* || $(LN_S) ../../$(REFERDIR)/$* .)

$(PYTHONLIBDIR)/%.py:
	@(cd $(PYTHONLIBDIR); test -h $*.py || $(LN_S) ../../$(REFERDIR)/$*.py .)

$(ODFDIR)/%:
	@(cd $(ODFDIR); test -h $* || $(LN_S) ../../$(REFERDIR)/$* .)

make_dirs: $(MKDIRS:=_makedir)


# 
# These rules should come after the rules to generate the links.
# Use the dependencies ($^) instead of $*_OBJS, since then we can add
# the wrappers for task libraries by adding them to the dependencies.
# The make depend stage determines the contents of libraries and executables.
#

#
# combilibs rules must come before the normal lib ones.
#
# filter-out is needed in case the library being built is also in the USEDLIBS line.
#

$(addprefix lib,$(addsuffix .a,$(COMBILIBS))):
	$(RM) -fr $(COMBIDIR)$@ && $(MKDIR) $(COMBIDIR)$@ && \
	cd $(COMBIDIR)$@ && \
	for l in $(subst .$(SO),.a,$^); do $(AR) x $$l ; done && \
	$(AR) cur $@ *.o && $(RANLIB) $@ && $(MV) $@ ..

$(addprefix lib,$(addsuffix .$(SO_FULL_EXT),$(COMBILIBS))):
	$(RM) -fr $(COMBIDIR)$@ && $(MKDIR) $(COMBIDIR)$@ && \
	cd $(COMBIDIR)$@ && \
	for l in $(subst .$(SO),.a,$^); do $(AR) x $$l ; done && \
	$(CXX) $(SHARED_LIBS_FLAGS) -o $@ *.o $(addprefix -l,$(filter-out $*,$(USEDLIBS))) $(LIBS_LDLIBS) && $(MV) $@ ..
	@test $@ = lib$*.$(SO) || ( test -h lib$*.$(SO) || $(LN_S) $@ lib$*.$(SO) )

lib%.a:
	$(AR) cur $@ $^
	$(RANLIB) $@

lib%.$(SO_FULL_EXT):
	$(CXX) $(SHARED_LIBS_FLAGS) -o $@ $^ $(addprefix -l,$(filter-out $*,$(USEDLIBS))) $(LIBS_LDLIBS)
	@test $@ = lib$*.$(SO) || ( test -h lib$*.$(SO) || $(LN_S) $@ lib$*.$(SO) )

#
# Compile an executable.
# Convert any library in the dependencies back to a -l option so that no
# absolute path to the library is linked into the executable.
#
# Here use $+ instead of $^ because we want to preserve duplicates and
# preserve their order. 
#

$(BINS) $(DEVBINS) $(TESTBINS) $(NEEDTASKMAIN):
	$(CXX) $(LDFLAGS) -o $@ $(shell $(SASBIN)/libtominl $+) $(LDLIBS)

#
# In the two following targets make sure that there is no trailing /.
# On RedHat 8.0 rm symlink/ fails (rm thinks it is a directory). But
# we use the final / as part of one of the pattern rules, so it cannot
# be removed there. So we get rid of it here before invoking rm.
#

clean.here:
	@$(RM) $(CLEANFILES:%\/=%)
	@$(RM) -r $(CLEANDIRS)

clobber.here:
	@$(RM) $(CLEANFILES:%\/=%) $(CLOBBERFILES:%\/=%)
	@$(RM) -r $(CLEANDIRS) $(CLOBBERDIRS)

tests.here: $(TESTBINS)


#
# Use an intermediate target to enforce doing the tests even if the subdir
# test exists.
#

test: dotest

#
# run all the tests in this and lower directories, bail out if one
# of them failed
#

dotest:
	@$(MAKE) runtests | tee test_log
	@grep FAILED test_log > /dev/null 2>&1 && $(ECHO) "ERROR: one of the tests failed" || exit 0

#
# Run all the tests, do not bail out on a failure. Serialize the tests; they
# should not run in parallel (some use the same output file).
#

runtests.here: $(TESTBINS) $(TESTS:=_test)

#
# Do everything that is needed before make depend can be done.
# make_dirs instead of $(MKDIRS) ensures that we can create directories with the
# same name as one of the targets (doc, test).
#

prepare.here: make_dirs $(TASKHEADERS) $(TASKHEADIMPS) $(CXXTASKWRAPPERS) $(TASKMODS) $(FTASKWRAPPERS) $(PERLTASKWRAPPERS) links.here



#
# Generation of dependencies.
#
# Its generation is serialized since they are written to the same file
# named Make.depends
#


depend.here: prepare.here
	@$(ECHO) "# Make.depends" > Make.depends
	@if [ -n "$(BINS)$(TESTBINS)$(DEVBINS)" ]; then \
	  ARGS="$(BINS) $(TESTBINS) $(DEVBINS)" ;\
	  for n in $$ARGS; do $(MAKE) $${n}_BDEPEND || exit; done; \
	fi
	@if [ -n "$(COMBILIBS)" ]; then \
	  ARGS="$(COMBILIBS)"; \
	  for n in $$ARGS; do $(MAKE) $${n}_CLDEPEND || exit; done; \
	fi
	@if [ -n "$(CXXTASKS)" ]; then \
	  ARGS="$(CXXTASKS)"; \
	  for n in $$ARGS; do $(MAKE) $${n}_TCDEPEND || exit; done; \
	fi
	@if [ -n "$(PERLTASKS)" ]; then \
	  ARGS="$(PERLTASKS)"; \
	  for n in $$ARGS; do $(MAKE) $${n}_TPDEPEND || exit; done; \
	fi
	@if [ -n "$(PYTHONTASKS)" ]; then \
	  ARGS="$(PYTHONTASKS)"; \
	  for n in $$ARGS; do $(MAKE) $${n}_TPYDEPEND || exit; done; \
	fi
	@if [ -n "$(FTASKS)" ]; then \
	  ARGS="$(FTASKS)"; \
	  for n in $$ARGS; do $(MAKE) $${n}_TFDEPEND || exit; done; \
	fi
	@if [ -n "$(LIBS)" ]; then \
	  ARGS="$(LIBS)"; \
	  for n in $$ARGS; do $(MAKE) $${n}_LDEPEND || exit; done; \
	fi
	@if [ -n "$(wildcard *.f90)" ]; then \
	   $(F90DEPEND) *.f90 >> Make.depends; \
	fi
	@if [ -n "$(wildcard *.f95)" ]; then \
	   $(F90DEPEND) *.f95 >> Make.depends; \
	fi
	@if [ -n "$(wildcard *.c)" ]; then \
	   $(CDEPEND) *.c >> Make.depends; \
	fi
	@if [ -n "$(wildcard *.cc)" ]; then \
	   $(CXXDEPEND) *.cc >> Make.depends; \
	fi

%_BDEPEND:
	@echo Dependencies for $*
	@if [ -z "$($*_OBJS)" -a -z "$($*_QOBJS)" ]; then $(ECHO) Missing $*_OBJS or $*_QOBJS for binary $*; exit 1; fi
	@$(ECHO) "$*: $(addsuffix .o,$($*_OBJS))" >> Make.depends
	@$(ECHO) "$*: $(addsuffix .o,$($*_QOBJS)) $(addprefix m_,$(addsuffix .o,$($*_QOBJS)))" >> Make.depends
	@$(ECHO) "$*: $(addprefix -l,$(USEDLIBS))" >> Make.depends

%_CLDEPEND:
	@echo Dependencies for $*
	@if [ -z "$($*_LIBS)" ]; then $(ECHO) Missing $*_LIBS for combilib $*; exit 1; fi
	@$(ECHO) "lib$*.a lib$*.$(SO_FULL_EXT): $(addprefix -l,$($*_LIBS))" >> Make.depends

%_TFDEPEND:
	@echo Dependencies for $*
	@if [ -z "$($*_OBJS)" ]; then $(ECHO) Missing $*_OBJS for Fortran task $*; exit 1; fi
	@$(ECHO) "$*: $*_main.o -l$*" >> Make.depends
	@$(ECHO) "$*_c.o: $*_c.cc $*.h" >> Make.depends
	@$(ECHO) "$*_h_imp.o: $*_h_imp.cc $*.h" >> Make.depends
	@$(ECHO) "lib$*.a lib$*.$(SO_FULL_EXT): $*_h_imp.o $*_c.o $(addsuffix .o,$($*_OBJS))" >> Make.depends
	@$(ECHO) "lib$*.a lib$*.$(SO_FULL_EXT): $(addsuffix .o,$($*_QOBJS)) $(addprefix m_,$(addsuffix .o,$($*_QOBJS)))" >> Make.depends
	@$(ECHO) "$*: $(addprefix -l,$(USEDLIBS))" >> Make.depends

%_TCDEPEND:
	@echo Dependencies for $*
	@if [ -z "$($*_OBJS)" -a -z "$($*_QOBJS)" ]; then $(ECHO) Missing $*_OBJS or $*_QOBJS for C++ task $*; exit 1; fi
	@$(ECHO) "$*: $*_main.o -l$*" >> Make.depends
	@$(ECHO) "$*_h_imp.o: $*_h_imp.cc $*.h" >> Make.depends
	@$(ECHO) "lib$*.a lib$*.$(SO_FULL_EXT): $*_h_imp.o $*_f_mod.o $*_f.o $(addsuffix .o,$($*_OBJS))" >> Make.depends
	@$(ECHO) "lib$*.a lib$*.$(SO_FULL_EXT): $(addsuffix .o,$($*_QOBJS)) $(addprefix m_,$(addsuffix .o,$($*_QOBJS)))" >> Make.depends
	@$(ECHO) "$*: $(addprefix -l,$(USEDLIBS))" >> Make.depends

%_TPDEPEND:
	@echo Dependencies for $*
	@$(ECHO) "$*: $*.pl $(SAS_DIR)/packages/taskmain/src/main.pl" >> Make.depends

%_TPYDEPEND:
	@echo Dependencies for $*
	@$(ECHO) "$*: $*.py $(SAS_DIR)/packages/taskmain/src/main.py" >> Make.depends

%_LDEPEND:
	@echo Dependencies for $*
	@if [ -z "$($*_OBJS)" -a  -z "$($*_QOBJS)" ]; then $(ECHO) Missing $*_OBJS or $*_QOBJS for library $*; exit 1; fi
	@$(ECHO) "lib$*.a lib$*.$(SO_FULL_EXT): $(addsuffix .o,$($*_OBJS))" >> Make.depends
	@$(ECHO) "lib$*.a lib$*.$(SO_FULL_EXT): $(addsuffix .o,$($*_QOBJS)) $(addprefix m_,$(addsuffix .o,$($*_QOBJS)))" >> Make.depends


#
# Target to generate a package in the form package-version.tgz, as well as checking/tagging the local git repo if present
#
dist:
	@$(RM) *.tmp_
	@$(SASBIN)/chkdist || exit 1
	@if [ ! -r VERSION ] ; then exit ; fi
	@if [ -d ../../.git ]; then \
	   echo Tagging $(PACKAGE)-$(VERSION) in the local git repository; \
	   git tag $(PACKAGE)-$(VERSION) || \
	   (echo "If tag already exists, and this is an error, remove it with 'git tag -d $(PACKAGE)-$(VERSION)' and try again." && exit 1); \
	 fi
	@( cd ..; find $(PACKAGE) | grep CVS > tmp%; tar cfX - tmp% $(PACKAGE) | gzip > $(PACKAGE)-$(VERSION).tgz; rm tmp% ; echo The distribution can be found in ../$(PACKAGE)-$(VERSION).tgz )


#
# Target to make external perl modules required by a perl task.
#
# This is controlled by means of the EXTPERLMODS variable which 
# provides the list of external perl modules.
#
# They must be placed in a subdirectory of the top direcctory
# of the package defined in variable EXTPERLDIR.
# 
# The modules are built by means of a specific shell script 
# which is identified by means of the variable EXTPERLSCRIPT.
#

.PHONY: extperlmods
extperlmods:
# If EXTPERLMODS is not null, checks for EXTPERLDIR and EXTPERLSCRIPT
ifneq ($(EXTPERLMODS),)
  ifeq ($(EXTPERLDIR),)
        @$(ECHO) Undefined EXTPERLDIR variable in $(shell basename $(PWD))/Makefile
        exit 1
  endif
  ifeq ($(EXTPERLSCRIPT),)
        @$(ECHO) Undefined EXTPERLSCRIPT variable in $(shell basename $(PWD))/Makefile
        exit 1
  endif
  ifeq ($(EXTPERLDIR),$(shell basename $(PWD)))
	@(/bin/bash ./$(EXTPERLSCRIPT))
  endif
endif



#
# Target to provide a mechanism of package uploading, as well as
# pushing changes from a local git repo to the main repo.
#
# This target depends on commit in case anything else needs to be
# committed.
#
# We do a git check first as part of the "dist" target, so that if it
# fails for some reason it needs to be resolved before the package
# upload.  Note that before we can push the changes to the main
# repository, we first need to do a "git pull". In case there are
# changes to other unrelated packages, we do a "git stash" before the
# pull followed by "git stash pop" after the push to revert those
# changes. However, if the "git pull" brought in some changes to one
# of these locally changed packages, you may get a merge conflict that
# needs to be resolved when the stash is re-applied. The
# re-application of the stash will not be fatal so that uploadsas may
# continue. Go and fix the files that "git stash pop" complained
# about, and then run "git stash drop" to remove the broken stash from
# the internal stack. Of course, the initial "git pull" may also
# reveal conflicts if two developers are working on the same package
# at the same time. This conflict will be fatal, requiring a
# resolution before things can continue.
#
# Use SASBIN instead of SASBINDEV so one can upload package sas itself
#

upload: commit dist
	@if [ -d ../../.git ]; then \
	   branch=`git rev-parse --abbrev-ref HEAD`; \
	   if [ "$$branch" != "master" ]; then \
	     echo "Error: working copy of git repository is on branch $$branch instead of master!"; \
	     exit 1; \
	   fi; \
	   istagged=`git show-ref $(PACKAGE)-$(VERSION)`; \
	   if [ -z "$$istagged" ]; then \
	     echo "ERROR: somehow $(PACKAGE)-$(VERSION) was not tagged during make dist"; \
	     exit 1; \
	   fi; \
	   echo ; \
	   echo "*** Pushing package changes to the main git repository ***"; \
	   echo ; \
	   pkg=`basename $$PWD`; \
	   pkgversion=`cat VERSION`;\
	   needstash=`git status --porcelain -uno | grep -v "\/$$pkg\/"`; \
	   if [ -n "$$needstash" ]; then \
	     echo " - Stash unrelated changes -"; \
	     git stash save "Stashed to upload $$pkg-$$pkgversion" || exit 1; \
	   fi; \
	   echo " - Pull changes from remote -"; \
	   git pull || exit 1; \
	   echo " - Push our updates to remote -"; \
	   git push || exit 1; \
	   echo " - Push tags to remote -"; \
	   git push --tags || exit 1; \
	   if [ -n "$$needstash" ]; then \
	     echo " - Pop stashed changes -"; \
	     git stash pop || ( echo "git stash pop failed. Please review your git status" ; exit 1) \
	   fi; \
	 fi

	@$(SASBIN)/uploadsas ../$(PACKAGE)-$(VERSION).tgz

#
# Target to provide a mechanism to commit to the git repo.
#
# Since moving to git from CVS, the main difference is that changes
# are only committed to the local repository. The synchronization with
# the remote master is part of the "upload" target. Tagging is now
# part of the "dist" target.
#
# Commits are made to the local master branch. By default only modified
# files in the current package are committed. Files that weren't previously
# in the index need to be added with "git add".

commit:
	@if [ ! -d ../../.git ]; then \
	  echo Not a git repo, nothing to do. ; \
	else \
	  branch=`git rev-parse --abbrev-ref HEAD` ; \
	  if [ "$$branch" != "master" ]; then \
	    echo "ERROR: currently working on branch $$branch. Fix this." ;\
	    echo "ERROR: Switch back to master and merge if needed:" ;\
	    echo "ERROR:   $$ git checkout master; git merge $$branch" ;\
	    exit 1 ; \
	  fi ; \
	  untracked=`git ls-files --others --exclude-standard .` ; \
	  if [ "$$untracked" != "" ]; then \
	    echo "ERROR: package contains untracked files: ";\
	    echo "$$untracked" ;\
	    echo "ERROR: Fix this using: ";\
	    echo "ERROR:   $$ git add [all new files/directories]" ;\
	    echo "ERROR: or delete them (e.g., make clobber) ";\
	    exit 1 ; \
	  fi ; \
	  docommits=`git status --porcelain .` ; \
	  if [ "$$docommits" != "" ]; then \
	    echo "Going to commit your changes ..."; \
	    pkg=`basename $$PWD` ; \
	    git add -u .; \
            pkgversion=`cat VERSION`; \
	    git commit -m "$$pkg-$$pkgversion: Committed through make" || exit 1; \
	  else \
	    echo "No changes to commit." ; \
	  fi; \
	fi



#
# Deprecated: old target to generate a branch in CVS
#

branch:
	@echo '--- DEPRECATED ---'
	@echo 'The branch target is no longer used since moving to git from cvs.'

#
# A target to see the list of packages to be built
#

pkglist:
	@$(ECHO) $(PKGLIST)





#
# The following targets share a number of functions
#

OK := +
ERR := -

buildlog  := build_log
buildlog2 := $(buildlog)_second

check_head 		= echo [depchk][chkdist][mkdep][bin][fulldoc][mktests][hastests][tests][retests]
incheck_head 		= echo [depchk][chkdist][mkdep][bin][psdoc][mktests][hastests][tests][retests]
build_head		= echo [depchk][chkdist][mkdep][bin][fulldoc]
date_stamp		= $(call echon,"$(PACKAGE) $(VERSION) `date +%H:%M` ")
dependency_check 	= $(SASBIN)/depchk          1>  $(buildlog) 2>&1 && $(call echon,$(OK))  || $(call echon,$(ERR))
distribution_check	= $(SASBIN)/chkdist $(1)    1>> $(buildlog) 2>&1 && $(call echon,$(OK))  || $(call echon,$(ERR))
make_depend		= $(MAKE) depend            1>> $(buildlog) 2>&1 && $(call echon,$(OK))  || $(call echon,$(ERR))
make_bin		= $(MAKE) bin               1>> $(buildlog) 2>&1 && $(call echon,$(OK))  || $(call echon,$(ERR))
make_ps			= $(MAKE) ps                1>> $(buildlog) 2>&1 && $(call echon,$(OK))  || $(call echon,$(ERR))
make_tests		= $(MAKE) tests             1>> $(buildlog) 2>&1 && $(call echon,$(OK))  || $(call echon,$(ERR))
make_doc		= $(MAKE) doc               1>> $(buildlog) 2>&1 && $(call echon,$(OK))  || $(call echon,$(ERR))
make_test_g		= $(MAKE) test              1>> $(1) 2>&1 
make_test		= $(call make_test_g,$(buildlog))
make_second_test	= $(call make_test_g,$(buildlog2))
make_clean		= $(MAKE) clean             1>> $(buildlog) 2>&1
make_clobber		= $(MAKE) clobber           1>> $(buildlog) 2>&1
has_tests		= grep '^Testing' $(buildlog) > /dev/null 2>&1 && $(call echon,$(OK))  || $(call echon,$(ERR))
has_failed_tests_g	= grep FAILED $(1)            > /dev/null 2>&1 && $(call echon,$(ERR)) || $(call echon,$(OK))
has_failed_tests	= $(call has_failed_tests_g,$(buildlog))
has_failed_second_tests	= $(call has_failed_tests_g,$(buildlog2))
second_test		= if [ -r $(SAS_DIR)/second.test ] ; then   . $(SAS_DIR)/second.test 1>> $(buildlog) 2>&1 ; $(RM) -f $(buildlog2) ;\
				$(call make_second_test) ; $(call has_failed_second_tests) ; else echo X ; fi



#
# Target to produce incremental builds where no clean or clobber is made.
#

runincheck.here:
	@if [ -r DEPEND -a -r VERSION ] ; then \
	  $(call incheck_head) ;\
	  $(call date_stamp) ;\
	  $(call dependency_check) ;\
	  $(call distribution_check,inc) ;\
	  $(call make_depend) ;\
	  $(call make_bin) ;\
	  if [ $(FULLDOC) = "yes" ] ; then \
	    $(call make_doc) ;\
	  else \
	    $(call make_ps) ;\
	  fi ;\
	  $(call make_tests) ;\
	  if [ $(RUNTESTS) = "yes" ] ; then \
	    $(call make_test) ;\
	    $(call has_tests) ;\
	    $(call has_failed_tests) ;\
	    $(call second_test) ;\
	  else \
	    echo "XXX" ;\
	  fi \
	else \
	  $(MAKE) make_dirs links.here ;\
	  touch Make.depends ;\
	fi
	@echo


#
# The standard check target to build each package
#

runcheck.here:
	@if [ -r DEPEND -a -r VERSION ] ; then \
	  $(call check_head) ;\
	  $(call date_stamp) ;\
	  $(call make_clobber) ;\
	  $(call dependency_check) ;\
	  $(call distribution_check) ;\
	  $(call make_depend) ;\
	  $(call make_bin) ;\
	  $(call make_doc) ;\
	  $(call make_tests) ;\
	  $(call make_test) ;\
	  $(call has_tests) ;\
	  $(call has_failed_tests) ;\
	  $(call second_test) ;\
	  $(call make_clean) ;\
	else \
	  $(MAKE) make_dirs links.here ;\
	  touch Make.depends ;\
	fi
	@echo


#
# Build without tests
#

build.here:
	@if [ -r DEPEND -a -r VERSION ] ; then \
	  $(call build_head) ;\
	  $(call date_stamp) ;\
	  $(call make_clobber) ;\
	  $(call dependency_check) ;\
	  $(call distribution_check) ;\
	  $(call make_depend) ;\
	  $(call make_bin) ;\
	  $(call make_doc) ;\
	  $(call make_clean) ;\
	else \
	  $(MAKE) make_dirs links.here ;\
	  touch Make.depends ;\
	fi
	@echo


#
# Target to check every package
#

distcheck.here:
	@if [ -r DEPEND -a -r VERSION ] ; then \
	  $(SASBIN)/chkdist ;\
	else \
	  $(ECHO) You can do this only in the top-level package directory ;\
	fi

#
# Target to check cross package dependencies
#

depcheck.here:
	@if [ -r DEPEND -a -r VERSION ] ; then \
	  $(SASBIN)/depchk ;\
	else \
	  $(ECHO) You can do this only in the top-level package directory ;\
	fi


#
# Target to ensure Make.depends is included
#

ifeq ("$(wildcard Make.depends)","")
bin tests test:
	@$(ECHO) Missing Make.depends - first do \'make depend\'
	@exit 1
else
include Make.depends
endif

#
# After all is done, check some things and replace some
# rules with error messages if something is wrong.
#
# Checks whether SAS_DIR and SAS_PATH are OK and config.h has been
# produced.
#

ifeq ("$(SAS_DIR)","")
depend bin tests test doc all check incheck:
	@$(ECHO) "SAS_DIR is undefined. First source sas-setup.[c]sh"
	@exit 1
else
ifeq ("$(SASDIRS)","")
depend bin tests test doc all check incheck:
	@$(ECHO) "SAS_PATH is not defined. First source sas-setup.[c]sh"
	@exit 1
else
ifeq ("$(TOPDIR)","")
depend bin tests test doc all check incheck:
	@$(ECHO) "The current directory is not a subdirectory of SAS_PATH."
	@$(ECHO) "You should first source sas-setup.[c]sh. If you already did so,"
	@$(ECHO) "then set SAS_PATH to include all paths that contain SAS packages"
	@$(ECHO) "and source sas-setup.[c]sh again."
	@$(ECHO) "  pwd=$(PWD)"
	@$(ECHO) "  SAS_DIR=$(SAS_DIR)"
	@$(ECHO) "  SAS_PATH=$(SAS_PATH)"
	@exit 1
else
ifeq ("$(wildcard $(SAS_DIR)/config.h)","")
depend bin tests test doc all check incheck:
	@$(ECHO) Missing config.h - first run ./configure in $$SAS_DIR
	@exit 1
endif
endif
endif
endif