#**************************************************************************
#*                                                                        *
#*                                 OCaml                                  *
#*                                                                        *
#*            Gabriel Scherer, projet Parsifal, INRIA Saclay              *
#*                                                                        *
#*   Copyright 2018 Institut National de Recherche en Informatique et     *
#*     en Automatique.                                                    *
#*                                                                        *
#*   All rights reserved.  This file is distributed under the terms of    *
#*   the GNU Lesser General Public License version 2.1, with the          *
#*   special exception on linking described in the file LICENSE.          *
#*                                                                        *
#**************************************************************************

# This makefile contains common definitions and rules shared by
# other Makefiles

include $(ROOTDIR)/Makefile.config_if_required

# %(DEPDIR) must be kept in sync with entries in .gitignore
DEPDIR=.dep
D=d
MKDIR=mkdir -p

# $(EMPTY) is defined in Makefile.config, but may not have been loaded
EMPTY :=
# $(SPACE) contains a single space
SPACE := $(EMPTY) $(EMPTY)
# $( ) suppresses warning from the alignments in the V_ macros below
$(SPACE) :=

ifeq "$(UNIX_OR_WIN32)" "win32"
DIR_SEP := \$ # There must a space following the $
CONVERT_PATH = $(subst /,$(DIR_SEP),$(strip $(1)))
else
DIR_SEP = /
CONVERT_PATH = $(strip $(1))
endif

V ?= 0

ifeq "$(V)" "0"

V_CC         = @$(info $   CC $@)
V_CCDEPS     = @$(info $   CCDEPS $@)
V_OCAMLC     = @$(info $   OCAMLC $@)
V_OCAMLOPT   = @$(info $   OCAMLOPT $@)
V_GEN        = @$(info $   GEN $@)
V_LINKC      = @$(info $   LINKC $@)
V_LINKOPT    = @$(info $   LINKOPT $@)
V_MKEXE      = @$(info $   MKEXE $@)
V_MKLIB      = @$(info $   MKLIB $@)
V_MKDLL      = @$(info $   MKDLL $@)
V_OCAMLLEX   = @$(info $   OCAMLLEX $@)
V_OCAMLYACC  = @$(info $   OCAMLYACC $@)
V_OCAMLDEP   = @$(info $   OCAMLDEP $@)
V_ASM        = @$(info $   ASM $@)
V_OCAMLMKLIB = @$(info $   OCAMLMKLIB $@)
V_OCAMLDOC   = @$(info $   OCAMLDOC $@)
V_ODOC       = @$(info $   ODOC $@)

else

V_CC         =
V_CCDEPS     =
V_OCAMLC     =
V_OCAMLOPT   =
V_GEN        =
V_LINKC      =
V_LINKOPT    =
V_MKEXE      =
V_MKLIB      =
V_MKDLL      =
V_OCAMLLEX   =
V_OCAMLYACC  =
V_OCAMLDEP   =
V_ASM        =
V_OCAMLMKLIB =
V_OCAMLDOC   =
V_ODOC       =

endif

DESTDIR ?=
INSTALL_BINDIR := $(DESTDIR)$(BINDIR)
INSTALL_LIBDIR := $(DESTDIR)$(LIBDIR)
INSTALL_INCDIR=$(INSTALL_LIBDIR)/caml
INSTALL_STUBLIBDIR := $(DESTDIR)$(STUBLIBDIR)
INSTALL_LIBDIR_PROFILING = $(INSTALL_LIBDIR)/profiling
INSTALL_MANDIR := $(DESTDIR)$(MANDIR)
INSTALL_PROGRAMS_MAN_DIR := $(DESTDIR)$(PROGRAMS_MAN_DIR)
INSTALL_LIBRARIES_MAN_DIR := $(DESTDIR)$(LIBRARIES_MAN_DIR)
INSTALL_DOCDIR := $(DESTDIR)$(DOCDIR)

FLEXDLL_SUBMODULE_PRESENT := $(wildcard $(ROOTDIR)/flexdll/Makefile)

IN_COREBOOT_CYCLE ?= false

# Variables used to represent the OCaml runtime system
# Most of the time, boot/ocamlrun and runtime/ocamlrun are the same.
# However, under some circumstances it is important to be able to
# distinguish one from the other, hence these two variables.
# Boot/ocamlrun is the most frequently used in the build system, so
# we use OCAMLRUN to designate it and keep NEW_OCAMLRUN to refer
# to runtime/ocamlrun, because it's less frequently used.
OCAMLRUN ?= $(ROOTDIR)/boot/ocamlrun$(EXE)
NEW_OCAMLRUN ?= $(ROOTDIR)/runtime/ocamlrun$(EXE)

# Standard library flags
STDLIBFLAGS ?= -nostdlib -I $(ROOTDIR)/stdlib
BOOT_STDLIBFLAGS ?= -nostdlib -I $(ROOTDIR)/boot

TEST_BOOT_OCAMLC_OPT = $(shell \
  test $(ROOTDIR)/boot/ocamlc.opt -nt $(ROOTDIR)/boot/ocamlc; \
  echo $$?)

# Use boot/ocamlc.opt if available
ifeq "$(TEST_BOOT_OCAMLC_OPT)" "0"
  BOOT_OCAMLC = $(ROOTDIR)/boot/ocamlc.opt
else
  BOOT_OCAMLC = $(OCAMLRUN) $(ROOTDIR)/boot/ocamlc
endif

BOOT_OCAMLDEP = $(BOOT_OCAMLC) -depend

# Takes an implicit path and converts it to a path expression which returns to
# the current directory. e.g. $(call ROOT_FROM, foo/bar/) expands to ../..
REMOVE_SLASH = $(strip $(patsubst %/,%, $(1)))
ROOT_FROM = \
  $(subst $(SPACE),/,$(patsubst %,..,$(subst /, ,$(call REMOVE_SLASH, $(1)))))

BYTE_BUILD_TREE = byte
OPT_BUILD_TREE = opt

BYTE_BINDIR = $(BYTE_BUILD_TREE)/bin
OPT_BINDIR = $(OPT_BUILD_TREE)/bin

ifeq "$(BOOTSTRAPPING_FLEXDLL)" "true"
  override REAL_ROOT_DIR := $(realpath $(ROOTDIR))
ifeq "$(filter $(REAL_ROOT_DIR)/$(BYTE_BINDIR), $(subst :, ,$(PATH)))" ""
  export PATH := \
    $(REAL_ROOT_DIR)/$(OPT_BINDIR):$(REAL_ROOT_DIR)/$(BYTE_BINDIR):$(PATH)
endif
  undefine REAL_ROOT_DIR
endif

# List of other libraries
ALL_OTHERLIBS = dynlink str systhreads unix runtime_events

# Flags to pass to the C preprocessor when preprocessing assembly files
OC_ASPPFLAGS=$(OC_CPPFLAGS) $(OC_NATIVE_CPPFLAGS)

OPTCOMPFLAGS=
ifeq "$(FUNCTION_SECTIONS)" "true"
OPTCOMPFLAGS += -function-sections
endif

# The rule to compile C files

# This rule is similar to GNU make's implicit rule, except that it is more
# general (it supports both .o and .obj)

ifeq "$(COMPUTE_DEPS)" "true"
RUNTIME_HEADERS :=
REQUIRED_HEADERS :=
else
RUNTIME_HEADERS := $(wildcard $(ROOTDIR)/runtime/caml/*.tbl) \
                   $(wildcard $(ROOTDIR)/runtime/caml/*.h)
REQUIRED_HEADERS := $(RUNTIME_HEADERS) $(wildcard *.h)
endif

%.$(O): %.c $(REQUIRED_HEADERS)
	$(V_CC)$(CC) -c $(OC_CFLAGS) $(CFLAGS) $(OC_CPPFLAGS) $(CPPFLAGS) \
	  $(OUTPUTOBJ)$@ $<

$(DEPDIR):
	$(MKDIR) $@

# When executable files have an extension (e.g. ".exe"),
# provide phony synonyms
define PROGRAM_SYNONYM
ifneq ($(EXE),)
.PHONY: $(1)
$(1): $(1)$(EXE)
endif
endef # PROGRAM_SYNONYM

# Definitions related to ocamldep

# Default value for OCAMLDEP
# In those directories where this needs to be overridden, the overriding
# should take place *before* Makefile.common is included.

OCAMLDEP ?= $(BEST_OCAMLDEP)
OCAMLDEPFLAGS ?=
OC_OCAMLDEPFLAGS = -slash
OC_OCAMLDEPDIRS =
OCAMLDEP_CMD = $(OCAMLDEP) $(OC_OCAMLDEPFLAGS) \
  $(addprefix -I ,$(OC_OCAMLDEPDIRS)) $(OCAMLDEPFLAGS)

# Lexer generation

BOOT_OCAMLLEX ?= $(OCAMLRUN) $(ROOTDIR)/boot/ocamllex

# Default value for OCAMLLEX
# In those directories where this needs to be overridden, the overriding
# should take place *before* Makefile.common is included.

OCAMLLEX ?= $(BEST_OCAMLLEX)

OCAMLLEXFLAGS ?= -q

%.ml: %.mll
	$(V_OCAMLLEX)$(OCAMLLEX) $(OCAMLLEXFLAGS) $<

# Parser generation

OCAMLYACC ?= $(ROOTDIR)/yacc/ocamlyacc$(EXE)

OCAMLYACCFLAGS ?= --strict -v

%.ml %.mli: %.mly
	$(V_OCAMLYACC)$(OCAMLYACC) $(OCAMLYACCFLAGS) $<

SAK = $(ROOTDIR)/runtime/sak$(EXE)

# Used with the Microsoft toolchain to merge generated manifest files into
# executables
if_file_exists = ( test ! -f $(1) || $(2) && rm -f $(1) )
MERGEMANIFESTEXE = $(call if_file_exists, $(1).manifest, \
  mt -nologo -outputresource:$(1) -manifest $(1).manifest)

# Macros and rules to compile OCaml programs and libraries

# The following variable is used to accumulate a list of all the CMX
# files that get built. Is is then used in the root Makefile to express
# the dependency on all these files on the native compiler, so that
# they get rebuilt if the native compiler is updated

ALL_CMX_FILES =

# We use secondary expansion here so that variables like
# foo_LIBRARIES and foo_SOURCES can be defined after the calls
# to the macros below. Without secondary expansion, those variables
# would have to be defined before the calls to OCAML_BYTECODE_PROGRAM etc.

.SECONDEXPANSION:

# Definitions that are common to both programs and libraries

define _OCAML_COMMON_BASE
$(basename $(notdir $(1)))_C_FILES = \
  $$(filter %.c, $$($(basename $(notdir $(1)))_SOURCES))
$(basename $(notdir $(1)))_MLI_FILES = \
  $$(filter %.mli, \
    $$(subst .mly,.mli,\
      $$($(basename $(notdir $(1)))_SOURCES)))
$(basename $(notdir $(1)))_CMI_FILES = \
  $$(subst .mli,.cmi,$$($(basename $(notdir $(1)))_MLI_FILES))
$(basename $(notdir $(1)))_ML_FILES = \
  $$(filter %.ml, \
    $$(subst .ml.in,.ml,$$(subst .mll,.ml,$$(subst .mly,.ml,\
      $$($(basename $(notdir $(1)))_SOURCES)))))
$(basename $(notdir $(1)))_MLL_FILES = \
  $$(filter %.mll, \
    $$($(basename $(notdir $(1)))_SOURCES))
$(basename $(notdir $(1)))_MLY_FILES = \
  $$(filter %.mly, \
    $$($(basename $(notdir $(1)))_SOURCES))
$(basename $(notdir $(1)))_SECONDARY_FILES = \
  $$(patsubst %.mll,%.ml, $$($(basename $(notdir $(1)))_MLL_FILES)) \
  $$(patsubst %.mly,%.mli, $$($(basename $(notdir $(1)))_MLY_FILES)) \
  $$(patsubst %.mly,%.ml, $$($(basename $(notdir $(1)))_MLY_FILES))
.SECONDARY: $$$$($(basename $(notdir $(1)))_SECONDARY_FILES)
beforedepend:: $$$$($(basename $(notdir $(1)))_SECONDARY_FILES)
$(basename $(notdir $(1)))_GENERATED_FILES = \
  $$($(basename $(notdir $(1)))_SECONDARY_FILES) \
  $$(patsubst %.mly,%.output, $$($(basename $(notdir $(1)))_MLY_FILES))
endef # _OCAML_COMMON_BASE

# Macros to build OCaml programs

# Each program foo is characterised by the foo_LIBRARIES and foo_SOURCES
# variables. The following macros provide the infrastructure to build foo
# from the object files whose names are derived from these two
# varialbes. In particular, the following macros define several
# variables whose names are prefixed with foo_ to compute the
# different lists of files used to build foo.

# The first macro, _OCAML_PROGRAM_BASE, is a private macro (hence the _ at the
# beginning of its name) which defines foo_ variables common to both
# bytecode and native programs. The next two macros, OCAML_BYTECODE_PROGRAM
# and OCAML_NATIVE_PROGRAM are used to define programs that are provided
# only in bytecode or native form, respectively. Programs provided
# in both forms should use OCAML_PROGRAM.

define _OCAML_PROGRAM_BASE
$(eval $(call _OCAML_COMMON_BASE,$(1)))
endef # _OCAML_PROGRAM_BASE

LINK_BYTECODE_PROGRAM =\
  $(CAMLC) $(OC_COMMON_LINKFLAGS) $(OC_BYTECODE_LINKFLAGS)

# The _OCAML_BYTECODE_PROGRAM macro defines a bytecode program but assuming
# that _OCAML_PROGRAM_BASE has already been called. Its public counterpart
# does not rely on this assumption and rather does call _OCAML_PROGRAM_BASE
# itself.

define _OCAML_BYTECODE_PROGRAM
$(eval $(call PROGRAM_SYNONYM,$(1)))
$(basename $(notdir $(1)))_CMA_FILES = \
  $$(patsubst %,%.cma, $$($(basename $(notdir $(1)))_LIBRARIES))
$(basename $(notdir $(1)))_BO_FILES = \
  $$(patsubst %.c,%.b.$(O), $$($(basename $(notdir $(1)))_C_FILES))
$(basename $(notdir $(1)))_CMO_FILES = \
  $$(patsubst %.ml,%.cmo, $$($(basename $(notdir $(1)))_ML_FILES))
$(basename $(notdir $(1)))_BCOBJS = \
  $$($(basename $(notdir $(1)))_CMA_FILES) \
  $$($(basename $(notdir $(1)))_BO_FILES) \
  $$($(basename $(notdir $(1)))_CMO_FILES)
$(1)$(EXE): $$$$($(basename $(notdir $(1)))_BCOBJS)
	$$(V_LINKC)$$(LINK_BYTECODE_PROGRAM) -o $$@ \
	  $$($(basename $(notdir $(1)))_BCOBJS)
endef # _OCAML_BYTECODE_PROGRAM

define OCAML_BYTECODE_PROGRAM
$(eval $(call _OCAML_PROGRAM_BASE,$(1)))
$(eval $(call _OCAML_BYTECODE_PROGRAM,$(1)))
endef # OCAML_BYTECODE_PROGRAM

LINK_NATIVE_PROGRAM =\
  $(CAMLOPT) $(OC_COMMON_LINKFLAGS) $(OC_NATIVE_LINKFLAGS)

define _OCAML_NATIVE_PROGRAM
$(eval $(call PROGRAM_SYNONYM,$(1)))
$(basename $(notdir $(1)))_CMXA_FILES = \
  $$(patsubst %,%.cmxa, $$($(basename $(notdir $(1)))_LIBRARIES))
$(basename $(notdir $(1)))_NO_FILES = \
  $$(patsubst %.c,%.n.$(O), $$($(basename $(notdir $(1)))_C_FILES))
$(basename $(notdir $(1)))_CMX_FILES = \
  $$(patsubst %.ml,%.cmx, $$($(basename $(notdir $(1)))_ML_FILES))
ALL_CMX_FILES += $$($(basename $(notdir $(1)))_CMX_FILES)
$(basename $(notdir $(1)))_NCOBJS = \
  $$($(basename $(notdir $(1)))_CMXA_FILES) \
  $$($(basename $(notdir $(1)))_NO_FILES) \
  $$($(basename $(notdir $(1)))_CMX_FILES)
$(1)$(EXE): $$$$($(basename $(notdir $(1)))_NCOBJS)
	$$(V_LINKOPT)$$(LINK_NATIVE_PROGRAM) -o $$@ \
	  $$($(basename $(notdir $(1)))_NCOBJS)
endef # _OCAML_NATIVE_PROGRAM

define OCAML_NATIVE_PROGRAM
$(eval $(call _OCAML_PROGRAM_BASE,$(1)))
$(eval $(call _OCAML_NATIVE_PROGRAM,$(1)))
endef # OCAML_NATIVE_PROGRAM

define OCAML_PROGRAM
$(eval $(call _OCAML_PROGRAM_BASE,$(1)))
$(eval $(call _OCAML_BYTECODE_PROGRAM,$(1)))
$(eval $(call _OCAML_NATIVE_PROGRAM,$(1).opt))
endef # OCAML_PROGRAM

# Macros for OCaml libraries, similar to those for OCaml programs

define _OCAML_LIBRARY_BASE
$(eval $(call _OCAML_COMMON_BASE,$(1)))
endef # _OCAML_LIBRARY_BASE

LINK_BYTECODE_LIBRARY =\
  $(CAMLC) $(OC_COMMON_LINKFLAGS) $(OC_BYTECODE_LINKFLAGS)

# The _OCAML_BYTECODE_LIBRARY macro defines a bytecode library but assuming
# that _OCAML_LIBRARY_BASE has already been called. Its public counterpart
# does not rely on this assumption and rather does call _OCAML_LIBRARY_BASE
# itself.

define _OCAML_BYTECODE_LIBRARY
$(basename $(notdir $(1)))_BYTE_CMI_FILES = \
  $$(foreach F,$$($(basename $(notdir $(1)))_CMI_FILES),\
    $$(if $$(findstring /native/,$$(F)),,$$(F)))
$(basename $(notdir $(1)))_BO_FILES = \
  $$(patsubst %.c,%.b.$(O), $$($(basename $(notdir $(1)))_C_FILES))
$(basename $(notdir $(1)))_CMO_FILES = \
  $$(patsubst %.ml,%.cmo, \
    $$(foreach F,$$($(basename $(notdir $(1)))_ML_FILES),\
      $$(if $$(findstring /native/,$$(F)),,$$(F))))
$(basename $(notdir $(1)))_BCOBJS = \
  $$($(basename $(notdir $(1)))_BO_FILES) \
  $$($(basename $(notdir $(1)))_CMO_FILES)
$(1).cma: \
  $$$$($(basename $(notdir $(1)))_BYTE_CMI_FILES) \
  $$$$($(basename $(notdir $(1)))_BCOBJS)
	$$(V_LINKC)$$(LINK_BYTECODE_LIBRARY) -a -o $$@ \
	  $$($(basename $(notdir $(1)))_BCOBJS)
endef # _OCAML_BYTECODE_LIBRARY

define OCAML_BYTECODE_LIBRARY
$(eval $(call _OCAML_LIBRARY_BASE,$(1)))
$(eval $(call _OCAML_BYTECODE_LIBRARY,$(1)))
endef # OCAML_BYTECODE_LIBRARY

LINK_NATIVE_LIBRARY =\
  $(CAMLOPT) $(OC_COMMON_LINKFLAGS) $(OC_NATIVE_LINKFLAGS)

define _OCAML_NATIVE_LIBRARY
$(basename $(notdir $(1)))_NATIVE_CMI_FILES = \
  $$(foreach F,$$($(basename $(notdir $(1)))_CMI_FILES),\
    $$(if $$(findstring /byte/,$$(F)),,$$(F)))
$(basename $(notdir $(1)))_NO_FILES = \
  $$(patsubst %.c,%.n.$(O), $$($(basename $(notdir $(1)))_C_FILES))
$(basename $(notdir $(1)))_CMX_FILES = \
  $$(patsubst %.ml,%.cmx, \
    $$(foreach F,$$($(basename $(notdir $(1)))_ML_FILES),\
      $$(if $$(findstring /byte/,$$(F)),,$$(F))))
ALL_CMX_FILES += $$($(basename $(notdir $(1)))_CMX_FILES)
$(basename $(notdir $(1)))_NCOBJS = \
  $$($(basename $(notdir $(1)))_NO_FILES) \
  $$($(basename $(notdir $(1)))_CMX_FILES)
$(1).cmxa: \
  $$$$($(basename $(notdir $(1)))_NATIVE_CMI_FILES) \
  $$$$($(basename $(notdir $(1)))_NCOBJS)
	$$(V_LINKOPT)$$(LINK_NATIVE_LIBRARY) -a -o $$@ \
	  $$($(basename $(notdir $(1)))_NCOBJS)
endef # _OCAML_NATIVE_LIBRARY

define OCAML_NATIVE_LIBRARY
$(eval $(call _OCAML_LIBRARY_BASE,$(1)))
$(eval $(call _OCAML_NATIVE_LIBRARY,$(1)))
endef # OCAML_NATIVE_LIBRARY

define OCAML_LIBRARY
$(eval $(call _OCAML_LIBRARY_BASE,$(1)))
$(eval $(call _OCAML_BYTECODE_LIBRARY,$(1)))
$(eval $(call _OCAML_NATIVE_LIBRARY,$(1)))
endef # OCAML_LIBRARY

# Installing a bytecode executable, with debug information removed
define INSTALL_STRIPPED_BYTE_PROG
$(OCAMLRUN) $(ROOTDIR)/tools/stripdebug $(1) $(1).tmp \
&& $(INSTALL_PROG) $(1).tmp $(2) \
&& rm $(1).tmp
endef # INSTALL_STRIPPED_BYTE_PROG

# ocamlc has several mechanisms for linking a bytecode image to the runtime
# which executes it. The exact mechanism depends on the platform and the precise
# location of the runtime. The boot compiler (boot/ocamlc) therefore needs this
# additional information, which comes from the stdlib build and is copied into
# boot/ as part of coldstart. See read_runtime_launch_info in
# bytecomp/bytelink.ml for further details.
HEADER_NAME = runtime-launch-info
