##########################################################################
#                                                                        #
#  This file is part of Frama-C.                                         #
#                                                                        #
#  Copyright (C) 2007-2009                                               #
#    CEA   (Commissariat  l'nergie Atomique)                           #
#    INRIA (Institut National de Recherche en Informatique et en         #
#           Automatique)                                                 #
#                                                                        #
#  you can redistribute it and/or modify it under the terms of the GNU   #
#  Lesser General Public License as published by the Free Software       #
#  Foundation, version 2.1.                                              #
#                                                                        #
#  It 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 Lesser General Public License for more details.                   #
#                                                                        #
#  See the GNU Lesser General Public License version v2.1                #
#  for more details (enclosed in the file licenses/LGPLv2.1).            #
#                                                                        #
##########################################################################

# This file is the main makefile of Frama-C.

MAKECONFIG_DIR=share

include share/Makefile.common

###########################
# Global plugin variables #
###########################

# the directory where compiled plugin files are stored
PLUGIN_LIB_DIR	= lib/plugins
PLUGIN_GUI_LIB_DIR= lib/gui

# the directory where the other Makefiles are
FRAMAC_SHARE	= share

# set it to yes to tell Makefile.dynamic than we come from here
FRAMAC_MAKE	=yes

# Shared lists between Makefile.plugin and Makefile :
# initialized them as "simply extended variables" (with :=)
# for a correct behavior of += (see section 6.6 of GNU Make manual)
PLUGIN_LIST	:=
PLUGIN_DYN_EXISTS:="no"
PLUGIN_DYN_LIST :=
PLUGIN_CMO_LIST	:=
PLUGIN_CMX_LIST	:=
PLUGIN_DYN_CMO_LIST :=
PLUGIN_DYN_CMX_LIST :=
PLUGIN_INTERNAL_CMO_LIST:=
PLUGIN_INTERNAL_CMX_LIST:=
PLUGIN_DEP_GUI_CMO_LIST:=
PLUGIN_DEP_GUI_CMX_LIST:=
PLUGIN_GUI_CMO_LIST:=
PLUGIN_GUI_CMX_LIST:=
PLUGIN_DYN_DEP_GUI_CMO_LIST:=
PLUGIN_DYN_DEP_GUI_CMX_LIST:=
PLUGIN_DYN_GUI_CMO_LIST :=
PLUGIN_DYN_GUI_CMX_LIST :=
PLUGIN_TYPES_CMO_LIST :=
PLUGIN_TYPES_CMX_LIST :=
PLUGIN_GENERATED_LIST :=
PLUGIN_DEP_LIST:=
PLUGIN_DOC_LIST :=
PLUGIN_DOC_DIRS :=
PLUGIN_DISTRIBUTED_LIST:=
PLUGIN_DIST_TARGET_LIST:=
PLUGIN_DIST_DOC_LIST:=
PLUGIN_BIN_DOC_LIST:=
PLUGIN_DIST_EXTERNAL_LIST:=
PLUGIN_TESTS_LIST:=
PLUGIN_DISTRIBUTED_NAME_LIST:=

###############################
# Additional global variables #
###############################

# put here any config option for the binary distribution outside of
# plugins
CONFIG_DISTRIB_BIN:=

# additional compilation targets for 'make all'.
# cannot be delayed after 'make all'
EXTRAS	= ptests

# Directories containing some source code
SRC_DIRS= ptests $(PLUGIN_LIB_DIR)

# Directory containing source code documentation
DOC_DIR	= doc/code

# Source files to document
MODULES_TODOC=

# Directories containing some source code
SRC_DIRS+= $(FRAMAC_SRC_DIRS)

# Directories to include when compiling
INCLUDES=$(addprefix -I , $(FRAMAC_SRC_DIRS)) -I $(PLUGIN_LIB_DIR) -I lib

# Directories to include for ocamldep
INCLUDES_FOR_OCAMLDEP= $(patsubst +%,.,$(INCLUDES) $(GUI_INCLUDES))

# Ocamldep flags
DEP_FLAGS= $(INCLUDES_FOR_OCAMLDEP)

