#  Copyright (c) 1997-2007
#  Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
#  http://www.math.tu-berlin.de/polymake,  mailto:polymake@math.tu-berlin.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 7568 2007-01-17 16:25:44Z gawrilow $

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

### provide 'all' be a default target
all : do_all ;

include $(ProjectTop)/support/utils.make

### locate ourselves
override .inside_project := $(filter .. ../%, $(BuildDir))
ifdef .inside_project
  ifeq ($(AppName)$(ModuleName),)
    .external := $(findstring /external/, $(CURDIR))
    ifndef .external
      ifneq ($(findstring /apps/, $(CURDIR)),)
        AppName := $(notdir $(CURDIR))
        BeFirst := $(AppName)
      else
      ifneq ($(findstring /modules/, $(CURDIR)),)
        ModuleName := $(notdir $(CURDIR))
        BeFirst := $(ModuleName)
      endif
      endif
    endif
  endif
endif

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

Libs := -lgmp $(Libs)
InstallClient := $(PERL) $(INSTALL_PL) -m 555

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

ifeq ($(Debug),)
  doOPT:=y
  CXXflags += -DALL_PLAUSIBLE_CHECKS=0
  InstallClient += -s
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
ifeq ($(Debug),timing)
  suffix:=-T
  CXXflags += -DPOLY_TIMING -DALL_PLAUSIBLE_CHECKS=0
  doOPT:=y
else
  suffix:=-d
  Cflags += $(CXXDEBUG)
  CXXflags += $(CXXDEBUG) -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
endif
endif
O := $(suffix).o
LO := $(if $(filter timing,$(Debug)),.o,$O)
A := $(filter-out -T,$(suffix)).a
export Profile

LINK_INCR := $(LD)

### locate the sources
ifdef .inside_project
  ifeq ($(AppName),lib)
    ### building the core library
    override SourceDir := $(wildcard $(ProjectTop)/lib/*/src)
    OwnLibraries := libpoly
    LibModules := $(basename $(notdir $(wildcard $(addsuffix /*.cc,$(SourceDir)))))
  else
    ifndef SourceDir
      ifdef .external
	SourceDir := $(wildcard $(ProjectTop)/ext_lib/$(notdir $(CURDIR)))
      else
        ifdef AppName
          ### building an application
          SourceDir := $(wildcard $(ProjectTop)/apps/$(AppName)/src)
          OwnIncludes := $(wildcard $(ProjectTop)/apps/$(AppName)/include)
        endif
        ifdef ModuleName
          ### building a module
          SourceDir := $(wildcard $(ProjectTop)/modules/$(ModuleName)/src)
          OwnIncludes := $(wildcard $(ProjectTop)/modules/$(ModuleName)/include)
        endif
      endif
    endif
  endif
endif # .inside_project
ifndef SourceDir
  Tries := src ../src . ..
  _FindSourceDir = $(patsubst %/,%,$(dir $(firstword $(wildcard $(foreach t,$(Tries),$(addprefix $t/,$(1)))))))
  SourceDir := $(call _FindSourceDir,*.c *.cc *.C *.cpp)
  ifndef SourceDir
    $(error SourceDir undefined, can't locate source files)
  endif
  ifneq ($(wildcard $(SourceDir)/*.h $(SourceDir)/*.hh),)
    OwnIncludes := $(SourceDir)
  endif
endif # !SourceDir

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))
endif
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 $(_obj_name:.o=.d) $(patsubst %,-MT '%',$(filter-out $(_obj_name),$(lib_dep_target)) $(_obj_name))
  else
    make_dep = -MD $(patsubst %,-MT '%',$(lib_dep_target))
  endif
endif

ifneq ($(AppName),lib)
  ### load per-client or per-application settings
  -include $(SourceDir)/Makefile.inc

  ### all clients that can be built
  StandardClients ?= $(filter-out $(LibModules) $(ExtraModules), $(basename $(call _list_CXX_sources,$(SourceDir))))
  PossibleClients := $(StandardClients) $(NonstandardClients) $(NoPrimaryModule)
  AllClients := all

  Includes := $(OwnIncludes) $(Includes)
  IncludesXX := $(OwnIncludes) $(patsubst %,$(ProjectTop)/apps/%/include,$(ExtendApp)) \
                $(patsubst %,$(ProjectTop)/modules/%/include,$(UseModules)) $(IncludesXX)

  ### check for own library
  ifdef LibModules
    OwnLibraries ?= lib$(AppName)$(ModuleName)
  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
ifdef .inside_project
  ifndef .external
    LocalLibs = $(foreach m, $(UseModules), $(wildcard $(BuildDir)/modules/$m/lib$m$A)) $(BuildDir)/lib/libpoly$A
    LocalLibDeps = $(LocalLibs)

    ifdef BeFirst
      define  _MakeCoreLib
	$(MAKE) --print-directory -C $(BuildDir)/lib AppName=lib BeFirst= Debug=$(filter-out timing,$(Debug)) $(1)

      endef

      ifdef UseModules
      define _MakeModule
	$(MAKE) --print-directory -C $(BuildDir)/modules/$(1) AppName= ModuleName=$(1) BeFirst= Debug=$(Debug) $(2)

      endef
      define _MakeModules
	$(foreach m,$(UseModules),$(call _MakeModule,$m,$(1)))
      endef
      endif
    endif

    ifdef ExternalLibs
      define _MakeExternalLib
	$(MAKE) --print-directory -C $(BuildDir)/external/$(1) Debug=$(filter-out timing,$(Debug)) AppName= ModuleName= $(2)

      endef
      define _MakeExternal
	$(foreach x,$(ExternalLibs),$(call _MakeExternalLib,$x,$(1)))
      endef
    endif
  endif
else  # ! .inside_project
  LocalLibs := -L$(InstallArch)/lib $(patsubst %,-l%,$(ExtendApp) poly)
  LocalLibDeps := 
endif  # ! .inside_project

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

ifdef OwnLibraries
  OwnLibs := $(addsuffix $A, $(OwnLibraries))

  ifeq ($(words $(OwnLibraries)),1)
    LibObjects := $(addsuffix $(LO), $(LibModules))
    .INTERMEDIATE: $(LibObjects) $(LibObjects:.o=-tmp.o)
    .PRECIOUS: $(LibObjects)
    .PHONY: $(OwnLibraries)

    $(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 = $(if $(filter -r,$(ExtraLDFLAGS)),$(OwnLibs)($@) $@, $(OwnLibs)($@))
    $(OwnLibraries) : LibCXXFLAGS := $(if $(COMOversion),-tused)

  else
    .PHONY: all-own-lib
    $(OwnLibraries) : % : all-own-lib;
    all-own-lib :
	@$(foreach l,$(OwnLibraries),$(MAKE) --no-print-directory all-lib OwnLibraries=$l Debug=$(filter-out timing,$(Debug));)
  endif
endif  # OwnLibraries

_build_core_lib:
	+@$(call _MakeCoreLib,all-lib)
_build_external_libs:
	+@$(call _MakeExternal,all-lib)
_build_module_libs:
	+@$(call _MakeModules,all-lib)

all-lib: $(if $(BeFirst),_build_core_lib) _build_external_libs $(if $(BeFirst),_build_module_libs) $(OwnLibraries)

### client building rules
ifdef AllClients

  # The aim of this one extra recursion level is to ensure all libraries are up-to-date
  # before the timestamps of client executables are checked.

  ifneq "$(origin AllClients)" "command line"
    
    _ignore := $(call _get_no_export,$(SourceDir),broken|test)
    AllClients := $(filter-out $(basename $(notdir $(_ignore))), $(PossibleClients))
    ClientFiles := $(addsuffix $(suffix),$(AllClients))

    do_all : all-lib
	@$(MAKE) --no-print-directory AllClients='$(AllClients)'
	+@$(call _MakeModules,all)

    all-clients : all-lib
	@$(MAKE) --no-print-directory AllClients='$(AllClients)'

    .PHONY: $(PossibleClients) given-clients
    $(PossibleClients) : % : all-lib given-clients ; @:

    given-clients: ; @$(MAKE) --no-print-directory AllClients='$(filter-out all-lib,$(MAKECMDGOALS))'

  else	 # self-recursive call
    do_all : $(AllClients)

    StandardClientFiles := $(addsuffix $(suffix),$(StandardClients))
    NonstandardClientFiles := $(addsuffix $(suffix),$(NonstandardClients))
    NoPrimaryModuleClientFiles := $(addsuffix $(suffix),$(NoPrimaryModule))

    ifdef suffix
      .PHONY: $(PossibleClients)

      $(PossibleClients) : % : %$(suffix) ; @:
    endif

    define _do_link
	$(CXX) $(ExtraLDFLAGS) $(LDFLAGS) -o $@ $(filter %.o,$^) \
	$(OwnLibs) $(LocalLibs) $(ExtraLIBS) $(LIBS)

    endef

    $(StandardClientFiles) $(NonstandardClientFiles) : % : %.o $(OwnLibs) $(LocalLibDeps)
	$(_do_link)
    $(NoPrimaryModuleClientFiles) : % : $(OwnLibs) $(LocalLibDeps)
	$(_do_link)

  endif  # explicit AllClients
endif  # AllClients

### compilation rules
_obj_name = $(if $(filter -r,$(ExtraLDFLAGS)),$(@:.o=-tmp.o),$@)

define _do_deps
	$(call _process_d,$(_obj_name:.o=.d))

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

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

endef
define _CXX_do_compile
	$(CXX) -c -o $(1) $(ExtraCXXFLAGS) $(LibCXXFLAGS) $(CXXFLAGS) $(if $(doOPT),$(CXXOPT)) $(make_dep) $<

endef
define _CXX_incr_link
	$(LINK_INCR) $(ExtraLDFLAGS) -o $@ $(@:.o=-tmp.o) $(ExtraLIBS)
	rm $(@:.o=-tmp.o)

endef
define _CXX_compile
$(if $(filter -r,$(ExtraLDFLAGS)), \
	$(call _CXX_do_compile,$(@:.o=-tmp.o)) \
	$(_CXX_incr_link) , \
	$(call _CXX_do_compile,$@) )

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)

ifeq "$(Debug)" "timing"
  OO := $(LO)
endif

ifdef OO
%$(OO) : %.cc
	$(_CXX_compile)
	@$(_do_deps)
%$(OO) : %.C
	$(_CXX_compile)
	@$(_do_deps)
%$(OO) : %.cpp
	$(_CXX_compile)
	@$(_do_deps)
%$(OO) : %.c
	$(_C_compile)
	@$(_do_deps)
endif

vpath %.cc $(SourceDir)
vpath %.C $(SourceDir)
vpath %.cpp $(SourceDir)
vpath %.c $(SourceDir)

### update dependence list
ifeq "$(ProcessDep)" "none"
  make_dep :=
  _do_deps :=

else
ifeq "$(ProcessDep)" "gcc"
  _process_d = sed -e 's:/usr/include/[^ 	]*[ 	]::g' \
		   -e 's:/[^ 	]*/gcc-lib/[^ 	]*/include/[^ 	]*[ 	]::g' \
		   -e '/^[ 	]*\\$$/ d' $(1) >$(@:.o=.dep) \
	       && rm $(1)
else
  _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-lib/[^ 	]*/include/[^ 	]*[ 	]::g' \
		   -e 's:/[^ 	]*/lib/gcc/[^ 	]*/include/[^ 	]*[ 	]::g' \
		   -e 's:/[^ 	]*/libcomo[^ 	]*[ 	]::g' \
		   -e '/^[ 	]*\\$$/ d' $*.d >$(@:.o=.dep) \
	       && rm $*.d
endif

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

include .dependences

%.h : ;	@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 $(wildcard $(PossibleClients)) *-d *-T *-dO? *-p \
	      *.o *.a .dependences *.d *.dep $(if $(COMOversion), *.ti *.ii *.et) $(ExtraCLEAN)
	@+$(call _MakeModules,clean)
	@+$(call _MakeCoreLib,clean)
	@+$(call _MakeExternal,clean)

ifneq ($(AppName)$(ModuleName),)
  InstallLibDir ?= $(InstallArch)/lib
  InstallBinDir ?= $(InstallArch)/$(if $(ModuleName),modules/$(ModuleName),apps/$(AppName))/bin

  ifneq ($(AppName),lib)
    InstallInclDir ?= $(InstallTop)/apps/$(AppName)/include
    install-include:
	@+$(call _MakeCoreLib,install-include)
	$(if $(OwnIncludes), \
	  $(PERL) $(INSTALL_PL) -m $(DirMask) $(if $(AppName),-U) $(OwnIncludes) $(InstallInclDir))
	@+$(call _MakeModules,install-include InstallInclDir=$(InstallInclDir))

    ### install the clients
    install : all
	$(PERL) $(INSTALL_PL) -d -m $(DirMask) -U $(InstallBinDir)
	$(InstallClient) $(ClientFiles) $(InstallBinDir)
	@+$(call _MakeModules,install)

    ifdef ModuleName
     ifdef OwnLibraries
      ### insert the library modules into the application library
      install-lib : all-lib
	$(AR) -xo $(OwnLibs)
	$(AR) -rc $(AppLib) $(LibObjects)
	rm -f $(LibObjects)
     endif
    else # Application
     ifdef OwnLibraries
      ### install the own libraries
      install-lib : all-lib
	@+$(call _MakeCoreLib,install-lib)
	$(if $(OwnLibraries), $(PERL) $(INSTALL_PL) -m 644 $(OwnLibs) $(InstallLibDir))
	@+$(call _MakeModules,install-lib AppLib=$(InstallLibDir)/$(OwnLibs))
	$(if $(OwnLibraries), \
	   $(foreach l, $(OwnLibs), $(RANLIB) $(InstallLibDir)/$l; chmod 444 $(InstallLibDir)/$l;) )
     endif
    endif

  else # AppName == lib
    InstallInclDir := $(InstallTop)/lib

    define _InstallIncludes
	$(PERL) $(INSTALL_PL) -m $(DirMask) -U $(1)/include $(InstallInclDir)/$(notdir $(1))/include

    endef

    install-include:
	$(foreach s, $(wildcard $(ProjectTop)/lib/*), $(call _InstallIncludes,$s))

    ### install the core libraries
    install-lib : all-lib
	$(PERL) $(INSTALL_PL) -d -m $(DirMask) $(InstallLibDir)
	$(PERL) $(INSTALL_PL) -m 644 $(OwnLibs) $(InstallLibDir)
	$(RANLIB) $(InstallLibDir)/$(OwnLibs); chmod 444 $(InstallLibDir)/$(OwnLibs)

  endif # AppName == lib
endif # AppName || ModuleName

# if nothing to do:
install% : ;


# Local Variables:
# mode: Makefile
# End:
