#-----------------------------------------------------------------------------#
# Copyright (C) 1995-2001 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=..
include $(MERCURY_DIR)/Mmake.common

MAIN_TARGET=mercury

VPATH=$(LIBRARY_DIR) $(BROWSER_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.
GCC_SRC_DIR := $(MERCURY_DIR)/$(GCC_SRC_DIR)
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

# Specify which compilers to use to compile the compiler.
# Don't change these without good reason - if you want to
# do a temporary change, change ../Mmake.params

M_ENV	=	MERCURY_INT_DIR=$(LIBRARY_DIR) \
		MERCURY_ALL_C_INCL_DIRS="\
			-I$(BROWSER_DIR) \
			-I$(TRACE_DIR) \
			-I$(LIBRARY_DIR) \
			-I$(RUNTIME_DIR) \
			-I$(BOEHM_GC_DIR) \
			-I$(BOEHM_GC_DIR)/include \
		"
SMC	=	$(MC) --search-directory $(BROWSER_DIR)
MCD	=	$(M_ENV) $(SMC) --generate-dependencies
MCI	=	$(M_ENV) $(SMC) --make-interface
MCPI	=	$(M_ENV) $(SMC) --make-private-interface
MCSI	=	$(M_ENV) $(SMC) --make-short-interface
MCOI	=	$(M_ENV) $(SMC) --make-optimization-interface
MCTOI	=	$(M_ENV) $(SMC) --make-transitive-optimization-interface
MCG	=	$(M_ENV) $(SMC) --compile-to-c
MCS	=	$(M_ENV) $(SMC) --split-c-files -c --cflags "$(ALL_CFLAGS)"
MGNUC	=	$(M_ENV) $(SCRIPTS_DIR)/mgnuc
C2INIT =	MERCURY_MOD_LIB_MODS="$(LIBRARY_DIR)/$(STD_LIB_NAME).init $(RUNTIME_DIR)/$(RT_LIB_NAME).init" \
		MERCURY_TRACE_LIB_MODS="$(BROWSER_DIR)/$(BROWSER_LIB_NAME).init" \
		MERCURY_MKINIT=$(UTIL_DIR)/mkinit $(SCRIPTS_DIR)/c2init
C2INITFLAGS =	--library
ML	=	MERCURY_C_LIB_DIR=. $(SCRIPTS_DIR)/ml
MLFLAGS =	--shared --mercury-libs none
MLLIBS  =	../main.$O \
		$(TRACE_DIR)/lib$(TRACE_LIB_NAME).$A \
		$(BROWSER_DIR)/lib$(BROWSER_LIB_NAME).$A \
		$(LIBRARY_DIR)/lib$(STD_LIB_NAME).$A \
		$(RUNTIME_DIR)/lib$(RT_LIB_NAME).$A ` \
		    case $(GRADE) in \
			*.par*.gc*.prof*) \
				echo $(BOEHM_GC_DIR)/libpar_gc_prof.$A ;; \
			*.par*.gc*)	echo $(BOEHM_GC_DIR)/libpar_gc.$A ;; \
			*.gc*.prof*)	echo $(BOEHM_GC_DIR)/libgc_prof.$A ;; \
			*.gc*)		echo $(BOEHM_GC_DIR)/libgc.$A ;; \
		    esac \
		` \
		$(GCC_BACKEND_LIBS) \
		$(MATH_LIB)
MTAGS	=	$(SCRIPTS_DIR)/mtags
MTAGSFLAGS =	$(EXTRA_MTAGSFLAGS)

#
# 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
endif

# Compilation of rl_code.c is really slow (about 26 minutes on traveller with
# --trace deep) at the default level of -O2, due to the C optimizer's use of
# quadratic algorithms on a couple of 20,000-line functions (the automatically
# generated index and compare routines on the bytecode type). The code in this
# module can't really benefit from those algorithms anyway. With -O1, the 26
# minutes drops to less than 26 seconds.

CFLAGS-rl_code=-O1

# The c_code in the module gcc.m needs the header files from the GNU C
# distribution.
CFLAGS-gcc =	-DMERCURY_BOOTSTRAP_H \
		-DIN_GCC -DHAVE_CONFIG_H \
		-I. \
		-I$(GCC_SRC_DIR)/gcc \
		-I$(GCC_SRC_DIR)/gcc/mercury \
		-I$(GCC_SRC_DIR)/gcc/config \
		-I$(GCC_SRC_DIR)/include \
		-I$(GCC_SRC_DIR)
# Likewise for mlds_to_gcc.m
CFLAGS-mlds_to_gcc = $(CFLAGS-gcc)

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

# 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-rl_file 		= $(ADITI_SED_EXPR)
PP_SED_EXPR-rl_out		= $(ADITI_SED_EXPR)
PP_SED_EXPR-maybe_mlds_to_gcc	= $(GCC_SED_EXPR)

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

#
# 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 = rl_file rl_out 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:
	touch $(PREPROCESSED_FILES)
	$(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
#
# mercury_compile

.PHONY: depend
depend:		mercury_compile.depend

mercury_compile.depend: regenerate_preprocessed_files

.PHONY: all
all:		mercury

.PHONY: mercury
mercury:	mercury_compile

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

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

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

mercury_compile: ../main.$O
mercury_compile: $(RUNTIME_DIR)/lib$(RT_LIB_NAME).$A
mercury_compile: $(LIBRARY_DIR)/lib$(STD_LIB_NAME).$A
mercury_compile: $(BROWSER_DIR)/lib$(BROWSER_LIB_NAME).$A
mercury_compile: $(TRACE_DIR)/lib$(TRACE_LIB_NAME).$A
# Should also depend on $(BOEHM_GC_DIR)/libgc(_prof).$A, but only
# if in .gc(.prof) grade; GNU make does not support dynamic dependencies,
# so just leave it out.
mercury_compile: $(GCC_MAIN_LIBS)

mercury_compile_init.c: $(UTIL_DIR)/mkinit

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

.PHONY: check
check		: mercury_compile.check

.PHONY: ints 
ints		: mercury_compile.ints

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

tags		: $(mercury_compile.ms) $(LIBRARY_DIR)/*.m
	$(MTAGS) $(MTAGSFLAGS) $(mercury_compile.ms) $(LIBRARY_DIR)/*.m

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

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

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

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

.PHONY: os cs ss
os: $(mercury_compile.os) $(os_subdir)mercury_compile_init.$O
cs: $(mercury_compile.cs) $(cs_subdir)mercury_compile_init.c
ss: $(mercury_compile.ss)

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

clean_local:
	rm -f ../main.$O
	for file in *.pp; do \
		if [ "$$file" != "*.pp" ]; then \
			rm -f `basename $$file .pp`.m; \
		fi; \
	done

realclean_local:
	rm -f tags mercury_compile.stats $(PP_DATE_FILES)

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

# 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)

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