# Files for which dependencies are computed
FILES_FOR_OCAMLDEP+=$(PLUGIN_LIB_DIR)/*.mli \
		$(addsuffix /*.mli, $(UNPACKED_DIRS)) \
		$(addsuffix /*.ml, $(UNPACKED_DIRS))

# Flags to use by ocamlc and ocamlopt
BFLAGS	= $(FLAGS) $(DEBUG) $(INCLUDES) $(COVERAGE_COMPILER_BYTE)
OFLAGS	= $(FLAGS) $(DEBUG) $(INCLUDES) $(COVERAGE_COMPILER_OPT)

BLINKFLAGS = $(BFLAGS) -linkall -custom
OLINKFLAGS = $(OFLAGS) -linkall

# Libraries generated by Frama-C
GEN_BYTE_LIBS=
GEN_OPT_LIBS=

# Libraries used in Frama-C
BYTE_LIBS = nums.cma unix.cma bigarray.cma str.cma dynlink.cma \
	$(GEN_BYTE_LIBS)
OPT_LIBS = nums.cmxa unix.cmxa bigarray.cmxa str.cmxa

ifeq ("$(NATIVE_DYNLINK)","yes")
OPT_LIBS+= dynlink.cmxa
endif

OPT_LIBS+= $(GEN_OPT_LIBS)

# files to be included in the distribution.
# plugins may add some files to this list if they include files that are
# not in $PLUGIN_DIR
DISTRIB_FILES:=cil/*/*.ml* cil/src/*/*.ml* cil/*/*.in cil/LICENSE	\
      cil/CHANGES cil/doc/*.html cil/doc/*.tex cil/doc/*.gif		\
      share/frama-c.rc man/frama-c.1 cil/doc/*.pdf cil/doc/api/*.html	\
      cil/doc/examples/*.txt doc/manuals/*.pdf doc/README		\
      doc/code/*.ml* doc/code/*.css doc/code/*.txt			\
      doc/code/toc_head.htm doc/code/toc_tail.htm tests/*/*.c		\
      tests/*/*.h tests/*/*.ml ptests/*.ml*				\
      tests/wp/test_config_dev.system_why				\
      tests/wp/test_config_dev.local_why configure.in Makefile		\
      share/Makefile.plugin configure share/Makefile.dynamic		\
      share/Makefile.dynamic_config.internal				\
      share/Makefile.dynamic_config.external Changelog config.h.in	\
      VERSION $(filter-out CVS,licenses/*) share/*.c share/*.h		\
      share/configure.ac share/Makefile.config.in			\
      share/Makefile.common share/Makefile.plugin			\
      share/Makefile.dynamic 						\
      share/why/*.why share/why/Makefile share/why/*.why.src		\
      $(filter-out %kui%,src/kernel/*.ml*) external/ptmap.ml*		\
      external/unmarshal*.ml* src/ai/*.ml* src/buckx/*.ml*		\
      src/buckx/*.c src/gui/*.ml* src/lib/*.ml* src/logic/*.ml*		\
      src/memory_state/*.ml* src/misc/*.ml* src/project/*.ml*		\
      src/toplevel/*.ml* bin/sed_get_make_major bin/sed_get_make_minor	\
      bin/sed_inplace INSTALL .make-clean .make-clean-stamp		\
      .make-ocamlgraph-stamp

################
# Main targets #
################

ifneq ($(ENABLE_GUI),no)
ifeq ($(HAS_LABLGTK),yes)
EXTRAS	+= gui
endif
endif

all:: byte $(EXTRAS) $(OCAMLBEST) share/Makefile.dynamic_config \
      share/Makefile.kernel
	for plugin in $(EXTERNAL_PLUGINS); do \
	$(MAKE) FRAMAC_LIBDIR=$(FRAMAC_SRC)/lib/fc FRAMAC_SHARE=$(FRAMAC_SRC)/share -C $$plugin all; \
	done

clean::
	$(PRINT_RM) $(OBJ_PERFCOUNT)
	$(RM) $(OBJ_PERFCOUNT)
	for plugin in $(EXTERNAL_PLUGINS); do \
	$(MAKE) FRAMAC_LIBDIR=$(FRAMAC_SRC)/lib/fc FRAMAC_SHARE=$(FRAMAC_SRC)/share -C $$plugin clean; \
	done

.PHONY: top opt byte dist bdist archclean rebuild
top: bin/toplevel.top$(EXE)
byte: bin/toplevel.byte$(EXE)
opt: bin/toplevel.opt$(EXE)

dist: clean
	$(QUIET_MAKE) OPTIM="-unsafe -noassert" DEBUG="" all
bdist: clean
	$(QUIET_MAKE) OPTIM="-unsafe -noassert" DEBUG="" byte

ifneq ("$(OCAMLGRAPH_LOCAL)","")
archclean: clean
	$(PRINT_RM) ocamlgraph
	$(QUIET_MAKE) -C $(OCAMLGRAPH_LOCAL) distclean
	$(PRINT_CONFIG) ocamlgraph
	cd $(OCAMLGRAPH_LOCAL) ; ./configure

rebuild: archclean
	$(PRINT_BUILD) ocamlgraph
	$(MAKE) -C $(OCAMLGRAPH_LOCAL)
	$(PRINT_BUILD) all
	$(QUIET_MAKE) all
else
archclean: clean

rebuild: archclean
	$(PRINT_BUILD) all
	$(QUIET_MAKE) all
endif

############
# Coverage #
############

USE_COVERAGE_TOOL=no
ifeq ($(USE_COVERAGE_TOOL),yes)
COVERAGE_PATH=.
COVERAGE_PREPRO=camlp4o -no_quot -filter $(COVERAGE_PATH)/coverage_filter.cmo
COVERAGE_COMPILER_BYTE=-I $(COVERAGE_PATH) -pp "$(COVERAGE_PREPRO)"
COVERAGE_COMPILER_OPT=-I $(COVERAGE_PATH) -pp "$(COVERAGE_PREPRO)"
COVERAGE_LIB_BYTE=coverage.cma
COVERAGE_LIB_OPT=coverage.cmxa
endif

INCLUDES+=$(COVERAGE_COMPILER_BYTE)
GEN_BYTE_LIBS+=$(COVERAGE_LIB_BYTE)
GEN_OPT_LIBS+=$(COVERAGE_LIB_OPT)
SRC_DIRS+=$(COVERAGE_PATH)

##############
# Ocamlgraph #
##############

ifneq ("$(OCAMLGRAPH_LOCAL)","")

lib/graph.cmi: .make-ocamlgraph $(wildcard $(OCAMLGRAPH_LOCAL)/src/*.ml*) \
		$(OCAMLGRAPH_LOCAL)/Makefile
	$(PRINT_BUILD) ocamlgraph
	$(MAKE) -C $(OCAMLGRAPH_LOCAL)
	$(PRINT_CP) $@
	$(CP) $(patsubst lib/%,$(OCAMLGRAPH_LOCAL)/%,$@) $@

lib/graph.cmo: lib/graph.cmi
	$(PRINT_CP) $@
	$(CP) $(patsubst lib/%,$(OCAMLGRAPH_LOCAL)/%,$@) $@

lib/graph.cmx: lib/graph.cmi
	$(PRINT_CP) $@
	$(CP) $(patsubst lib/%,$(OCAMLGRAPH_LOCAL)/%,$@) $@

lib/graph.o: lib/graph.cmi
	$(PRINT_CP) $@
	$(CP) $(patsubst lib/%,$(OCAMLGRAPH_LOCAL)/%,$@) $@

GENERATED+= lib/graph.cmo lib/graph.cmi
ifneq ($(OCAMLOPT),no)
GENERATED+= lib/graph.cmx lib/graph.o
endif

GRAPH_BYTE_LIBS=lib/graph.cmo
GRAPH_OPT_LIBS=lib/graph.cmx
GEN_BYTE_LIBS+=$(GRAPH_BYTE_LIBS)
GEN_OPT_LIBS+=$(GRAPH_OPT_LIBS)

.PRECIOUS: .cmo .cmi .cmx .o .cmxa .cma

# viewgraph and  dgraph (included in ocamlgraph)
ifeq ($(HAS_GNOMECANVAS),yes)

lib/viewgraph.cmi: lib/graph.cmi
	$(PRINT_CP) $@
	$(CP) $(patsubst lib/%,$(OCAMLGRAPH_LOCAL)/view_graph/%,$@) $@

lib/viewgraph.cmo: lib/graph.cmi
	$(PRINT_CP) $@
	$(CP) $(patsubst lib/%,$(OCAMLGRAPH_LOCAL)/view_graph/%,$@) $@

lib/viewgraph.cmx: lib/graph.cmi
	$(PRINT_CP) $@
	$(CP) $(patsubst lib/%,$(OCAMLGRAPH_LOCAL)/view_graph/%,$@) $@

lib/viewgraph.o: lib/graph.cmi
	$(PRINT_CP) $@
	$(CP) $(patsubst lib/%,$(OCAMLGRAPH_LOCAL)/view_graph/%,$@) $@

lib/dgraph.cmi: lib/graph.cmi
	$(PRINT_CP) $@
	$(CP) $(patsubst lib/%,$(OCAMLGRAPH_LOCAL)/dgraph/%,$@) $@

lib/dgraph.cmo: lib/graph.cmi
	$(PRINT_CP) $@
	$(CP) $(patsubst lib/%,$(OCAMLGRAPH_LOCAL)/dgraph/%,$@) $@

lib/dgraph.cmx: lib/graph.cmi
	$(PRINT_CP) $@
	$(CP) $(patsubst lib/%,$(OCAMLGRAPH_LOCAL)/dgraph/%,$@) $@

lib/dgraph.o: lib/graph.cmi
	$(PRINT_CP) $@
	$(CP) $(patsubst lib/%,$(OCAMLGRAPH_LOCAL)/dgraph/%,$@) $@

GRAPH_GUICMO= lib/dgraph.cmo lib/viewgraph.cmo
GRAPH_GUICMI= $(GRAPH_GUICMO:.cmo=.cmi)
GRAPH_GUICMX= $(GRAPH_GUICMO:.cmo=.cmx)
GRAPH_GUIO=  $(GRAPH_GUICMO:.cmo=.o)
GENERATED+= $(GRAPH_GUICMI) $(GRAPH_GUICMO)
ifneq ($(OCAMLOPT),no)
GENERATED+= $(GRAPH_GUICMX) $(GRAPH_GUIO)
endif

GEN_BYTE_GUI_LIBS+=$(GRAPH_GUICMO)
GEN_OPT_GUI_LIBS+=$(GRAPH_GUICMX)

HAS_VIEWGRAPH=yes
HAS_DGRAPH=yes

else # viewgraph and dgraph are not available
HAS_DGRAPH=no
endif

else # does not use ocamlgraph local version

INCLUDES+=$(OCAMLGRAPH)
BYTE_LIBS+= graph.cma
OPT_LIBS+= graph.cmxa

# viewgraph and dgraph (included in ocamlgraph)
ifeq ($(HAS_GNOMECANVAS),yes)
GRAPH_GUICMO_BASE= dgraph.cmo viewgraph.cmo
GRAPH_GUICMO=$(GRAPH_GUICMO_BASE:%=$(OCAMLGRAPH_HOME)/%)
GRAPH_GUICMX= $(GRAPH_GUICMO:.cmo=.cmx)
GRAPH_GUIO= $(GRAPH_GUICMO:.cmo=.o)
HAS_DGRAPH=yes
else # viewgraph and dgraph not available
HAS_DGRAPH=no
endif

endif # testing ocamlgraph is local

# If 'make untar-ocamlgraph' have to be performed after 'cvs update':
# change '.make-ocamlgraph-stamp' before 'cvs commit'
.make-ocamlgraph: .make-ocamlgraph-stamp
	touch $@
# Inline the rules of "untar-ocamlgraph" here 
# because calling a recursive make does not work
	$(PRINT_UNTAR) ocamlgraph
	$(RM) -r $(OCAMLGRAPH_LOCAL)
	$(TAR) xzf ocamlgraph.tar.gz
	cd $(OCAMLGRAPH_LOCAL) && ./configure

include .make-ocamlgraph
DISTRIB_FILES += .make-ocamlgraph

# force "make untar-ocamlgraph" to be executed for all users of CVS
force-ocamlgraph:
	expr `$(CAT) .make-ocamlgraph-stamp` + 1 > .make-ocamlgraph-stamp

.PHONY: untar-ocamlgraph
untar-ocamlgraph:
	$(PRINT_UNTAR) $@
	$(RM) -r $(OCAMLGRAPH_LOCAL)
	$(TAR) xzf $<
	cd $(OCAMLGRAPH_LOCAL) && ./configure

##################
# Frama-C Kernel #
##################

# Dynlink library
#################

GENERATED += src/lib/dynlink_common_interface.ml

ifeq ($(HAS_OCAML311),yes) # ocaml >= 3.11

ifeq ($(USABLE_NATIVE_DYNLINK),yes) # native dynlink works

src/lib/dynlink_common_interface.ml: src/lib/dynlink_311_or_higher.ml \
		share/Makefile.config Makefile
	$(PRINT_MAKING) $@
	$(CP) $< $@
	$(CHMOD_RO) $@

else # ocaml >= 3.11 but native dynlink doesn't work

ifeq ($(NATIVE_DYNLINK),yes) # native dynlink does exist but doesn't work
src/lib/dynlink_common_interface.ml: src/lib/bad_dynlink_311_or_higher.ml \
		share/Makefile.config Makefile
	$(PRINT_MAKING) $@
	$(CP) $< $@
	$(CHMOD_RO) $@

else # no dynlink at all (for instance no native compiler)

# Just for ocamldep
src/lib/dynlink_common_interface.ml: src/lib/dynlink_311_or_higher.ml \
		share/Makefile.config Makefile
	$(PRINT_MAKING) $@
	$(CP) $< $@
	$(CHMOD_RO) $@

# Add two different rules for bytecode and native since
# the file dynlink_common_interface.ml does not provide from the same file
# in these cases.

src/lib/dynlink_common_interface.cmo: src/lib/dynlink_311_or_higher.ml \
		share/Makefile.config Makefile
	$(PRINT_MAKING) src/lib/dynlink_common_interface.ml
	$(CP) $< src/lib/dynlink_common_interface.ml
	$(CHMOD_RO) src/lib/dynlink_common_interface.ml
	$(PRINT_OCAMLC) $@
	$(OCAMLC) -c $(BFLAGS) src/lib/dynlink_common_interface.ml

src/lib/dynlink_common_interface.o src/lib/dynlink_common_interface.cmx: src/lib/no_dynlink_opt.ml share/Makefile.config Makefile
	$(PRINT_MAKING) src/lib/dynlink_common_interface.ml
	$(CP) $< src/lib/dynlink_common_interface.ml
	$(CHMOD_RO) src/lib/dynlink_common_interface.ml
	$(PRINT_OCAMLOPT) $@
	$(OCAMLOPT) -c $(OFLAGS) src/lib/dynlink_common_interface.ml

endif

endif

else # ocaml 3.10.*

# Just for ocamldep
src/lib/dynlink_common_interface.ml: src/lib/dynlink_lower_311_byte.ml \
		share/Makefile.config Makefile
	$(PRINT_MAKING) $@
	$(CP) $< $@
	$(CHMOD_RO) $@

# Add two different rules for bytecode and native since
# the file dynlink_common_interface.ml does not provide from the same file
# in these cases.

src/lib/dynlink_common_interface.cmo: src/lib/dynlink_lower_311_byte.ml \
		share/Makefile.config Makefile
	$(PRINT_MAKING) src/lib/dynlink_common_interface.ml
	$(CP) $< src/lib/dynlink_common_interface.ml
	$(CHMOD_RO) src/lib/dynlink_common_interface.ml
	$(PRINT_OCAMLC) $@
	$(OCAMLC) -c $(BFLAGS) src/lib/dynlink_common_interface.ml

src/lib/dynlink_common_interface.o src/lib/dynlink_common_interface.cmx: src/lib/no_dynlink_opt.ml share/Makefile.config Makefile
	$(PRINT_MAKING) src/lib/dynlink_common_interface.ml
	$(CP) $< src/lib/dynlink_common_interface.ml
	$(CHMOD_RO) src/lib/dynlink_common_interface.ml
	$(PRINT_OCAMLOPT) $@
	$(OCAMLOPT) -c $(OFLAGS) src/lib/dynlink_common_interface.ml

endif

# Libraries which could be compiled fully independently
#######################################################

EXTERNAL_LIB_CMO = unmarshal unmarshal_nums
EXTERNAL_LIB_CMO:= $(patsubst %, external/%.cmo, $(EXTERNAL_LIB_CMO))
CMO	+= $(EXTERNAL_LIB_CMO)

LIB_CMO = dynlink_common_interface \
	extlib \
	pretty_utils \
	hook \
	qstack \
	mergemap \
	rangemap \
	type \
	descr
LIB_CMO:= $(patsubst %, src/lib/%.cmo, $(LIB_CMO))
CMO	+= $(LIB_CMO)

# Very first files to be linked (most modules used them)
###############################

FIRST_CMO= config gui_init log cmdline journal
FIRST_CMO:= $(patsubst %, src/kernel/%.cmo, $(FIRST_CMO))
CMO	+= $(FIRST_CMO)

#Project
PROJECT_CMO= namespace kind project datatype computation
PROJECT_CMO:= $(patsubst %, src/project/%.cmo, $(PROJECT_CMO))
CMO	+= $(PROJECT_CMO)
MLI_ONLY+= src/project/signature.mli

# Cil
#####

ifeq ("$(LOCAL_MACHDEP)","yes")

# Create the machine dependency module
# If the cl command cannot be run then the MSVC part will be identical to GCC
.PHONY : machdep $(CIL_PATH)/local_machdep.ml
machdep: $(CIL_PATH)/local_machdep.ml
bin/machdep.exe: machdep

$(CIL_PATH)/local_machdep.ml : cil/src/machdep.c configure.in Makefile
	$(PRINT_MAKING) $@
	$(RM) $@
	$(ECHO) "(* This module was generated automatically by code in Makefile and machdep.c *)" >$@
# Now generate the type definition
	$(ECHO) "open Cil_types" >> $@
	if gcc -D_GNUCC $< -o bin/machdep.exe ;then \
	    $(ECHO) "machdep.exe created succesfully."; \
	else \
            $(RM) $@; exit 1; \
        fi
	$(ECHO) "let gcc = {" >>$@
	./bin/machdep.exe >>$@
	$(ECHO) "	 underscore_name = $(UNDERSCORE_NAME) ;" >> $@
	$(ECHO) "}"          >>$@
	if cl /D_MSVC $< /Febin/machdep.exe /Fobin/machdep.obj ;then \
           $(ECHO) "let hasMSVC = true" >>$@; \
        else \
           $(ECHO) "let hasMSVC = false" >>$@; \
        fi
	$(ECHO) "let msvc = {" >>$@
	./bin/machdep.exe >>$@
	$(ECHO) "	 underscore_name = true ;" >> $@
	$(ECHO) "}"          >>$@
	$(ECHO) \
          "let gccHas__builtin_va_list = $(HAVE_BUILTIN_VA_LIST)" >>$@
	$(ECHO) "let __thread_is_keyword = $(THREAD_IS_KEYWORD)"  >>$@
	$(ECHO) \
	  "$@ generated. You may have this file merged into Frama-C by developers."
	$(CHMOD_RO) $@

endif

# Performance counters
PERFCOUNT=cil/ocamlutil/perfcount
USE_PERFCOUNT=no
ifeq ($(USE_PERFCOUNT),yes)
OBJ_PERFCOUNT=$(PERFCOUNT).o
STATS=cil/ocamlutil/stats.cmo
GEN_BYTE_LIBS+= $(OBJ_PERFCOUNT)
GEN_OPT_LIBS+= $(OBJ_PERFCOUNT)
else
OBJ_PERFCOUNT=
STATS=
endif

# .cmo files of cil
CIL_CMO = \
	cil/src/cilmsg.cmo \
	cil/ocamlutil/alpha.cmo cil/ocamlutil/clist.cmo \
	cil/ocamlutil/growArray.cmo \
	cil/ocamlutil/inthash.cmo $(STATS) \
	cil/ocamlutil/cilutil.cmo \
	cil/ocamlutil/setWithNearest.cmo \
	$(addprefix $(CIL_PATH)/, \
		cil_datatype.cmo cil_computation.cmo \
		logic/utf8_logic.cmo \
		cilglobopt.cmo \
		machdep_x86_16.cmo machdep_x86_32.cmo machdep_x86_64.cmo \
		machdep_ppc_32.cmo machdep_ppc_32_diab.cmo \
		machdep.cmo cil_const.cmo logic/logic_env.cmo \
		escape.cmo logic/logic_const.cmo cil.cmo \
                frontc/errorloc.cmo \
		frontc/cabs.cmo \
		ext/expcompare.cmo \
		frontc/cabshelper.cmo frontc/whitetrack.cmo \
		logic/logic_utils.cmo logic/logic_builtin.cmo \
                logic/logic_parser.cmo logic/logic_lexer.cmo \
		frontc/lexerhack.cmo \
		mergecil.cmo rmtmps.cmo \
		logic/logic_typing.cmo \
		frontc/cprint.cmo \
		frontc/cabsvisit.cmo frontc/cabs2cil.cmo \
		frontc/clexer.cmo frontc/cparser.cmo \
		logic/logic_preprocess.cmo \
		frontc/patch.cmo frontc/frontc.cmo \
		ext/obfuscate.cmo ext/ciltools.cmo \
		ext/callgraph.cmo ext/dataflow.cmo ext/dominators.cmo \
		ext/oneret.cmo ext/cfg.cmo \
		ext/usedef.cmo ext/liveness.cmo ext/reachingdefs.cmo \
		ext/availexpslv.cmo ext/rmciltmps.cmo ext/deadcodeelim.cmo \
		zrapp.cmo) # end of addprefix

CMO	+= $(CIL_CMO)
MLI_ONLY+= $(CIL_PATH)/cil_types.mli $(CIL_PATH)/logic/logic_ptree.mli
NO_MLI+=cil/src/cilglobopt.mli \
	cil/src/machdep_ppc_32.mli \
	cil/src/logic/logic_const.mli \
	cil/src/frontc/cabs.mli \
	cil/src/ext/expcompare.mli \
	cil/src/logic/logic_utils.mli \
	cil/src/logic/logic_lexer.mli \
	cil/src/frontc/lexerhack.mli \
	cil/src/ext/ciltools.mli \
	cil/src/ext/usedef.mli \
	cil/src/ext/liveness.mli \
	cil/src/ext/reachingdefs.mli \
	cil/src/ext/availexpslv.mli \
	cil/src/ext/rmciltmps.mli \
	cil/src/ext/deadcodeelim.mli

GENERATED += $(addprefix $(CIL_PATH)/, \
		frontc/clexer.ml frontc/cparser.ml frontc/cparser.mli \
		logic/logic_lexer.ml logic/logic_parser.ml \
		logic/logic_parser.mli logic/logic_preprocess.ml)

# Buckx
#######

CMO	+= src/buckx/buckx.cmo

GEN_BUCKX=src/buckx/mybigarray.o src/buckx/buckx_c.o
GEN_BYTE_LIBS+= $(GEN_BUCKX)
GEN_OPT_LIBS+= $(GEN_BUCKX)

src/buckx/buckx_c.o: src/buckx/buckx_c.c
	$(PRINT_OCAMLC) $@
	$(OCAMLC) $(BFLAGS) -ccopt "-O3 -fno-pic -fomit-frame-pointer -o $@" $<

# Main part of the kernel
#########################

# cannot use $(CONFIG_CMO) here :-(
KERNEL_CMO= \
	src/kernel/messages.cmo \
	src/kernel/dynamic.cmo \
	src/kernel/ast_printer.cmo \
	src/kernel/ast_info.cmo \
	src/kernel/kernel_type.cmo \
	src/kernel/plugin.cmo \
	src/kernel/kernel.cmo \
	src/kernel/alarms.cmo \
	src/kernel/cilE.cmo \
	src/memory_state/binary_cache.cmo \
	src/kernel/parameters.cmo \
	src/kernel/ast.cmo \
	src/ai/my_bigint.cmo \
	external/ptmap.cmo \
	src/memory_state/ptset.cmo \
	src/ai/abstract_interp.cmo \
	src/memory_state/mweak.cmo \
	src/ai/int_Base.cmo \
	src/kernel/unicode.cmo \
	src/misc/bit_utils.cmo \
	src/misc/subst.cmo \
	src/kernel/annotations.cmo \
	src/kernel/globals.cmo \
	src/kernel/kernel_function.cmo \
        src/misc/service_graph.cmo \
	src/ai/ival.cmo \
	src/ai/base.cmo \
	src/ai/base_Set_Lattice.cmo \
	src/ai/origin.cmo \
	src/ai/map_Lattice.cmo \
	src/memory_state/abstract_value.cmo \
	src/memory_state/baseUtils.cmo \
	src/memory_state/locations.cmo \
	src/memory_state/shifted_Location.cmo \
	src/memory_state/path_lattice.cmo \
	src/memory_state/int_Interv.cmo \
	src/memory_state/int_Interv_Map.cmo \
	src/memory_state/new_offsetmap.cmo \
	src/memory_state/offsetmap.cmo \
	src/memory_state/offsetmap_bitwise.cmo \
	src/memory_state/lmap.cmo \
	src/memory_state/lmap_bitwise.cmo \
	src/memory_state/lmap_whole.cmo \
	src/memory_state/function_Froms.cmo \
	src/memory_state/cvalue_type.cmo \
	src/memory_state/widen_type.cmo \
	src/memory_state/relations_type.cmo \
	src/memory_state/state_set.cmo \
	src/kernel/stmts_graph.cmo \
	src/kernel/visitor.cmo \
	src/kernel/printer.cmo src/kernel/unroll_loops.cmo \
	src/kernel/loop.cmo \
	$(PLUGIN_TYPES_CMO_LIST) \
	src/kernel/db.cmo  \
	src/logic/translate_lightweight.cmo \
	src/kernel/file.cmo \
	src/misc/debug.cmo \
	src/misc/filter.cmo \
	src/kernel/special_hooks.cmo \
	src/memory_state/widen.cmo \
	src/memory_state/bit_model_access.cmo \
	src/logic/logic_interp.cmo \
	src/logic/infer_annotations.cmo
CMO	+= $(KERNEL_CMO)

MLI_ONLY+= src/kernel/db_types.mli
NO_MLI+= src/ai/my_bigint.mli \
	src/ai/int_Base.mli \
	src/ai/base_Set_Lattice.mli \
	src/ai/origin.mli \
	src/ai/map_Lattice.mli \
	src/memory_state/abstract_value.mli \
	src/memory_state/baseUtils.mli \
	src/memory_state/int_Interv.mli \
	src/memory_state/int_Interv_Map.mli \
	src/memory_state/function_Froms.mli \
	src/memory_state/cvalue_type.mli \
	src/kernel/unroll_loops.mli \
	src/misc/debug.mli \
	src/memory_state/widen.mli

# Common startup module
# All link command should add it as last linked module and depend on it.
########################################################################

STARTUP_CMO=src/kernel/boot.cmo
STARTUP_CMX=$(STARTUP_CMO:.cmo=.cmx)

###############################################################################
#                                                                             #
####################                                                          #
# Plug-in sections #                                                          #
####################                                                          #
#                                                                             #
# For 'internal' developpers:                                                 #
# Add your own plug-in here                                                   #
#                                                                             #
###############################################################################

##################
# Occurrence     #
##################

PLUGIN_ENABLE:=$(ENABLE_OCCURRENCE)
PLUGIN_NAME:=Occurrence
PLUGIN_DISTRIBUTED:=yes
PLUGIN_HAS_MLI:=yes
PLUGIN_DIR:=src/occurrence
PLUGIN_CMO:= options register
PLUGIN_GUI_CMO:=register_gui
PLUGIN_INTRO:=doc/code/intro_occurrence.txt
include share/Makefile.plugin

###########
# Metrics #
###########

PLUGIN_ENABLE:=$(ENABLE_METRICS)
PLUGIN_NAME:=Metrics
PLUGIN_DISTRIBUTED:=yes
PLUGIN_HAS_MLI:=yes
PLUGIN_NO_TEST:=yes
PLUGIN_DIR:=src/metrics
PLUGIN_CMO:= metrics_parameters register
PLUGIN_NO_TEST:= yes
PLUGIN_GUI_CMO:=register_gui
include share/Makefile.plugin

#######################
# Syntactic callgraph #
#######################

# Extension of the GUI for syntactic callgraph is compilable
# only if dgraph is available
ifeq ($(HAS_DGRAPH),yes)
PLUGIN_GUI_CMO:=cg_viewer
else
PLUGIN_UNDOC:=cg_viewer.ml
endif

PLUGIN_ENABLE:=$(ENABLE_SYNTACTIC_CALLGRAPH)
PLUGIN_NAME:=Syntactic_callgraph
PLUGIN_DISTRIBUTED:=yes
PLUGIN_HAS_MLI:=yes
PLUGIN_DIR:=src/syntactic_callgraph
PLUGIN_CMO:= options register
PLUGIN_NO_TEST:=yes
include share/Makefile.plugin

##################
# Value analysis #
##################

PLUGIN_ENABLE:=$(ENABLE_VALUE)
PLUGIN_NAME:=Value
PLUGIN_DIR:=src/value
PLUGIN_CMO:= kf_state value_parameters eval kinstr register
PLUGIN_GUI_CMO:=register_gui
PLUGIN_HAS_MLI:=yes
PLUGIN_NO_TEST:=yes
PLUGIN_DISTRIBUTED:=yes
include share/Makefile.plugin

#################
# From analysis #
#################

PLUGIN_ENABLE:=$(ENABLE_FROM)
PLUGIN_NAME:=From
PLUGIN_DIR:=src/from
PLUGIN_CMO:= from_parameters from_register
PLUGIN_GUI_CMO:=from_register_gui
PLUGIN_HAS_MLI:=yes
PLUGIN_TESTS_DIRS:=idct test misc float
PLUGIN_DISTRIBUTED:=yes
include share/Makefile.plugin

##################
# Users analysis #
##################

PLUGIN_ENABLE:=$(ENABLE_USERS)
PLUGIN_NAME:=Users
PLUGIN_DIR:=src/users
PLUGIN_CMO:= users_register
PLUGIN_HAS_MLI:=yes
PLUGIN_NO_TEST:=yes
PLUGIN_DISTRIBUTED:=yes
include share/Makefile.plugin

########################
# Constant propagation #
########################

PLUGIN_ENABLE:=$(ENABLE_CONSTANT_PROPAGATION)
PLUGIN_NAME:=Constant_Propagation
PLUGIN_DIR:=src/constant_propagation
PLUGIN_CMO:= propagationParameters \
	register
PLUGIN_HAS_MLI:=yes
PLUGIN_DISTRIBUTED:=yes
include share/Makefile.plugin

###################
# Post-dominators #
###################

PLUGIN_ENABLE:=$(ENABLE_POSTDOMINATORS)
PLUGIN_NAME:=Postdominators
PLUGIN_DIR:=src/postdominators
PLUGIN_CMO:= print compute
PLUGIN_HAS_MLI:=yes
PLUGIN_NO_TEST:=yes
PLUGIN_DISTRIBUTED:=yes
include share/Makefile.plugin

#########
# inout #
#########

PLUGIN_ENABLE:=$(ENABLE_INOUT)
PLUGIN_NAME:=Inout
PLUGIN_DIR:=src/inout
PLUGIN_CMO:= kf_state inout_parameters context inputs outputs derefs \
             access_path register
PLUGIN_TYPES_CMO:=src/memory_state/inout_type
PLUGIN_HAS_MLI:=yes
PLUGIN_NO_TEST:=yes
PLUGIN_DISTRIBUTED:=yes
include share/Makefile.plugin

######################
# Semantic callgraph #
######################

PLUGIN_ENABLE:=$(ENABLE_SEMANTIC_CALLGRAPH)
PLUGIN_NAME:=Semantic_callgraph
PLUGIN_DIR:=src/semantic_callgraph
PLUGIN_CMO:= options register
PLUGIN_HAS_MLI:=yes
PLUGIN_NO_TEST:=yes
PLUGIN_DISTRIBUTED:=yes
include share/Makefile.plugin

######
# wp #
######

# Extension of the GUI for wp is compilable
# only if gnomecanvas is available
ifeq ($(HAS_GNOMECANVAS),yes)
PLUGIN_GUI_CMO:=wp_gui
else
PLUGIN_UNDOC:=wp_gui.ml
endif

PLUGIN_ENABLE:=$(ENABLE_WP)
PLUGIN_NAME:=Wp
PLUGIN_DIR:=src/wp
PLUGIN_CMO:= wp_parameters macros normAtLabels \
             fol why_output \
	     types why_ops wpFol \
             cil2cfg wpAnnot \
	     toprop call calculus translate \
	     mvar model0 model1 \
	     mmem model2 lowlevel_model \
	     register
# I don't know why, but ocamldoc doesn't like this file
PLUGIN_UNDOC:= translate.ml
PLUGIN_INTRO:=doc/code/intro_wp.txt
PLUGIN_HAS_MLI:=yes
PLUGIN_DISTRIBUTED:=no
PLUGIN_DISTRIB_BIN:=no
# ifeq (@HAS_ALTERGO@,no)
# PLUGIN_NO_DEFAULT_TEST:=yes
# endif

include share/Makefile.plugin

WP_LIB_DIR=share/why
include $(WP_LIB_DIR)/Makefile
lib/plugins/Wp.cmo : $(WP_LIB_FILES)

#####################
# Security analysis #
#####################

PLUGIN_ENABLE:=$(ENABLE_SECURITY)
PLUGIN_NAME:=Security
PLUGIN_DIR:=src/security
PLUGIN_CMO:= options lattice model components analysis register
PLUGIN_GUI_CMO:=register_gui
PLUGIN_HAS_MLI:=yes
PLUGIN_UNDOC:=analysis.ml
 # ocamldoc doesn't like recursive modules!
PLUGIN_DISTRIBUTED:=yes
include share/Makefile.plugin

###################
# Impact analysis #
###################

PLUGIN_ENABLE:=$(ENABLE_IMPACT)
PLUGIN_NAME:=Impact
PLUGIN_DIR:=src/impact
PLUGIN_CMO:= options register
PLUGIN_GUI_CMO:= register_gui
PLUGIN_HAS_MLI:=yes
PLUGIN_DISTRIBUTED:=yes
# PLUGIN_UNDOC:=impact_gui.ml
include share/Makefile.plugin

##################################
# PDG : program dependence graph #
##################################

PLUGIN_ENABLE:=$(ENABLE_PDG)
PLUGIN_NAME:=Pdg
PLUGIN_DIR:=src/pdg
PLUGIN_HAS_MLI:=yes
PLUGIN_CMO:= pdg_parameters print macros \
            lexical_successors \
            ctrlDpds \
	    state \
            build \
            sets \
            annot \
	    marks \
            register

PDG_TYPES:=pdgIndex pdgTypes pdgMarks
PDG_TYPES:=$(addprefix src/pdg_types/, $(PDG_TYPES))
PLUGIN_TYPES_CMO:=$(PDG_TYPES)

PLUGIN_INTRO:=doc/code/intro_pdg.txt
PLUGIN_TYPES_TODOC:=$(addsuffix .mli, $(PDG_TYPES))

PLUGIN_DISTRIBUTED:=yes
include share/Makefile.plugin

#####################################
# Scope : (very experimental !)     #
#####################################

PLUGIN_ENABLE:=$(ENABLE_SCOPE)
PLUGIN_NAME:=Scope
PLUGIN_DIR:=src/scope
PLUGIN_CMO:= datascope zones
PLUGIN_HAS_MLI:=yes
PLUGIN_GUI_CMO:=dpds_gui
PLUGIN_INTRO:=doc/code/intro_scope.txt
PLUGIN_DISTRIBUTED:=yes
include share/Makefile.plugin

#####################################
# Sparecode : unused code detection #
#####################################

PLUGIN_ENABLE:=$(ENABLE_SPARECODE)
PLUGIN_NAME:=Sparecode
PLUGIN_DIR:=src/sparecode
PLUGIN_CMO:= sparecode_params globs marks transform register
PLUGIN_HAS_MLI:=yes
PLUGIN_DEPENDS:=Pdg
PLUGIN_INTRO:=doc/code/intro_sparecode.txt
PLUGIN_DISTRIBUTED:=yes
include share/Makefile.plugin

###########
# Slicing #
###########

PLUGIN_ENABLE:=$(ENABLE_SLICING)
PLUGIN_NAME:=Slicing
PLUGIN_DIR:=src/slicing
PLUGIN_CMO:= slicingParameters \
            slicingMacros \
            slicingMarks \
            slicingActions \
            fct_slice \
            printSlice \
            slicingProject \
	    slicingTransform \
            slicingCmds \
            register
SLICING_TYPES:=slicingInternals slicingTypes
SLICING_TYPES:=$(addprefix src/slicing_types/, $(SLICING_TYPES))
PLUGIN_TYPES_CMO:=$(SLICING_TYPES)

PLUGIN_GUI_CMO:=register_gui

PLUGIN_INTRO:=doc/code/intro_slicing.txt
PLUGIN_TYPES_TODOC:= $(addsuffix .ml, $(SLICING_TYPES))
PLUGIN_UNDOC:=register.ml # slicing_gui.ml

PLUGIN_TESTS_DIRS:= slicing slicing2
#PLUGIN_TESTS_DIRS_DEFAULT:=slicing
PLUGIN_TESTS_LIB:= tests/slicing/libSelect tests/slicing/libAnim
PLUGIN_DEPENDS:=Pdg
PLUGIN_DISTRIBUTED:=yes
include share/Makefile.plugin

FILES_FOR_OCAMLDEP+=$(TEST_SLICING_ML)

#######################
# Aorai : ltl_to_acsl #
#######################

PLUGIN_ENABLE	:=$(ENABLE_LTL_TO_ACSL)
PLUGIN_DIR	:=src/ltl_to_acsl
PLUGIN_DYNAMIC  :=$(DYNAMIC_LTL_TO_ACSL)
DISTRIB_FILES += $(PLUGIN_DIR)/Makefile
include $(PLUGIN_DIR)/Makefile

###############################################################################
#                                                                             #
###########################                                                   #
# End of plug-in sections #                                                   #
###########################                                                   #
#                                                                             #
###############################################################################

#####################
# Generic variables #
#####################

CMX	= $(CMO:.cmo=.cmx)
CMI	= $(CMO:.cmo=.cmi)

ALL_CMO	= $(CMO) $(PLUGIN_CMO_LIST) $(STARTUP_CMO)
ALL_CMX	= $(patsubst %.cma, %.cmxa, $(ALL_CMO:.cmo=.cmx))

FILES_FOR_OCAMLDEP+= $(addsuffix /*.mli, $(FRAMAC_SRC_DIRS)) \
	$(addsuffix /*.ml, $(FRAMAC_SRC_DIRS))

MODULES_TODOC+=$(MLI_ONLY) \
	$(filter-out $(NO_MLI), \
	$(filter-out $(PLUGIN_TYPES_CMO_LIST:.cmo=.mli), \
		$(CMO:.cmo=.mli)))

############
# Toplevel #
############

ALL_BATCH_CMO= $(filter-out src/kernel/gui_init.cmo, $(ALL_CMO))
ALL_BATCH_CMX= $(patsubst %.cma, %.cmxa, $(ALL_BATCH_CMO:.cmo=.cmx))

bin/toplevel.byte$(EXE): $(ALL_BATCH_CMO) $(GEN_BYTE_LIBS) \
			$(PLUGIN_DYN_CMO_LIST)
	$(PRINT_LINKING) $@
	$(OCAMLC) $(BLINKFLAGS) -o $@ $(BYTE_LIBS) $(ALL_BATCH_CMO)
	$(MAKE) install-kernel-byte FRAMAC_LIBDIR=lib/fc

bin/toplevel.prof$(EXE): $(ALL_BATCH_CMO) $(GEN_BYTE_LIBS) \
			$(PLUGIN_DYN_CMO_LIST)
	$(PRINT_OCAMLCP) $@
	$(OCAMLCP) $(BFLAGS) -o $@ $(BYTE_LIBS) $(ALL_BATCH_CMO)

bin/toplevel.top$(EXE): $(ALL_BATCH_CMO) src/toplevel/toplevel_topdirs.cmo \
		$(GEN_BYTE_LIBS) $(PLUGIN_DYN_CMO_LIST)
	$(PRINT_OCAMLMKTOP) $@
	$(OCAMLMKTOP) $(BFLAGS) -custom -o $@ $(BYTE_LIBS) \
          $(filter-out src/kernel/boot.cmo, $(ALL_BATCH_CMO)) \
	  src/toplevel/toplevel_topdirs.cmo

bin/toplevel.opt$(EXE): $(ALL_BATCH_CMX) $(GEN_OPT_LIBS) $(PLUGIN_DYN_CMX_LIST)
	$(PRINT_LINKING) $@
	$(OCAMLOPT) $(OLINKFLAGS) -o $@ $(OPT_LIBS) $(ALL_BATCH_CMX)
	$(MAKE) install-kernel-opt FRAMAC_LIBDIR=lib/fc

share/Makefile.kernel: Makefile
	$(PRINT_MAKING) $@
	$(RM) $@
	$(ECHO) "# This makefile was automatically generated." > $@
	$(ECHO) "# Do not modify." >> $@
	$(ECHO) "ifeq (\$$(FRAMAC_INTERNAL),yes)" >> $@
	$(ECHO) "DYN_BLINKFLAGS=$(filter-out $(INCLUDES), $(BLINKFLAGS)) $(foreach d, $(INCLUDES:-I%=%), -I $(FRAMAC_SRC)/$(d))" >> $@
	$(ECHO) "DYN_GEN_BYTE_LIBS=$(addprefix $(FRAMAC_SRC)/, $(GEN_BYTE_LIBS))" >> $@
	$(ECHO) "DYN_BYTE_LIBS=$(filter-out $(GEN_BYTE_LIBS), $(BYTE_LIBS))" >> $@
	$(ECHO) "DYN_ALL_BATCH_CMO=$(addprefix $(FRAMAC_SRC)/, $(notdir $(ALL_BATCH_CMO)))" >> $@
	$(ECHO) "DYN_OLINKFLAGS=$(filter-out $(INCLUDES), $(OLINKFLAGS)) $(foreach d, $(INCLUDES:-I%=%), -I $(FRAMAC_SRC)/$(d))" >> $@
	$(ECHO) "DYN_GEN_OPT_LIBS=$(addprefix $(FRAMAC_SRC)/, $(GEN_OPT_LIBS))" >> $@
	$(ECHO) "DYN_OPT_LIBS=$(filter-out $(GEN_OPT_LIBS), $(OPT_LIBS))" >> $@
	$(ECHO) "DYN_ALL_BATCH_CMX=$(addprefix $(FRAMAC_SRC)/, $(ALL_BATCH_CMX))" >> $@
	$(ECHO) "else" >> $@
	$(ECHO) "DYN_BLINKFLAGS=$(filter-out $(INCLUDES), $(BLINKFLAGS))" >> $@
	$(ECHO) "DYN_GEN_BYTE_LIBS=$(addprefix $(FRAMAC_LIBDIR)/, $(notdir $(GEN_BYTE_LIBS)))" >> $@
	$(ECHO) "DYN_BYTE_LIBS=$(filter-out $(GEN_BYTE_LIBS), $(BYTE_LIBS))" >> $@
	$(ECHO) "DYN_ALL_BATCH_CMO=$(addprefix $(FRAMAC_LIBDIR)/, $(notdir $(ALL_BATCH_CMO)))" >> $@
	$(ECHO) "DYN_OLINKFLAGS=$(filter-out $(INCLUDES), $(OLINKFLAGS))" >> $@
	$(ECHO) "DYN_GEN_OPT_LIBS=$(addprefix $(FRAMAC_LIBDIR)/, $(notdir $(GEN_OPT_LIBS)))" >> $@
	$(ECHO) "DYN_OPT_LIBS=$(filter-out $(GEN_OPT_LIBS), $(OPT_LIBS))" >> $@
	$(ECHO) "DYN_ALL_BATCH_CMX=$(addprefix $(FRAMAC_LIBDIR)/, $(notdir $(ALL_BATCH_CMX)))" >> $@
	$(ECHO) "endif" >> $@
	$(CHMOD_RO) $@

#######
# GUI #
#######

ifneq ($(ENABLE_GUI),no)
GUI_INCLUDES = -I src/gui -I +lablgtk2
BYTE_GUI_LIBS+= lablgtk.cma
OPT_GUI_LIBS += lablgtk.cmxa
FILES_FOR_OCAMLDEP+= src/gui/*.ml src/gui/*.mli

ifeq ("$(OCAMLGRAPH_LOCAL)","")
GUI_INCLUDES += $(OCAMLGRAPH)
endif

ifeq ($(HAS_GNOMECANVAS),yes)
BYTE_GUI_LIBS += lablgnomecanvas.cma
OPT_GUI_LIBS += lablgnomecanvas.cmxa
endif

ifeq ($(HAS_LABLGTK),yes)
EXTRAS	+= gui
endif

ifeq ($(HAS_GTKSOURCEVIEW),yes)
ifeq ($(HAS_LEGACY_GTKSOURCEVIEW),yes)
GUI_INCLUDES  += -I +lablgtksourceview
endif
BYTE_GUI_LIBS += lablgtksourceview.cma
OPT_GUI_LIBS  += lablgtksourceview.cmxa
endif

src/gui/filetree.ml: Makefile

ifeq ($(HAS_LABLGTK_CUSTOM_MODEL),yes)
src/gui/filetree.ml: src/gui/filetree_custom.ml
	$(PRINT_MAKING) $@
	$(CP) $< $@
	$(CHMOD_RO) $@
else
src/gui/filetree.ml: src/gui/filetree_default.ml
	$(PRINT_MAKING) $@
	$(CP) $< $@
	$(CHMOD_RO) $@
endif
GENERATED += src/gui/filetree.ml

# NEW dynamic GUI
ifeq (no,yes)

PLUGIN_ENABLE:=$(ENABLE_GUI)
PLUGIN_NAME:=Gui
PLUGIN_DISTRIBUTED:=yes
# PLUGIN_HAS_MLI:=yes
PLUGIN_DIR:=src/gui
#PLUGIN_CMO:=
PLUGIN_CMO:= gtk_helper source_viewer pretty_source source_manager warning_manager \
	 filetree launcher design project_manager \
	 about_dialog
PLUGIN_BFLAGS:=-I +lablgtk2
PLUGIN_OFLAGS:=-I +lablgtk2
PLUGIN_LINK_BFLAGS:=-I +lablgtk2
PLUGIN_EXTRA_BYTE:=lablgtk.cma lablgtksourceview.cma
PLUGIN_EXTRA_OPT:=lablgtk.cmxa
PLUGIN_DYNAMIC:=yes

lablgtk.cma lablgtksourceview.cma:
lablgtk.cmxa:

include share/Makefile.plugin

gui: lib/plugins/Gui.cmo

else

GUICMO += gtk_helper source_viewer pretty_source source_manager warning_manager \
	 filetree launcher design project_manager \
	 about_dialog
GUICMO:= $(patsubst %, src/gui/%.cmo, $(GUICMO)) $(PLUGIN_GUI_CMO_LIST)

MODULES_TODOC+= $(addprefix src/gui/,$(addsuffix .mli,\
		gtk_helper source_viewer source_manager warning_manager \
		pretty_source filetree launcher design project_manager))

GUICMI = $(GUICMO:.cmo=.cmi)
GUICMX = $(GUICMO:.cmo=.cmx)

$(GUICMI) $(GUICMO) bin/viewer.byte$(EXE): BFLAGS+= $(GUI_INCLUDES)
$(GUICMX) bin/viewer.opt$(EXE): OFLAGS+= $(GUI_INCLUDES)

$(PLUGIN_DEP_GUI_CMO_LIST) $(PLUGIN_DYN_DEP_GUI_CMO_LIST): BFLAGS+= $(GUI_INCLUDES)
$(PLUGIN_DEP_GUI_CMX_LIST) $(PLUGIN_DYN_DEP_GUI_CMX_LIST): OFLAGS+= $(GUI_INCLUDES)

.PHONY:gui

gui: bin/viewer.byte$(EXE) bin/viewer.$(OCAMLBEST)$(EXE)

bin/viewer.byte$(EXE): BYTE_LIBS+=$(BYTE_GUI_LIBS) $(GRAPH_GUICMO)
bin/viewer.byte$(EXE): $(ALL_CMO) $(GRAPH_GUICMO) $(GUICMO) \
			$(GEN_BYTE_LIBS) \
			$(PLUGIN_DYN_CMO_LIST) $(PLUGIN_DYN_GUI_CMO_LIST)
	$(PRINT_LINKING) $@
	$(OCAMLC) $(BLINKFLAGS) -o $@ $(BYTE_LIBS) \
		$(CMO) \
		$(filter-out $(patsubst lib/gui/%.cmo, lib/plugins/%.cmo, $(PLUGIN_GUI_CMO_LIST)), $(PLUGIN_CMO_LIST)) \
		$(GUICMO) $(STARTUP_CMO)
	$(MAKE) install-gui FRAMAC_LIBDIR=lib/fc

bin/viewer.opt$(EXE): OPT_LIBS+= $(OPT_GUI_LIBS) $(GRAPH_GUICMX)
bin/viewer.opt$(EXE): $(ALL_CMX) $(GRAPH_GUICMX) $(GUICMX) \
			$(STARTUP_CMX) $(GEN_OPT_LIBS) $(GRAPH_GUIO) \
			$(PLUGIN_DYN_CMX_LIST) $(PLUGIN_DYN_GUI_CMX_LIST)
	$(PRINT_LINKING) $@
	$(OCAMLOPT) $(OLINKFLAGS) -o $@ $(OPT_LIBS) \
		$(CMX) \
		$(filter-out $(patsubst lib/gui/%.cmx, lib/plugins/%.cmx, $(PLUGIN_GUI_CMX_LIST)), $(PLUGIN_CMX_LIST)) \
		$(GUICMX) $(STARTUP_CMX)
	$(MAKE) install-gui FRAMAC_LIBDIR=lib/fc
endif
endif

#########################
# Standalone obfuscator #
#########################

obfuscator: bin/obfuscator.$(OCAMLBEST)

bin/obfuscator.byte$(EXE): $(ACMO) $(KERNEL_CMO) $(STARTUP_CMO) $(GEN_BYTE_LIBS)
	$(PRINT_LINKING) $@
	$(OCAMLC) $(BLINKFLAGS) -o $@ $(BYTE_LIBS) $^

bin/obfuscator.opt$(EXE): $(ACMX) $(KERNEL_CMX) $(STARTUP_CMX) $(GEN_OPT_LIBS)
	$(PRINT_LINKING) $@
	$(OCAMLOPT) $(OLINKFLAGS) -o $@ $(OPT_LIBS) $^

VERSION=$(shell $(SED) -e 's/\\(.*\\)/\\1/' VERSION)
CONFIG_DIR=src/kernel
CONFIG_FILE=$(CONFIG_DIR)/config.ml
CONFIG_CMO=$(CONFIG_DIR)/config.cmo
GENERATED +=$(CONFIG_FILE)

empty:=
space:=$(empty) $(empty)
$(CONFIG_FILE): VERSION share/Makefile.config Makefile
	$(PRINT_MAKING) $@
	$(RM) $@
	$(ECHO) "(* This file is generated by Makefile. Do not modify. *)" \
		> $@
	$(ECHO) "let version = \""$(VERSION)"\"" >> $@
	$(ECHO) "let date = \""`LC_ALL=C date`"\"" >> $@
	$(ECHO) "let is_gui = ref false" >> $@
	$(ECHO) "let datadir = try Sys.getenv \"FRAMAC_SHARE\" with Not_found -> \"$(FRAMAC_DATADIR)\"" >> $@
	$(ECHO) "let libdir = try Sys.getenv \"FRAMAC_LIB\" with Not_found -> \"$(FRAMAC_LIBDIR)\"" >> $@
	$(ECHO) "let plugin_dir = try Sys.getenv \"FRAMAC_PLUGIN\" with Not_found -> try (Sys.getenv \"FRAMAC_LIB\") ^ \"/plugins\" with Not_found -> \"$(FRAMAC_PLUGINDIR)\"" >> $@
	$(ECHO) "let static_plugins = [" \
		$(subst $(space),"; ",$(foreach p,$(PLUGIN_LIST),\"$(notdir $p)\")) \
		"]" >> $@
	$(ECHO) "let static_gui_plugins = [" \
		$(subst $(space),"; ",$(foreach p,$(PLUGIN_GUI_CMO_LIST),\"$(notdir $(patsubst %.cmo,%,$p))\")) \
		"]" >> $@
	$(CHMOD_RO) $@

#########
# Tests #
#########

.PHONY: tests oracles btests tests_dist
tests: byte opt ptests
	$(PRINT_EXEC) ptests
	time -p ./bin/ptests.byte$(EXE) $(PLUGIN_TESTS_LIST)
	for plugin in $(EXTERNAL_PLUGINS); do \
	$(MAKE) FRAMAC_LIBDIR=$(FRAMAC_SRC)/lib/fc FRAMAC_SHARE=$(FRAMAC_SRC)/share -C $$plugin tests; \
	done

oracles: opt ptests
	$(PRINT_MAKING) oracles
	./bin/ptests.byte$(EXE) $(PLUGIN_TESTS_LIST) > /dev/null 2>&1
	./bin/ptests.byte$(EXE) -update $(PLUGIN_TESTS_LIST)

btests: byte ptests
	$(PRINT_EXEC) ptests -byte
	time -p ./bin/ptests.byte$(EXE) -byte $(PLUGIN_TESTS_LIST)

tests_dist: dist ptests
	$(PRINT_EXEC) ptests
	time -p ./bin/ptests.byte$(EXE) $(PLUGIN_TESTS_LIST)

# test only one test suite : make suite_tests
%_tests: opt ptests
	$(PRINT_EXEC) ptests
	./bin/ptests.byte$(EXE) $($*_TESTS_OPTS) $*

# full test suite
wp_TESTS_OPTS=-j 1
fulltests: tests wp_tests

acsl_tests: byte
	$(PRINT_EXEC) acsl_tests
	find doc/speclang -name \*.c -exec ./bin/toplevel.byte$(EXE) {} \; > /dev/null

# Non-plugin test directories containing some ML files to compile
TEST_DIRS_AS_PLUGIN=dynamic dynamic_plugin journal saveload spec
PLUGIN_TESTS_LIST += $(TEST_DIRS_AS_PLUGIN)
$(foreach d,$(TEST_DIRS_AS_PLUGIN),$(eval $(call COMPILE_TESTS_ML_FILES,$d,,)))

# Testing of dynamic plug-ins
#############################

tests/dynamic/.cmi tests/dynamic/empty.cmifoo:tests/dynamic/empty.cmi
	$(CP) $< $@

tests/dynamic/.cmo tests/dynamic/empty.cmofoo:tests/dynamic/empty.cmo \
			tests/dynamic/.cmi tests/dynamic/empty.cmifoo
	$(CP) $< $@

tests/dynamic/Register_mod1.cmo:tests/dynamic_plugin/register_mod1.cmo
	$(OCAMLC) -o $@ -pack $^

tests/dynamic/Register_mod2.cmo:tests/dynamic_plugin/register_mod2.cmo
	$(OCAMLC) -o $@ -pack $^

tests/dynamic/Apply.cmo:tests/dynamic_plugin/apply.cmo
	$(OCAMLC) -o $@ -pack $^

DYNAMIC_TESTS_TARGETS=tests/dynamic/empty.cmo tests/dynamic/empty_gui.cmo \
	tests/dynamic/.cmo tests/dynamic/empty.cmofoo \
	tests/dynamic/Register_mod1.cmo tests/dynamic/Register_mod2.cmo \
	tests/dynamic/Apply.cmo tests/dynamic/abstract.cmo

.PHONY:tests/dynamic/all
tests/dynamic/all:
	$(QUIET_MAKE) $(DYNAMIC_TESTS_TARGETS)

##############
# Emacs tags #
##############

.PHONY: tags
# otags gives a better tagging of ocaml files than etags
ifdef OTAGS
tags:
	$(OTAGS) -r external src lib cil
vtags:
	$(OTAGS) -vi -r external src lib cil
else
tags:
	find . -name "*.ml[ily]" -o -name "*.ml" | sort -r | xargs \
	etags "--regex=/[ \t]*let[ \t]+\([^ \t]+\)/\1/" \
	      "--regex=/[ \t]*let[ \t]+rec[ \t]+\([^ \t]+\)/\1/" \
	      "--regex=/[ \t]*and[ \t]+\([^ \t]+\)/\1/" \
	      "--regex=/[ \t]*type[ \t]+\([^ \t]+\)/\1/" \
              "--regex=/[ \t]*exception[ \t]+\([^ \t]+\)/\1/" \
	      "--regex=/[ \t]*val[ \t]+\([^ \t]+\)/\1/" \
	      "--regex=/[ \t]*module[ \t]+\([^ \t]+\)/\1/"
endif

#################
# Documentation #
#################

.PHONY: wc doc doc-distrib

wc:
	ocamlwc -p external/*.ml* cil/*/*.ml cil/*/*.ml[ily] cil/src/*/*.ml[ily] cil/src/*/*.ml[ly] src/*/*.ml src/*/*.ml[iyl] 

# private targets, usefull for recompiling the doc without dependencies 
# (too long!)
.PHONY: doc-kernel doc-index plugins-doc doc-update doc-tgz

ifeq ("$(OCAMLDOC)","ocamldoc.opt")
DOC_PLUGIN=$(DOC_DIR)/docgen.cmxs
else
DOC_PLUGIN=$(DOC_DIR)/docgen.cmo
endif

$(DOC_DIR)/docgen.cmo: $(DOC_DIR)/docgen.ml
	$(PRINT_OCAMLC) $@
	$(OCAMLC) -c -I +ocamldoc -I $(CONFIG_DIR) $(DOC_DIR)/docgen.ml

$(DOC_DIR)/docgen.cmxs: $(DOC_DIR)/docgen.ml
	$(PRINT_PACKING) $@
	$(OCAMLOPT) -o $@ -shared -I +ocamldoc -I $(CONFIG_DIR) \
	  $(DOC_DIR)/docgen.ml

clean::
	$(PRINT_RM) $(DOC_DIR)/docgen.cm*
	$(RM) $(DOC_DIR)/docgen.cm*

DOC_NOT_FOR_DISTRIB=yes
plugins-doc: 
	$(QUIET_MAKE) \
	 $(if $(DOC_NOT_FOR_DISTRIB), $(PLUGIN_DOC_LIST), \
	   $(filter \
	     $(addsuffix _DOC, $(PLUGIN_DISTRIBUTED_NAME_LIST)), \
	     $(PLUGIN_DOC_LIST)))

# to make the documentation for one pluggin only,
# the name of the pluggin should begin with a capital letter :
# Example for the pdg doc : make Pdg_DOC
# While working on the documentation of a pluggin, it can also be usefull
# to use : make -o doc/code/kernel-doc.ocamldoc Plugin_DOC
# to avoid redoing the global documentation each time.

DOC_FLAGS:= -colorize-code -stars -inv-merge-ml-mli -m A -hide-warnings \
	$(INCLUDES) $(GUI_INCLUDES)

STDLIB_FILES:=map set pervasives big_int list array string char marshal \
	printf format scanf hashtbl buffer sys
STDLIB_FILES:=$(patsubst %, $(OCAMLLIB)/%.mli, $(STDLIB_FILES))

doc-kernel: #dependencies in doc target
	$(PRINT_DOC) Kernel Documentation
	$(MKDIR) $(DOC_DIR)/html
	$(RM) $(DOC_DIR)/html/*.html
	$(OCAMLDOC) $(DOC_FLAGS) -I $(OCAMLLIB) \
	  $(addprefix -stdlib , $(STDLIB_FILES)) \
	  -t "Frama-C Kernel" \
          -sort -css-style ../style.css \
	  -g $(DOC_PLUGIN) \
	  -d $(DOC_DIR)/html -dump $(DOC_DIR)/kernel-doc.ocamldoc \
	  $(MODULES_TODOC)

doc-index: #dependencies in doc target
	$(PRINT_MAKING) doc/code/index.html
	$(CAT)  $(DOC_DIR)/toc_head.htm $(DOC_DIR)/*.toc \
		$(DOC_DIR)/toc_tail.htm > $(DOC_DIR)/index.html

doc-update: doc-kernel plugins-doc doc-index

DOC_DEPEND=$(MODULES_TODOC) byte $(DOC_PLUGIN)
ifneq ($(ENABLE_GUI),no)
DOC_DEPEND+=bin/viewer.byte
endif
doc: $(DOC_DEPEND)
	$(QUIET_MAKE) doc-kernel plugins-doc doc-index

doc-tgz:
	$(PRINT_MAKING) frama-c-api.tar.gz
	cd $(DOC_DIR); \
	  $(TAR) zcf tmp.tgz index.html *.css *.png html \
	  $(foreach p, $(PLUGIN_DISTRIBUTED_NAME_LIST), \
	    $(notdir $($(p)_DOC_DIR)))
	$(MKDIR) frama-c-api
	$(RM) -r frama-c-api/*
	cd frama-c-api; $(TAR) zxf ../$(DOC_DIR)/tmp.tgz
	$(TAR) zcf frama-c-api.tar.gz frama-c-api
	$(RM) -r frama-c-api $(DOC_DIR)/tmp.tgz

doc-distrib: 
	$(QUIET_MAKE) clean-doc
	$(QUIET_MAKE) doc DOC_NOT_FOR_DISTRIB=
	$(QUIET_MAKE) doc-tgz

doc/db/db.tex: src/kernel/db.mli
	$(PRINT_DOC) $@
	$(MKDIR) $(dir $@)
	$(OCAMLDOC) $(INCLUDES) -I $(OCAMLLIB) \
	  -latex -noindex -latextitle 3,paragraph -notoc -noheader -notrailer \
	  -o $@ $<

# Could be optimized
.PHONY: db_doc
db_doc doc/db/db.pdf: doc/db/main.tex doc/db/main.bib doc/db/db.tex
	$(PRINT_MAKING) doc/db/db.pdf
	cd $(dir $@); \
	  pdflatex $(notdir $<); bibtex main; \
	  pdflatex $(notdir $<); pdflatex $(notdir $<); \
	  mv main.pdf $(notdir $@)

#find src -name "*.ml[i]" -o -name "*.ml" -maxdepth 3 | sort -r | xargs
dots: $(ALL_CMO)
	$(PRINT_DOC) callgraph
	$(OCAMLDOC) $(INCLUDES) -o doc/call_graph.dot \
	  -dot -dot-include-all -dot-reduce $(MODULES_TODOC)
	$(QUIET_MAKE) doc/call_graph.svg
	$(QUIET_MAKE) doc/call_graph.ps

datatype_dependencies.dot computation_dependencies.dot: ./bin/toplevel.byte$(EXE)
	$(PRINT_MAKING) $@
	./bin/toplevel.byte$(EXE) -project-debug -dump \
	  > /dev/null 2> /dev/null

.PHONY:display_dependencies
display_dependencies: datatype_dependencies.svg computation_dependencies.svg
	inkscape datatype_dependencies.svg computation_dependencies.svg &

oug:
	echo $(ALL_CMX) $(STARTUP_CMX) > cmx.files
	rpl ".cmx" ".ml" cmx.files
	cp cmx.files ml0.files
	rpl ".ml" ".mli" cmx.files
	cat cmx.files >> ml0.files
	(ls -U `cat ml0.files` | grep -v sparecode > ml.files | true)
	cp ml.files files
	oug.x --debug 0 -I `ocamlc -where` $(INCLUDES) -I src/value -I src/pdg -I src/slicing -I src/security -I +lablgtk2 --no-reduce --dump dump.oug `cat files`
	oug.x --load dump.oug --no-reduce --useless-elements useless.txt --aliases-used --print-loc --progress
	oug.x --load dump.oug --useless-elements useless-reduced.txt --aliases-used --print-loc --progress

metrics:
	$(PRINT) Computing metrics
	ocamlmetrics -max-mi 75 -worst-modules 10 -worst-functions 25 \
		$(filter-out $(GENERATED), $(patsubst cil/%,, $(patsubst lib/%,,$(ALL_CMO:.cmo=.ml)))) \
		> doc/metrics.html

################
# Installation #
################

FILTER_INTERFACE_DIRS:=lib/plugins src/gui

ifeq ("$(OCAMLGRAPH_LOCAL)","")
FILTER_INTERFACE_DIRS+= +ocamlgraph
endif

.PHONY: install-kernel-byte install-kernel-opt install-gui

.install-kernel-byte: $(ALL_BATCH_CMO) $(GEN_BYTE_LIBS)
	$(MAKE) install-kernel-byte

install-kernel-byte:
	$(PRINT_CP) bytecode kernel API
	$(MKDIR) $(FRAMAC_LIBDIR)
#       line below does not work if INCLUDES contains twice the same directory
#       Do not attempt to copy gui interfaces if gui is disabled
	$(CP) $(wildcard $(foreach d,$(filter-out $(FILTER_INTERFACE_DIRS),$(INCLUDES:-I%=%)), $(d)/*.cmi)) $(FRAMAC_LIBDIR)
	$(CP) $(ALL_BATCH_CMO) $(filter-out %.o, $(GEN_BYTE_LIBS:.cmo=.cmi)) \
		$(GEN_BYTE_LIBS) $(FRAMAC_LIBDIR)
	touch .install-kernel-byte

install-kernel-opt: .install-kernel-byte
	$(PRINT_CP) native kernel API
	$(CP) $(ALL_BATCH_CMX) $(ALL_BATCH_CMX:.cmx=.o) $(FRAMAC_LIBDIR)
	$(CP) $(filter-out %.o, $(GEN_OPT_LIBS)) $(GEN_OPT_LIBS:.cmx=.o) \
		$(FRAMAC_LIBDIR)

install-gui:
	$(PRINT_CP) gui API
	$(MKDIR) $(FRAMAC_LIBDIR)
	if [ "$(ENABLE_GUI)" != "no" ]; then \
	  $(CP) src/gui/*.cmi $(FRAMAC_LIBDIR); \
        fi

.PHONY: install
install:
	$(PRINT_MAKING) destination directories
	$(MKDIR) $(BINDIR)
	$(MKDIR) $(MANDIR)/man1
	$(MKDIR) $(FRAMAC_PLUGINDIR)/gui
	$(MKDIR) $(FRAMAC_DATADIR)
	$(PRINT_CP) shared files
	$(CP) -R share/frama-c.rc share/*.c share/*.h share/why \
	  share/Makefile.dynamic share/Makefile.plugin share/Makefile.kernel \
	  share/Makefile.config share/Makefile.common \
	  $(FRAMAC_DATADIR)
	$(CP) share/Makefile.dynamic_config.external \
              $(FRAMAC_DATADIR)/Makefile.dynamic_config
	$(PRINT_CP) binaries
	$(CP) bin/toplevel.$(OCAMLBEST) $(BINDIR)/frama-c$(EXE)
	$(CP) bin/toplevel.byte$(EXE) $(BINDIR)/frama-c.byte$(EXE)
	if [ -x bin/toplevel.top ] ; then \
          $(CP) bin/toplevel.top $(BINDIR)/frama-c.toplevel$(EXE); \
	fi
	if [ -x bin/viewer.$(OCAMLBEST) ] ; then \
	  $(CP) bin/viewer.$(OCAMLBEST) $(BINDIR)/frama-c-gui$(EXE);\
	fi
	if [ -x bin/viewer.byte$(EXE) ] ; then \
	  $(CP) bin/viewer.byte$(EXE) $(BINDIR)/frama-c-gui.byte$(EXE); \
	fi
	$(CP) bin/ptests.byte$(EXE) $(BINDIR)/ptests.byte$(EXE)
	$(CP) ptests/ptests_config.cmi $(FRAMAC_LIBDIR)
	$(PRINT_CP) manuals
	if [ -d doc/manuals ]; then $(CP) -R doc/manuals $(FRAMAC_DATADIR); fi
	$(PRINT_CP) dynamic plug-ins
	if [ -d lib/plugins -a "$(PLUGIN_DYN_EXISTS)" = "yes" ]; then \
	  $(CP)  $(PLUGIN_DYN_CMO_LIST) $(PLUGIN_DYN_CMX_LIST) \
		 $(FRAMAC_PLUGINDIR); \
	fi
	$(PRINT_CP) dynamic gui plug-ins
	if [ -d lib/gui -a "$(PLUGIN_DYN_GUI_EXISTS)" = "yes" ]; then \
	  $(CP)  $(PLUGIN_DYN_GUI_CMO_LIST) $(PLUGIN_DYN_GUI_CMX_LIST) \
		 $(FRAMAC_PLUGINDIR)/gui; \
	fi
	$(MAKE) install-kernel-byte install-kernel-opt
	$(MAKE) install-gui
	$(PRINT_CP) man pages
	$(CP) man/frama-c.1 $(MANDIR)/man1
	$(CP) man/frama-c.1 $(MANDIR)/man1/frama-c-gui.1
	for plugin in $(EXTERNAL_PLUGINS); do \
	  $(MAKE) FRAMAC_LIBDIR=$(FRAMAC_LIBDIR) FRAMAC_SHARE=$(FRAMAC_SRC)/share -C $$plugin install; \
	done

.PHONY: uninstall
uninstall:
	$(PRINT_RM) installed binaries
	$(RM) $(BINDIR)/frama-c* $(BINDIR)/ptests.byte
	$(PRINT_RM) installed shared files
	$(RM) -R $(FRAMAC_DATADIR)
	$(PRINT_RM) installed libraries
	$(RM) -R $(FRAMAC_LIBDIR) $(FRAMAC_PLUGINDIR)
	for plugin in $(EXTERNAL_PLUGINS); do \
	$(MAKE) FRAMAC_LIBDIR=$(FRAMAC_LIBDIR) FRAMAC_SHARE=$(FRAMAC_SRC)/share -C $$plugin uninstall; \
	done

################################
# File headers: license policy #
################################

MODIFIED_MENHIR=external/ptmap.ml*

CIL	= cil/ocamlutil/*.ml* cil/ocamlutil/perfcount.c.in \
	cil/src/*.ml* \
	cil/src/ext/*.ml* cil/src/ext/pta/*.ml* \
	cil/src/frontc/*.ml*

CEA_INRIA_LGPL	= Makefile configure.in config.h.in \
	src/logic/*.ml* \
	cil/src/logic/*.ml* \
	src/pdg_types/*.ml* src/pdg/*.ml* doc/code/intro_pdg.txt \
	src/slicing_types/*.ml* src/slicing/*.ml* doc/code/intro_slicing.txt \
	src/scope/*.ml* doc/code/intro_scope.txt \
	src/sparecode/*.ml* doc/code/intro_sparecode.txt \
	src/wp/*.ml* doc/code/intro_wp.txt \
	share/why/*.why \
	man/frama-c.1

INRIA_LGPL=
INRIA_BSD= external/unmarshal*.ml*
INSA_INRIA_LGPL= src/ltl_to_acsl/*.ml* src/ltl_to_acsl/Makefile

CEA_LGPL= share/Makefile.config.in share/Makefile.common \
	share/Makefile.plugin share/Makefile.dynamic \
	share/Makefile.dynamic_config.internal \
	share/Makefile.dynamic_config.external \
	share/configure.ac configure.ml \
	share/*.c share/*.h \
	share/libc/*.c share/libc/*.h \
	share/frama-c.rc \
	src/ai/*.ml* \
	src/buckx/*.ml* src/buckx/*.[cS] \
	src/constant_propagation/*.ml* \
	src/from/*.ml* \
	src/gui/*.ml* \
	src/inout/*.ml* \
	src/impact/*.ml* \
	src/kernel/*.ml* \
	src/lib/*.ml* \
	src/memory_state/*.ml* \
	src/metrics/*.ml* \
	src/misc/*.ml* \
	src/occurrence/*.ml* doc/code/intro_occurrence.txt \
	src/postdominators/*.ml* \
	src/project/*.ml* \
	src/security/*.ml* \
	src/semantic_callgraph/*.ml* \
	src/syntactic_callgraph/*.ml* \
	src/toplevel/*.ml* \
	src/users/*.ml* \
	src/value/*.ml* \
	src/a3export/*.ml* src/a3export/Makefile \
	src/dummy/*/*.ml* \
	src/dummy/*/Makefile \
	ptests/*.ml* \
	doc/code/docgen.ml \
	doc/code/style.css \
	doc/code/intro_plugin.txt \
	doc/code/toc_head.htm doc/code/toc_tail.htm \
	bin/lithium2beryllium.sh

CEA_PROPRIETARY:= src/modular_dependencies/*.ml* \
        share/*.cc share/miel-mode.el \
	src/mthread/*.ml*

LICENSES= MODIFIED_MENHIR CEA_LGPL CEA_PROPRIETARY CEA_INRIA_LGPL INRIA_LGPL \
	CIL MODIFIED_CAMLLIB INSA_INRIA_LGPL INRIA_BSD

.PHONY: headers
headers: clean
	@echo "Applying Headers..."
	$(foreach l,$(LICENSES),\
	$(foreach f,$($l),$(shell $(HEADACHE) -c share/headache_config -h headers/$l $f)))

NO_CHECK_HEADERS=cil/doc/* cil/doc/*/* tests/*/* doc/manuals/*.pdf \
	         doc/README cil/LICENSE cil/CHANGES Changelog .make* \
	         licenses/* VERSION INSTALL bin/sed* src/lib/rangemap.ml

.PHONY: check-headers
check-headers: clean
	@echo "Checking Headers..."
	$(foreach f,$(wildcard $(DISTRIB_FILES)),\
	  $(if $(findstring $(f),\
	          $(wildcard $(NO_CHECK_HEADERS)) \
	          $(wildcard $(foreach l,$(LICENSES),$(value $l)))),,\
               echo "file $(f) does not have a proper license";))

########################################################################
# Makefile is rebuilt whenever Makefile.in or configure.in is modified #
########################################################################

share/Makefile.config: share/Makefile.config.in config.status
	$(PRINT_MAKING) $@
	./config.status

share/Makefile.dynamic_config: share/Makefile.dynamic_config.internal
	$(PRINT_MAKING) $@
	$(RM) $@
	$(CP) $< $@
	$(CHMOD_RO) $@

config.status: configure
	$(PRINT_MAKING) $@
	./config.status --recheck

configure: configure.in
	$(PRINT_MAKING) $@
	autoconf

$(PERFCOUNT).c: $(PERFCOUNT).c.in
$(PERFCOUNT).c.in:
	./configure

# If 'make clean' have to be performed after 'cvs update':
# change '.make-clean-stamp' before 'cvs commit'
.make-clean: .make-clean-stamp
	touch $@
	$(QUIET_MAKE) clean

include .make-clean

# force "make clean" to be executed for all users of CVS
force-clean:
	expr `$(CAT) .make-clean-stamp` + 1 > .make-clean-stamp

############
# cleaning #
############

clean-journal:
	$(PRINT_RM) journal
	$(RM) frama_c_journal*

clean-tests:
	$(PRINT_RM) tests
	$(RM) tests/*/*.byte$(EXE) tests/*/*.opt$(EXE) tests/*/*.cm* \
		tests/dynamic/.cm* tests/*/*~ tests/*/#*
	$(RM) tests/*/result/*.*

clean-doc: $(PLUGIN_LIST:=_CLEAN_DOC)
	$(PRINT_RM) documentation
	$(RM) -r $(DOC_DIR)/html
	$(RM) $(DOC_DIR)/docgen.cm* $(DOC_DIR)/*~
	$(RM) doc/db/*~ doc/db/ocamldoc.sty doc/db/db.tex
	$(RM) doc/training/*/*.cm*
	if [ -f doc/developer/Makefile ]; then \
	  $(MAKE) --silent -C doc/developer clean; \
	fi
	if [ -f doc/architecture/Makefile ]; then \
	  $(MAKE) --silent -C doc/architecture clean; \
	fi
	if [ -f doc/speclang/Makefile ]; then \
	  $(MAKE)  --silent -C doc/speclang clean; \
	fi
	if [ -f doc/www/src/Makefile ]; then \
	  $(MAKE) --silent -C doc/www/src clean; \
	fi

clean-gui::
	$(PRINT_RM) gui
	$(RM) src/*/*_gui.cm* src/*/*_gui.o src/gui/*.cm* src/gui/*.o

clean:: $(PLUGIN_LIST:=_CLEAN) $(PLUGIN_DYN_LIST:=_CLEAN) \
		clean-tests clean-journal
	$(PRINT_RM) plugins
	$(RM) $(PLUGIN_GENERATED_LIST)
	$(RM) $(PLUGIN_LIB_DIR)/*.mli $(PLUGIN_LIB_DIR)/*.cm* \
	  $(PLUGIN_LIB_DIR)/*.o
	$(RM) $(PLUGIN_GUI_LIB_DIR)/*.mli $(PLUGIN_GUI_LIB_DIR)/*.cm* \
	  $(PLUGIN_GUI_LIB_DIR)/*.o
	$(PRINT_RM) local installation
	$(RM) lib/*.cm* lib/*.o lib/fc/*.cm* lib/fc/*.o lib/gui/*.cm* lib/*.cm*
	$(PRINT_RM) other sources
	for d in . $(SRC_DIRS) src/gui share; do \
	  $(RM) $$d/*.cm* $$d/*.o $$d/*.a $$d/*.annot $$d/*~ $$d/*.output \
	   	$$d/*.annot $$d/\#*; \
	done
	$(PRINT_RM) generated files
	$(RM) $(GENERATED)
	$(RM) ptests_config.* # temporary clean-up of svn version
	$(PRINT_RM) binaries
	$(RM) bin/*.byte$(EXE) bin/*.opt$(EXE) bin/*.top$(EXE)

distclean-ocamlgraph:
	$(PRINT_RM) ocamlgraph
	if [ -f ocamlgraph/Makefile ]; then \
	  $(MAKE) --silent -C ocamlgraph distclean; \
	fi

dist-clean distclean:: clean clean-doc distclean-ocamlgraph
	$(PRINT_RM) config
	$(RM) share/Makefile.config
	$(RM) config.cache config.log config.h
	$(PRINT_RM) dummy plug-ins
	$(RM) src/dummy/*/*.cm* src/dummy/*/*.o src/dummy/*/*.a \
		src/dummy/*/*.annot src/dummy/*/*~ src/dummy/*/*.output \
	   	src/dummy/*/*.annot src/dummy/*/\#*

##########
# Depend #
##########

GENERATED+=ptests/ptests_config.ml
PLUGIN_DEP_LIST:=$(PLUGIN_LIST) $(PLUGIN_DYN_LIST)

.PHONY: depend
.depend: $(PLUGIN_DEP_LIST:%=%_DEP)
depend:  $(PLUGIN_DEP_LIST:%=%_DEP_REDO)

.depend depend: $(GENERATED) share/Makefile.dynamic_config share/Makefile.kernel
	$(PRINT_MAKING) .depend
	$(RM) .depend
	if test "$(PLUGIN_DEP_LIST)" != ""; then \
	  $(CAT) $(foreach d, $(PLUGIN_DEP_LIST), $(dir $d).depend) > .depend; \
	fi
	$(OCAMLDEP) $(DEP_FLAGS) $(FILES_FOR_OCAMLDEP) >> .depend
	$(CHMOD_RO) .depend
	for plugin in $(EXTERNAL_PLUGINS); do \
	$(MAKE) FRAMAC_LIBDIR=$(FRAMAC_SRC)/lib/fc FRAMAC_SHARE=$(FRAMAC_SRC)/share -C $$plugin depend; \
	done

include .depend

#####################
# ptest development #
#####################

.PHONY: ptests

# Because Ocaml on MacOS X has issues with native threads
ptests: bin/ptests.byte$(EXE)

PTESTS_SRC=ptests/ptests_config.ml ptests/ptests.ml

ifeq ($(OCAMLWIN32),yes)
# OCaml on Win32 does not support vmthreads, use native ones.
bin/ptests.byte$(EXE): $(PTESTS_SRC)
	$(PRINT_LINKING) $@
	$(OCAMLC) -I ptests -dtypes -thread -g -o $@ \
            unix.cma threads.cma str.cma dynlink.cma $^
else
bin/ptests.byte$(EXE): $(PTESTS_SRC)
	$(PRINT_LINKING) $@
	$(OCAMLC) -I ptests -dtypes -vmthread -g -o $@ \
            unix.cma threads.cma str.cma dynlink.cma $^
endif

#bin/ptests.opt$(EXE): $(PTESTS_SRC)
#	$(PRINT_LINKING) $@
#	$(OCAMLOPT) -I ptests -dtypes -thread -o $@ \
#            unix.cmxa threads.cmxa str.cmxa dynlink.cmxa $^

ptests/ptests_config.ml: Makefile
	$(PRINT_MAKING) $@
	$(RM) $@
	$(ECHO) \
         "let default_suites = ref [" $(PLUGIN_TESTS_LIST:%='"%";') "];;" > $@
	$(ECHO) \
	 "let no_native_dynlink = " \
         $(subst yes,false,$(subst no,true,$(USABLE_NATIVE_DYNLINK))) ";;" \
	 >> $@
	$(ECHO) \
	"let toplevel_path = ref \"bin/toplevel.$(OCAMLBEST)$(EXE)\";;" >> $@
	$(ECHO) \
	"let framac_share = ref (Filename.concat Filename.current_dir_name \
\"share\");;" >> $@
	$(ECHO) \
	"let framac_plugin = ref \
(Filename.concat (Filename.concat Filename.current_dir_name \"lib\")\
 \"plugins\");;" >> $@
	$(ECHO) \
	"let framac_plugin_gui = ref \
(Filename.concat (Filename.concat Filename.current_dir_name \"lib\")\
 \"gui\");;" >> $@
	$(CHMOD_RO) $@

GENERATED+=ptests/ptests_config.ml

#######################
# Source distribution #
#######################

STANDALONE_PLUGINS_FILES = \
	$(addprefix src/dummy/hello_world/, hello_world.ml Makefile) \
	$(addprefix src/dummy/untyped_metrics/, count_for.ml Makefile)

DISTRIB_FILES+= $(PLUGIN_DISTRIBUTED_LIST) $(PLUGIN_DIST_DOC_LIST) $(STANDALONE_PLUGINS_FILES)

EXPORT=frama-c-$(VERSION)

src-distrib: src-distrib-ocamlgraph $(PLUGIN_DIST_EXTERNAL_LIST)
	$(PRINT_TAR) tmp-distrib
	$(TAR) cf tmp.tar $(DISTRIB_FILES)
	$(PRINT_MAKING) export directories
	$(MKDIR) $(EXPORT)/bin
	$(MKDIR) $(EXPORT)/lib/plugins
	$(MKDIR) $(EXPORT)/lib/gui
	$(MKDIR) $(EXPORT)/external
	$(PRINT_UNTAR) tmp-distrib
	cd $(EXPORT); $(TAR) xf ../tmp.tar;
	$(PRINT_RM) tmp-distrib
	$(RM) tmp.tar
	$(PRINT_MAKING) test directories
	for dir in $(EXPORT)/tests/*; do \
	  $(MKDIR) $$dir/result; \
	  $(MKDIR) $$dir/oracle; \
        done
	$(PRINT_MAKING) archive
	$(TAR) czf frama-c-src.tar.gz $(EXPORT)
	$(PRINT) Cleaning
	$(RM) -fr $(EXPORT)

bin-distrib: depend configure Makefile
	$(PRINT_MAKING) bin-distrib
	$(RM) -r $(VERSION)
	./configure $(CONFIG_DISTRIB_BIN)
	$(QUIET_MAKE)
	$(QUIET_MAKE) DESTDIR=$(FRAMAC_SRC)/$(VERSION) install
	$(CP) README $(VERSION)

clean-distrib: dist-clean
	$(PRINT_RM) distrib
	$(RM) -r $(EXPORT) $(EXPORT).tar.gz

ifeq ($(OCAMLGRAPH_LOCAL),"")
src-distrib-ocamlgraph:
	$(PRINT_MAKING) distrib-ocamlgraph
	@ $(ECHO) "Cannot make distrib tar ball without local ocamlgraph installation"
	@ exit 2
else
src-distrib-ocamlgraph:
	$(PRINT_MAKING) distrib-ocamlgraph
	$(MKDIR) $(EXPORT)
	$(CP) ocamlgraph.tar.gz $(EXPORT)
endif

###############################################################################
# Local Variables:
# compile-command: "LC_ALL=C make"
# End:
