#-----------------------------------------------------------------------------#
# Copyright (C) 1995-2003 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

# 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=mercury

MERCURY_MAIN_MODULES = top_level mlds_to_gcc

VPATH=$(LIBRARY_DIR) $(BROWSER_DIR) $(ANALYSIS_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 +=	-I $(BROWSER_DIR) -I $(ANALYSIS_DIR) \
			--c-include-directory $(ANALYSIS_DIR)
CFLAGS +=	-I$(ANALYSIS_DIR) -I$(ANALYSIS_DIR)/$(mihs_subdir)
MLOBJS :=	../main.$O ../analysis/lib$(ANALYSIS_LIB_NAME).$A $(MLOBJS)
ALL_MLLIBS =	$(MLLIBS) $(EXTRA_MLLIBS) $(GCC_BACKEND_LIBS)
MLFLAGS +=	--no-main --shared
MCFLAGS +=	--no-main --linkage shared
C2INITARGS +=	$(ANALYSIS_DIR)/$(ANALYSIS_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

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

# 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-aditi_backend	= $(ADITI_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 = aditi_backend 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:
	-[ -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

# 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:
	$(MC) $(ALL_MCFLAGS) -f *.m

.PHONY: all
all:		mercury

.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 ../analysis/*.dll ../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% java%,$(GRADE))","")

.PHONY: depend
depend:		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

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

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

ifeq ($(findstring il,$(GRADE)),il)        
MS_CSCFLAGS=/lib:`$(FIX_PATH_FOR_CSC) ../analysis`

# This line works around an Mmake bug: mmake doesn't record
# dependencies properly with --transitive-intermodule-optimization
%.il: opts
else
$(MC_PROG): ../main.$O
$(MC_PROG): $(RUNTIME_DIR)/lib$(RT_LIB_NAME).$A
$(MC_PROG): $(LIBRARY_DIR)/lib$(STD_LIB_NAME).$A
$(MC_PROG): $(BROWSER_DIR)/lib$(MDBCOMP_LIB_NAME).$A
$(MC_PROG): $(BROWSER_DIR)/lib$(BROWSER_LIB_NAME).$A
$(MC_PROG): $(TRACE_DIR)/lib$(TRACE_LIB_NAME).$A
$(MC_PROG): $(ANALYSIS_DIR)/lib$(ANALYSIS_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

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

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

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

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

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

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

$(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
ifeq ($(MMAKE_USE_MMC_MAKE),no)
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 \
		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)

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