#  Copyright (c) 1997-2009
#  Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Darmstadt, Germany)
#  http://www.polymake.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 2, or (at your option) any
#  later version: http://www.gnu.org/licenses/gpl.txt.
#
#  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.
#-------------------------------------------------------------------------------
#  $Project: polymake $$Id: build.make 9363 2009-10-18 11:41:26Z gawrilow $

.PHONY: all do_all all-clients all-lib clean install install-src

### provide 'all' be a default target
all : all-lib ;

include ${ProjectTop}/support/utils.make

### locate ourselves
ifndef AppName
  .external := $(findstring /external/, ${CURDIR})
  ifndef .external
    ifneq ($(findstring /apps/, ${CURDIR}),)
      AppName := $(notdir ${CURDIR})
      ifeq (${ExtensionTop}${AppTop},)
        BeFirst := ${AppName}
      endif
    endif
  endif
endif

ProjectTop := $(call _abs_path,${ProjectTop})
ifndef AppTop
  AppTop := ${ProjectTop}
endif

Includes :=
IncludesXX :=
ifndef .external
  ### everything in C++ needs the core libraries
  IncludesXX := $(addprefix ${ProjectTop}/, lib/PTL/include lib/PTL/include/std)
endif

Libs := -lgmp ${Libs}

### compiler options depending on the chosen debugging features
suffix:=

ifeq (${Debug},)
  doOPT:=y
  CXXflags += -DALL_PLAUSIBLE_CHECKS=0
else ifeq (${Debug},profile)
  suffix:=-p
  doOPT:=y
  Cflags += -pg
  CXXflags += -pg -DALL_PLAUSIBLE_CHECKS=0
  LDflags += -pg
  Libs := $(subst -lgmp,-lgmp_p,${Libs})
  ifeq (${Profile},detailed)
    CXXflags += -fno-inline -fno-default-inline
    LDflags += -Wl,-z,muldefs
  endif
else
  suffix:=-d
  Cflags += ${CXXDEBUG}
  CXXflags += ${CXXDEBUG} $(if $(filter n N,${POLY_DEBUG}),,-DPOLY_DEBUG)
  LDflagsDebug += ${CXXDEBUG}
  check := 1
  ifneq ($(findstring opt,${Debug}),)
    doOPT:=y
    suffix:=${suffix}$(patsubst -%,%,${CXXOPT})
    check := 0
  endif
  CXXflags += -DALL_PLAUSIBLE_CHECKS=${check}
endif
O := ${suffix}.o
S := ${suffix}.${SO}
A := ${suffix}.a
export Profile

### locate the sources
ifndef SourceDir
  ifeq (${AppName},lib)
    ### building the core library
    SourceDir := $(wildcard ${ProjectTop}/lib/PTL/src)
  else ifdef .external
    SourceDir := $(wildcard ${ProjectTop}/ext_lib/$(notdir ${CURDIR}))
  else ifdef ExtensionTop
    SourceDir := $(wildcard ${ExtensionTop}/apps/${AppName}/src)
  else
    SourceDir := $(wildcard ${AppTop}/apps/${AppName}/src)
  endif
endif

ifeq "${COMOversion}${ICCversion}${GCCversion}" ""
  $(error unknown C++ compiler)
endif

ifdef COMOversion
  addinclude = -I$(patsubst %/,%,$(dir $(1))) --preinclude $(notdir $(1))
  make_dep_opt := -MD --no_preproc_only
  make_dep = ${make_dep_opt} >$(patsubst %$O,%.d,$@)
  define _cleanup_ti
	[ ! -f $(1) ] || { sed -e '/^cmd:/ s/${make_dep_opt}//' $(1) >$(1).clean && ${MV} $(1).clean $(1); }

  endef
endif

ifdef ICCversion
  addinclude = -I$(patsubst %/,%,$(dir $(1))) -include $(notdir $(1))
else ifdef GCCversion
  addinclude = -include $(1)
endif
ifndef make_dep
  ifdef CCache
    ifeq "$(filter CCACHE_DISABLE,$(shell echo $${!CCACHE_DISABLE*}))" "CCACHE_DISABLE"
      CCache :=
    endif
  endif
  ifdef CCache
    make_dep = -MD -MF $(@:.o=.d) $(patsubst %,-MT '%',$(filter-out $@,${lib_dep_target}) $@)
  else
    make_dep = -MD $(patsubst %,-MT '%',${lib_dep_target})
  endif
endif

_list_includes = $(wildcard $(1)/include/perl/bindings $(1)/include)
_includes_for_app = $(foreach t,${ExtensionTop} ${ImportExts} ${AppTop}, $(call _list_includes,$t/apps/$(1)))

### load per-client or per-application settings
ifeq (${AppName},lib)
  SharedModules := $(basename $(call _list_CXX_sources,${SourceDir}) $(call _list_CXX_sources,${SourceDir},perl))
  OwnShared := poly$S

else  # ! core lib
  ifdef ExtensionTop
    ExtensionConf := $(wildcard ${BuildDir}/conf.make)
    ifdef ExtensionConf
      include ${ExtensionConf}
    endif
  endif
  -include ${SourceDir}/Makefile.inc

  ifeq (${SharedModules},ALL)
    SharedModules :=
  endif
  ifeq (${SharedModules},)
    broken := $(notdir $(call _get_no_export,${SourceDir},broken))
    SharedModules := $(basename $(filter-out ${broken}, $(call _list_CXX_sources,${SourceDir})))
  else
    SharedModules := $(basename $(notdir $(wildcard $(foreach s,${CXX_suffixes}, $(patsubst %, ${SourceDir}/%.$s, ${SharedModules})))))
  endif
  ifneq ($(wildcard ${SourceDir}/perl),)
    SharedModules += $(filter-out perl/wrap-%, $(basename $(call _list_CXX_sources,${SourceDir},perl)))
  endif

  IncludesXX := $(foreach a,${AppName} ${ImportApps}, $(call _includes_for_app,$a)) ${IncludesXX}

  ### check for own library
  ifneq ($(strip ${SharedModules}),)
    OwnShared := ${BuildDir}/lib/${AppName}$S
  endif
endif  # ! core lib

LibObjects    := $(addsuffix $O, ${LibModules})
SharedObjects := $(addsuffix $O, ${SharedModules})
OwnLibs := $(addsuffix $A, ${OwnLibraries})
${LibObjects} ${SharedObjects} : LibCXXFLAGS := ${CsharedFlags} $(if ${COMOversion},-tused)
${LibObjects} ${SharedObjects} : LibCFLAGS := ${CsharedFlags}
ifneq (${AppName},lib)
  ifdef SharedObjects
    ifdef ExtensionConf
      # recompile everything if the extension was reconfigured
      ${SharedObjects} : ${ExtensionConf}
    endif

    WithWrappers.cc  := $(patsubst wrap-%,%$O,$(basename $(notdir $(wildcard ${SourceDir}/perl/wrap-*.cc))))
    WithWrappers.C   := $(patsubst wrap-%,%$O,$(basename $(notdir $(wildcard ${SourceDir}/perl/wrap-*.C))))
    WithWrappers.cpp := $(patsubst wrap-%,%$O,$(basename $(notdir $(wildcard ${SourceDir}/perl/wrap-*.cpp))))
    ${WithWrappers.cc}  : %$O : ${SourceDir}/perl/wrap-%.cc
    ${WithWrappers.C}   : %$O : ${SourceDir}/perl/wrap-%.C
    ${WithWrappers.cpp} : %$O : ${SourceDir}/perl/wrap-%.cpp
    ${WithWrappers.cc} ${WithWrappers.C} ${WithWrappers.cpp} : addWrapper = ${SourceDir}/perl/wrap-$(notdir $<)

    # ignore deleted wrappers in dependences
    ${SourceDir}/perl/wrap-%.cc ${SourceDir}/perl/wrap-%.C ${SourceDir}/perl/wrap-%.cpp :
	@echo wrapper file $@ mentioned in .dependences does not exist - ignored
  endif
endif

### put all include directories together
Cflags := $(addprefix -I, ${Includes}) ${Cflags}
CXXflags := $(addprefix -I, ${IncludesXX}) ${CXXflags}

### append the user-specified values
override CFLAGS += ${Cflags}
override CXXFLAGS += ${CXXflags}
override LDFLAGS += ${LDflags} ${LDflagsDebug}
override LIBS += ${Libs}

### determine the libraries to be built and/or linked with
ifndef .external
  ifdef OnlyModules
    BeFirst :=
  endif
  ifdef BeFirst
    define  _MakeCoreLib
      $(MAKE) --print-directory -C ${BuildDir}/lib AppName=lib BeFirst= Debug=${Debug} $(1)

    endef
  endif

  ifdef ExternalLibs
    define _MakeExternalLib
      $(MAKE) --print-directory -C ${BuildDir}/external/$(1) Debug=${Debug} AppName= $(2)

    endef
    define _MakeExternal
      $(foreach x,${ExternalLibs},$(call _MakeExternalLib,$x,$(1)))
    endef
  endif
endif

ifndef _MakeCoreLib
  _MakeCoreLib := : ;
endif
ifndef _MakeExternal
  _MakeExternal := : ;
endif

_build_core_lib:
	+@$(call _MakeCoreLib,all-lib)

.PHONY: all-own-lib

ifdef ExternalLibs
  all-own-lib ::
	+@$(call _MakeExternal,all-lib)
endif

ifdef OwnLibraries
  .PHONY: ${OwnLibraries}

  ifeq ($(words ${OwnLibraries}),1)
    .PRECIOUS: ${LibObjects}

    .INTERMEDIATE: ${LibObjects}

    ${OwnLibraries} : % : %$A(${LibObjects})
	@NewObjects=`for o in $?; do [ -f $$o ] && echo $$o; done`; \
	[ -z "$$NewObjects" ] || { \
	  set -x; \
	  ${AR} -rc $@$A $$NewObjects; \
	  rm $$NewObjects; \
	  ${RANLIB} $@$A; \
	}

    (%.o) : %.o ;

    ${OwnLibraries} : lib_dep_target = ${OwnLibs}($@)
  endif

  all-own-lib ::
	+@$(foreach l,${OwnLibraries},$(MAKE) --no-print-directory $l OwnLibraries=$l Debug=${Debug};)
endif

ifdef OwnShared
  all-own-lib ::
	+@$(MAKE) --no-print-directory ${OwnShared}

  CCLD := ${CXX}

  ${OwnShared} : $(if ${OnlyModules}, $(filter $(addsuffix $O,${OnlyModules}), ${SharedObjects}), ${SharedObjects})
	${CCLD} ${LDsharedFlags} -o $@ ${SharedObjects} ${LDFLAGS} ${LIBS}
endif

all-lib: $(if ${BeFirst},_build_core_lib) $(if ${OwnLibraries}${OwnShared},all-own-lib)

### compilation rules
define _do_deps
	$(call _process_d,$(@:.o=.d))

endef
ifdef COMOversion
  _do_deps += $(if $(filter %.c,$<),,$(call _cleanup_ti,$(@:.o=.ti)))
endif

define _C_compile
	${CC} -c -o $@ ${ExtraCFLAGS} ${LibCFLAGS} ${CFLAGS} $(if ${doOPT},${CXXOPT}) $(make_dep) $<

endef
define _CXX_compile
	${CXX} -c -o $@ ${ExtraCXXFLAGS} ${LibCXXFLAGS} ${CXXFLAGS} $(if ${doOPT},${CXXOPT}) $(make_dep) \
	       $(if ${addWrapper}, $(call addinclude,$<) ${addWrapper}, $<)

endef

%$O : %.cc
	$(_CXX_compile)
	@$(_do_deps)
%$O : %.C
	$(_CXX_compile)
	@$(_do_deps)
%$O : %.cpp
	$(_CXX_compile)
	@$(_do_deps)
%$O : %.c
	$(_C_compile)
	@$(_do_deps)

vpath %.cc ${SourceDir}
vpath %.C ${SourceDir}
vpath %.cpp ${SourceDir}
vpath %.c ${SourceDir}

### update dependence list
ifeq "${ProcessDep}" "none"
  make_dep :=
  _do_deps :=

else
  _replace_known_paths := -e 's:${ProjectTop}:$${ProjectTop}:g' \
			  $(if ${ExtensionTop}, -e 's:${ExtensionTop}:$${ExtensionTop}:g') \
			  $(if $(filter-out ${ProjectTop},${AppTop}), -e 's:${AppTop}:$${AppTop}:g')

ifdef COMOversion
  _process_d = sed -e '1 s|^$*\.o:|${lib_dep_target} $(1:.d=.o):|' \
		   -e '2,$$ s/^[^ 	]*://' \
		   -e '$$! s/$$/ \\/' \
		   -e 's:/usr/include/[^ 	]*[ 	]::g' \
		   -e 's:/[^ 	]*/lib/gcc/[^ 	]*/include/[^ 	]*[ 	]::g' \
		   -e 's:/[^ 	]*/gcc-lib/[^ 	]*/include/[^ 	]*[ 	]::g' \
		   -e 's:/[^ 	]*/libcomo[^ 	]*[ 	]::g' \
		   ${_replace_known_paths} \
		   -e '/^[ 	]*\\$$/ d' $*.d >$(@:.o=.dep) \
	       && rm $*.d
else
  _process_d = sed -e 's:/usr/include/[^ 	]*[ 	]::g' \
		   -e 's:/[^ 	]*/lib/gcc/[^ 	]*/include/[^ 	]*[ 	]::g' \
		   -e 's:/[^ 	]*/gcc-lib/[^ 	]*/include/[^ 	]*[ 	]::g' \
		   ${_replace_known_paths} \
		   -e '/^[ 	]*\\$$/ d' $(1) >$(@:.o=.dep) \
	       && rm $(1)
endif

.dependences : $(wildcard *.dep perl/*.dep)
	@{ [ ! -f $@ ] || sed $(foreach f,$^, -e '/^$(subst /,\/,$(f:.dep=\.o))[: ]/,/[^\\]$$/ d') $@; \
	   [ -z "$^" ] || { cat $^; rm $^; }; \
	} >$@.new
	@${MV} $@.new $@

include .dependences

%.h : ;	@echo include file $@ mentioned in .dependences does not exist - ignored
$(ProjectTop)/lib/PTL/include/std/ext/% : ;	@echo include file $@ mentioned in .dependences does not exist - ignored
%.hpp : ; @echo include file $@ mentioned in .dependences does not exist - ignored
%.tcc : ; @echo include file $@ mentioned in .dependences does not exist - ignored

endif  # ProcessDep != none

### delete all non-sources
clean:
	rm -f *-d *-dO? *-p *.o perl/*.o *.a ${BuildDir}/lib/${AppName}*.${SO} .dependences *.d *.dep perl/*.dep \
	      $(if ${COMOversion}, *.ti *.ii *.et) ${ExtraCLEAN}
	@+$(call _MakeCoreLib,clean)
	@+$(call _MakeExternal,clean)

ifdef AppName
  InstallLibDir ?= ${InstallArch}/lib

  ifneq (${AppName},lib)
    install-src:
	@+$(call _MakeCoreLib,install-src)
	${PERL} ${INSTALL_PL} -m ${DirMask} -U $(if ${ExtensionTop},${ExtensionTop},${AppTop})/apps/${AppName}/include ${InstallTop}/apps/${AppName}/include
	${PERL} ${INSTALL_PL} -m ${DirMask} -U -X perl $(if ${ExtensionTop},${ExtensionTop},${AppTop})/apps/${AppName}/src ${InstallTop}/apps/${AppName}/src

    install : all-lib
	@+$(call _MakeCoreLib,install)
	${PERL} ${INSTALL_PL} -m 555 ${OwnShared} ${InstallLibDir}

  else # AppName == lib
    install-src:
	${PERL} ${INSTALL_PL} -m ${DirMask} -U -X src ${ProjectTop}/lib/PTL ${InstallTop}/lib/PTL

    install : all-lib
	${PERL} ${INSTALL_PL} -d -m ${DirMask} ${InstallLibDir}
	${PERL} ${INSTALL_PL} -m 555 ${OwnShared} ${InstallLibDir}

  endif # AppName == lib
endif # AppName

# if nothing to do:
install% : ;


# Local Variables:
# mode: Makefile
# End:
