#-----------------------------------------------------------------------------#
# Copyright (C) 1995-2003, 2005-2011 The University of Melbourne. 
# This file may only be copied under the terms of the GNU General
# Public Licence - see the file COPYING in the Mercury distribution.
#-----------------------------------------------------------------------------#

# Mmake - this is Mmake file for building the Mercury compiler 

MERCURY_DIR=..
LINK_STATIC=yes
include $(MERCURY_DIR)/Mmake.common

# Override the settings in ../Mmake.workspace so that in debugging grades we
# do not include mer_mdbcomp.init twice in the list of files passed to mkinit.
#
C2INITFLAGS = \
	--trace-init-file $(BROWSER_DIR)/$(BROWSER_LIB_NAME).init \
	--ssdb-init-file $(SSDB_DIR)/$(SSDB_LIB_NAME).init

-include Mmake.compiler.params

# Override the default rule in `mmake --use-mmc-make' that asks `mmc' to
# create a missing optional params file for us.
Mmake.compiler.params:

# Module-specific options should go in Mercury.options so they
# can be found by `mmc --make'.
# Mercury.options uses $(GCC_SRC_DIR), so make sure it is
# in the environment of `mmc --make'.
GCC_SRC_DIR := $(MERCURY_DIR)/$(GCC_SRC_DIR)
export GCC_SRC_DIR
include Mercury.options

MAIN_TARGET=all

MERCURY_MAIN_MODULES = top_level mlds_to_gcc

VPATH = \
	$(LIBRARY_DIR) \
	$(MDBCOMP_DIR) \
	$(BROWSER_DIR) \
	$(SSDB_DIR)

#-----------------------------------------------------------------------------#

# Specify how to link in the GCC back-end.
# This uses the file `mercury_gcc_backend_libs', which is generated by
# the gcc Makefile (from gcc/mercury/Make-lang.in), which contains
# a list of the object files and libraries that we need to link in.
ifeq ($(ENABLE_GCC_BACK_END),yes)
GCC_LIBS = $(shell cat $(GCC_SRC_DIR)/gcc/mercury_gcc_backend_libs)
GCC_EXTRA_LIBS = $(filter -l%,$(GCC_LIBS))
GCC_MAIN_LIBS = $(patsubst %,$(GCC_SRC_DIR)/gcc/%,$(filter-out -l%,$(GCC_LIBS)))
GCC_BACKEND_LIBS = $(GCC_MAIN_LIBS) $(GCC_EXTRA_LIBS)
else
GCC_MAIN_LIBS =
GCC_BACKEND_LIBS =
endif

# Ensure that we rebuild the GCC libbackend.a, etc., if it is out-of-date
.PHONY: force
force: ;

$(GCC_MAIN_LIBS): force
	cd $(GCC_SRC_DIR)/gcc && $(MAKE) mercury_gcc_backend_libs

MCFLAGS	     += --flags COMP_FLAGS $(CONFIG_OVERRIDE)

ifeq ("$(filter il% csharp% java% erlang%,$(GRADE))","")
MLOBJS       := ../main.$O \
		../trace/lib$(EVENTSPEC_LIB_NAME).$A \
		$(MLOBJS)
else
MLOBJS =
endif

MLLIBS       += $(THREAD_LIBS)
ALL_MLLIBS    = $(MLLIBS) $(EXTRA_MLLIBS) $(GCC_BACKEND_LIBS)
MLFLAGS      += --no-main --shared
C2INITARGS   += $(MDBCOMP_DIR)/$(MDBCOMP_LIB_NAME).init

#
# Work-around for a fixed limit: on alpha-dec-osf3.2, if we compile with
# `-O5', then when linking mercury_compile we get an error message of the form
#
#   /usr/bin/ld:
#	Too many GOT entries in object file '/usr/lib/cmplrs/cc/libexc_init.a';
#	Found 8190 (6660 locals + 1530 globals) but max is 8189
#
# unless we link it statically.
#
ifeq ($(FULLARCH),alpha-dec-osf3.2)
MLFLAGS += --static
MCFLAGS += --linkage static
endif

# -Xmx256m doesn't always seem to be enough memory to build the complier.
# This bumps up the memory when building the compiler if the javac executable
# accepts the -J-Xmx flag, without bumping up the memory requirements in
# general.
ifneq ("$(findstring -J\"-Xmx,$(JAVACFLAGS))","")
JAVACFLAGS   += -J\"-Xmx2048m\"
endif

#-----------------------------------------------------------------------------#

# Rules for preprocessing `.pp' files.
# `.pp_date' files are used as timestamps as for interface files.

#
# Rule to generate foo.m from foo.pp by applying `sed $(PP_SED_EXPR)'
#
# Note that we set hash="#" for use in $(PP_SED_EXPR).
# This seems to be the easiest way to get a "#" character;
# we can't just use a Make variable since "#" is a comment character
# in Make and so its hard to create a variable with that value.
#
$(dates_subdir)%.pp_date: %.pp
	-hash="#"; \
	m_file=$(<:.pp=.m); \
	[ ! -f $$m_file ] || chmod +w $$m_file; \
	sed $(PP_SED_EXPR) $< > $$m_file.tmp && \
	mercury_update_interface -v $$m_file && \
	touch $@ && \
	chmod -w $$m_file

#
# Define $(PP_SED_EXPR) appropriately for each preprocessed module.
#
PP_SED_EXPR			= $(PP_SED_EXPR-$*)
PP_SED_EXPR-maybe_mlds_to_gcc	= $(GCC_SED_EXPR)

#
# For GCC .pp files, enable/disable code within
# `#if ENABLE_GCC_BACK_END ... #else .. #endif'
#
ifeq ($(ENABLE_GCC_BACK_END),yes)
# Remove the #if line and everything between the #else and #endif lines.
GCC_SED_EXPR  = -e "/^$${hash}if *ENABLE_GCC_BACK_END/s/.*//" \
		-e "/^$${hash}else/,/^$${hash}endif/s/.*//"
else
# Remove everything between the #if line and the #else line,
# and the #endif line.
GCC_SED_EXPR  = -e "/^$${hash}if *ENABLE_GCC_BACK_END/,/^$${hash}else/s/.*//" \
		-e "/^$${hash}endif/s/.*//"
endif

PREPROCESSED_MODULES = maybe_mlds_to_gcc
PREPROCESSED_FILES = $(PREPROCESSED_MODULES:%=%.pp)
PREPROCESSED_M_FILES = $(PREPROCESSED_MODULES:%=%.m)
PP_DATE_FILES = $(PREPROCESSED_MODULES:%=$(dates_subdir)%.pp_date)

# Force regeneration of the preprocessed modules.
# This is necessary if the setting of `INCLUDE_ADITI_OUTPUT' has changed.
regenerate_preprocessed_files:
	-[ -d ./$(dates_subdir) ] || mkdir -p ./$(dates_subdir)
	touch $(PREPROCESSED_FILES)
	MMAKE_DIR=$(SCRIPTS_DIR) $(MMAKE) $(PREPROCESSED_M_FILES)

# The `.m' files for the preprocessed modules depend on the `.pp_date' files.
$(PREPROCESSED_M_FILES): %.m: $(dates_subdir)%.pp_date
	@:

#-----------------------------------------------------------------------------#

# targets

# specify the name of the top-level module to build
MC_PROG = top_level

# mercury_compile

.PHONY: depend
depend:		$(MC_PROG).depend

$(MC_PROG).depend: regenerate_preprocessed_files Mercury.modules COMP_FLAGS 

# This directory contains source files for which the module
# name doesn't match the file name, so smart recompilation
# won't work without the Mercury.modules file.
.PHONY: Mercury.modules
Mercury.modules: COMP_FLAGS
	$(MC) $(ALL_GRADEFLAGS) $(ALL_MCFLAGS) -f *.m

.PHONY: all
all:		mercury $(TAGS_FILE_EXISTS)

.PHONY: mercury
mercury:	mercury_compile

.PHONY: libmmc
libmmc:		libmercury_compile.a mercury_compile_init.$O

# The executable was previous known as `mercury_compile',
# but now we generate it as `top_level'.  For compatibility with
# various existing code, we make links to the old names.

LN = ln

ifneq ("$(EXT_FOR_EXE)","")
.PHONY: mercury_compile
mercury_compile: mercury_compile$(EXT_FOR_EXE)
endif

mercury_compile$(EXT_FOR_EXE): $(MC_PROG)$(EXT_FOR_EXE)
	rm -f mercury_compile$(EXT_FOR_EXE)
	$(LN) $(MC_PROG)$(EXT_FOR_EXE) mercury_compile$(EXT_FOR_EXE) || \
		cp $(MC_PROG)$(EXT_FOR_EXE) mercury_compile$(EXT_FOR_EXE)
ifeq ($(findstring il,$(GRADE)),il)        
	# set the stack size to 100M -- the default of 1M is too low
	-editbin /nologo /stack:100000000 mercury_compile$(EXT_FOR_EXE)
	cp ../browser/*.dll .
endif

libmercury_compile.a: lib$(MC_PROG).a
	rm -f libmercury_compile.a
	cp lib$(MC_PROG).a libmercury_compile.a
	ar d libmercury_compile.a main.o

mercury_compile_init.$O: $(MC_PROG)_init.$O
	rm -f mercury_compile_init.$O
	$(LN) $(MC_PROG)_init.$O mercury_compile_init.$O || \
		cp $(MC_PROG)_init.$O mercury_compile_init.$O

#-----------------------------------------------------------------------------#

# The GCC back-end stuff is conditionally compiled out of maybe_mlds_to_gcc.m.
# But we want to make sure that the GCC back-end continues to compile,
# even when the compiler was configured without the GCC back-end.
# So we include the following rules, which tell Mmake to build the
# dependencies for mlds_to_gcc and to build mlds_to_gcc.c and gcc.c.
# (We used to just build mlds_to_gcc.err, but that caused bootstrapping problems
# with the source distribution; using the .c files is little more robust.)

ifeq ("$(filter il% csharp% java% erlang%,$(GRADE))","")

.PHONY: depend
depend:		COMP_FLAGS mlds_to_gcc.depend

mlds_to_gcc.depend: regenerate_preprocessed_files

.PHONY: mercury
mercury:	mlds_to_gcc.c gcc.c

.PHONY: cs
cs: 		mlds_to_gcc.c gcc.c

endif

#-----------------------------------------------------------------------------#

# Tell the C# compiler where the stdlib and mdbcomp assemblies are.
#
ifneq ("$(filter csharp%,$(GRADE))","")
CSCFLAGS=-lib:../library -r:mer_std -lib:../mdbcomp -r:mer_mdbcomp
endif

#-----------------------------------------------------------------------------#

# Add some additional dependencies, so that Mmake knows to remake the
# compiler if one of the libraries changes.

ifeq ($(findstring il,$(GRADE)),il)        
CSCFLAGS=/lib

# This line works around an Mmake bug: mmake doesn't record
# dependencies properly with --transitive-intermodule-optimization
%.il: opts
else
ifeq ("$(filter csharp% java% erlang%,$(GRADE))","")
$(MC_PROG): ../main.$O
$(MC_PROG): $(RUNTIME_DIR)/lib$(RT_LIB_NAME).$A
$(MC_PROG): $(LIBRARY_DIR)/lib$(STD_LIB_NAME).$A
$(MC_PROG): $(MDBCOMP_DIR)/lib$(MDBCOMP_LIB_NAME).$A
$(MC_PROG): $(BROWSER_DIR)/lib$(BROWSER_LIB_NAME).$A
$(MC_PROG): $(SSDB_DIR)/lib$(SSDB_LIB_NAME).$A
$(MC_PROG): $(TRACE_DIR)/lib$(TRACE_LIB_NAME).$A
$(MC_PROG): $(TRACE_DIR)/lib$(EVENTSPEC_LIB_NAME).$A
# XXX should also depend on $(BOEHM_GC_DIR)/libgc(_prof).$A, but only
# if in .gc(.prof) grade
$(MC_PROG): $(GCC_MAIN_LIBS)
endif
endif

$(MC_PROG)_init.c: $(UTIL_DIR)/mkinit

#-----------------------------------------------------------------------------#

.PHONY: check
check:	$(MC_PROG).check

.PHONY: ints 
int3s:	$(MC_PROG).int3s

.PHONY: ints 
ints:	$(MC_PROG).ints

#-----------------------------------------------------------------------------#

# We need the shenanigans with .compiler_tags to avoid situations in which an
# "mmake tags" in this directory does nothing even in the absence of a tags
# file in this directory, because mmake uses VPATH to find ../library/tags
# and believes it to be the tags file we are asking for.

.PHONY: tags
tags:	.compiler_tags

.compiler_tags:	$(MTAGS) $(PREPROCESSED_M_FILES) \
		$(wildcard *.m) \
		$(wildcard $(LIBRARY_DIR)/*.m) \
		$(wildcard $(MDBCOMP_DIR)/*.m)
	$(MTAGS) $(MTAGSFLAGS) *.m $(LIBRARY_DIR)/*.m $(MDBCOMP_DIR)/*.m
	@touch .compiler_tags

.PHONY: tags_file_exists
tags_file_exists:
	@if test ! -f tags; then echo making tags; \
	$(MTAGS) $(MTAGSFLAGS) *.m $(LIBRARY_DIR)/*.m $(MDBCOMP_DIR)/*.m; \
	touch .compiler_tags; \
	fi

$(MC_PROG).stats: source_stats.awk $($(MC_PROG).ms)
	awk -f `vpath_find source_stats.awk` \
		`vpath_find $($(MC_PROG).ms)` > $@

#-----------------------------------------------------------------------------#

.PHONY: dates
dates:
	touch $($(MC_PROG).dates)

#-----------------------------------------------------------------------------#

# Note that the cs and os targets don't build top_level_init.{c,o}
.PHONY: os cs ss ils
ifneq ($(MMAKE_USE_MMC_MAKE),yes)
os: $($(MC_PROG).os)
cs: $($(MC_PROG).cs)
ss: $($(MC_PROG).ss)
ils: $($(MC_PROG).ils)
opts: $($(MC_PROG).opts)
else
os: $(MC_PROG).os
cs: $(MC_PROG).cs
ss: $(MC_PROG).ss
ils: $(MC_PROG).ils
opts: $(MC_PROG).opts
endif

#-----------------------------------------------------------------------------#

clean_local:
	rm -f ../main.$O $(PREPROCESSED_M_FILES) $(PP_DATE_FILES)

realclean_local:
	rm -f tags $(MC_PROG).stats Mercury.modules \
		COMP_FLAGS COMP_FLAGS.date mercury_compile$(EXT_FOR_EXE)

#-----------------------------------------------------------------------------#
#-----------------------------------------------------------------------------#

# Installation targets

.PHONY: install
install: install_mercury

.PHONY: install_all
install_all: install_mercury

.PHONY: install_mercury
install_mercury: install_compiler
	
.PHONY: install_dirs
install_dirs:
	-[ -d $(INSTALL_MERC_BIN_DIR) ] || mkdir -p $(INSTALL_MERC_BIN_DIR)

.PHONY: install_compiler
install_compiler: mercury_compile install_dirs
	cp `vpath_find mercury_compile$(EXT_FOR_EXE)` $(INSTALL_MERC_BIN_DIR)

#-----------------------------------------------------------------------------#
