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

# Mmake.rules - rules for building Mercury programs

# N.B. All the builtin rules must use $@ as the target, so that they work
# when $(VPATH) is set.
#
# When passing a module to mmc, strip off the directory part of the
# name. This way the compiler will report an error if the source file
# is in another directory, rather than generating interface files in
# the wrong directory.

main_target: $(MAIN_TARGET)

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

# Beware that the order of suffixes is significant.
.SUFFIXES: .m .nl .no .err \
		.int0 .int .int2 .int3 .opt .trans_opt \
		.dep .depend .dv .doit .ugly \
		.date0 .date .date3 .optdate .trans_opt_date \
		.c .$O .pic_o \
		.i .s .pic_s \
		.java .class \
		.il .dll .exe .cpp .cs \
		.c_date .il_date .java_date .s_date .pic_s_date

#-----------------------------------------------------------------------------#
#
# Code to set variables based on the setting of MMAKE_USE_SUBDIRS
# (i.e. --use-subdirs).
#

ifeq ($(MMAKE_USE_SUBDIRS),yes)

MCFLAGS += --use-subdirs
ALL_MGNUCFLAGS += -I. -I$(mihs_subdir).

endif

#-----------------------------------------------------------------------------#
#
# Find the directory containing the interface files for the standard library.
#
ifdef MERCURY_STDLIB_DIR
    export MERCURY_STDLIB_DIR
    MERC_INT_DIR = $(MERCURY_STDLIB_DIR)/ints
else
    MERC_INT_DIR =
endif

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

.PRECIOUS: $(date0s_subdir)%.date0
.PRECIOUS: $(dates_subdir)%.date
.PRECIOUS: $(date3s_subdir)%.date3
.PRECIOUS: $(optdates_subdir)%.optdate
.PRECIOUS: $(trans_opt_dates_subdir)%.trans_opt_date
.PRECIOUS: $(c_dates_subdir)%.c_date
.PRECIOUS: $(il_dates_subdir)%.il_date
.PRECIOUS: $(java_dates_subdir)%.java_date
.PRECIOUS: $(s_dates_subdir)%.s_date
.PRECIOUS: $(pic_s_dates_subdir)%.pic_s_date

#-----------------------------------------------------------------------------#
#
# Rules for building dependency files
#

# When creating the dependencies with `--use-subdirs' enabled,
# we need to create the `Mercury/dates' directories manually
# in order to get things started.  This should not be necessary,
# but there is a bug in GNU Make with regard to directory caching.
# I have sent off a bug report to the GNU Make maintainers (19 March 1998).
#	-fjh.

ifneq ($(MMAKE_USE_MMC_MAKE),yes)

# Beware the code for `%.depend' and `%.dep'/`%.dv' is duplicated,
# with each copy having two variants that differ only by a @.
# javac doesn't create the destination directory for class files
# so we must create it manually
# the following mkdirs work around a bug in GNU Make
$(deps_subdir)%.dep $(deps_subdir)%.dv:
	$(MCD) $(ALL_GRADEFLAGS) $(ALL_MCDFLAGS) $*
ifeq ($(MMAKE_USE_SUBDIRS),yes)
ifeq ($(MMAKE_USE_SUBDIRS_EXPLICIT),yes)
	-mkdir -p $(classes_subdir) \
		Mercury/dates Mercury/date0s Mercury/date3s \
		Mercury/optdates Mercury/trans_opt_dates \
		Mercury/c_dates Mercury/il_dates \
		Mercury/s_dates Mercury/pic_s_dates
else
	@-mkdir -p $(classes_subdir) \
		Mercury/dates Mercury/date0s Mercury/date3s \
		Mercury/optdates Mercury/trans_opt_dates \
		Mercury/c_dates Mercury/il_dates \
		Mercury/s_dates Mercury/pic_s_dates
endif
endif

# Beware the code for `%.depend' and `%.dep'/`%.dv' is duplicated,
# with each copy having two variants that differ only by a @.
# javac doesn't create the destination directory for class files
# so we must create it manually
# the following mkdirs work around a bug in GNU Make
.PHONY: %.depend
%.depend :
	$(MCD) $(ALL_GRADEFLAGS) $(ALL_MCDFLAGS) $*
ifeq ($(MMAKE_USE_SUBDIRS),yes)
ifeq ($(MMAKE_USE_SUBDIRS_EXPLICIT),yes)
	-mkdir -p $(classes_subdir) \
		Mercury/dates Mercury/date0s Mercury/date3s \
		Mercury/optdates Mercury/trans_opt_dates \
		Mercury/c_dates Mercury/il_dates \
		Mercury/s_dates Mercury/pic_s_dates
else
	@-mkdir -p $(classes_subdir) \
		Mercury/dates Mercury/date0s Mercury/date3s \
		Mercury/optdates Mercury/trans_opt_dates \
		Mercury/c_dates Mercury/il_dates \
		Mercury/s_dates Mercury/pic_s_dates
endif
endif

endif	# MMAKE_USE_MMC_MAKE != yes

#-----------------------------------------------------------------------------#
#
# Rules for building interface files
# WARNING: any changes here will probably need to be
# duplicated in compiler/modules.m.
#

ifneq ($(MMAKE_USE_MMC_MAKE),yes)

$(date0s_subdir)%.date0 : %.m
	$(MCPI) $(ALL_GRADEFLAGS) $(ALL_MCPIFLAGS) $(*F)

$(dates_subdir)%.date : %.m
	$(MCI) $(ALL_GRADEFLAGS) $(ALL_MCIFLAGS) $(*F)

$(date3s_subdir)%.date3 : %.m
	$(MCSI) $(ALL_GRADEFLAGS) $(ALL_MCSIFLAGS) $(*F)

$(optdates_subdir)%.optdate : %.m
	$(MCOI) $(ALL_GRADEFLAGS) $(ALL_MCOIFLAGS) $(*F)

$(trans_opt_dates_subdir)%.trans_opt_date : %.m
	$(MCTOI) $(ALL_GRADEFLAGS) $(ALL_MCTOIFLAGS) $(*F)

# Be very careful about changing the following rules.
# The `@:' is a silent do-nothing command.
# It is used to force GNU Make to recheck the timestamp
# on the target file.  (It is a pity that GNU Make doesn't
# have a way of handling these sorts of rules in a nicer manner.)

$(int0s_subdir)%.int0 : $(date0s_subdir)%.date0
	@:

$(ints_subdir)%.int : $(dates_subdir)%.date
	@:

$(int2s_subdir)%.int2 : $(dates_subdir)%.date
	@:

$(int3s_subdir)%.int3 : $(date3s_subdir)%.date3
	@:

$(opts_subdir)%.opt : $(optdates_subdir)%.optdate
	@:

$(trans_opts_subdir)%.trans_opt : $(trans_opt_dates_subdir)%.trans_opt_date
	@:

endif	# MMAKE_USE_MMC_MAKE != yes

#-----------------------------------------------------------------------------#
#
# Rules for compiling Mercury source files
# WARNING: any changes here will probably need to be
# duplicated in compiler/modules.m.
#

ifneq ($(MMAKE_USE_MMC_MAKE),yes)

# C back-end

# When smart recompilation finds that a module does not need to be
# recompiled, it only touches the `.c_date' file.
$(cs_subdir)%.c : $(c_dates_subdir)%.c_date
	@:

$(c_dates_subdir)%.c_date : %.m
	$(MCG) $(ALL_GRADEFLAGS) $(ALL_MCGFLAGS) $(*F) $(ERR_REDIRECT)

# Java back-end

ifeq ($(MMAKE_USE_SUBDIRS),yes)

$(classes_subdir)%.class: $(javas_subdir)%.java
	$(JAVAC) $(ALL_JAVACFLAGS) -d $(classes_subdir) $<

else

$(classes_subdir)%.class: $(javas_subdir)%.java
	$(JAVAC) $(ALL_JAVACFLAGS) $<

endif

# When smart recompilation finds that a module does not need to be
# recompiled, it only touches the `.java_date' file.
$(javas_subdir)%.java: $(java_dates_subdir)%.java_date
	@:

$(java_dates_subdir)%.java_date : %.m
	$(MCG) $(ALL_GRADEFLAGS) $(ALL_MCGFLAGS) \
		--java-only $(*F) $(ERR_REDIRECT)

# .NET back-end

# When smart recompilation finds that a module does not need to be
# recompiled, it only touches the `.il_date' file.
$(ils_subdir)%.il : $(il_dates_subdir)%.il_date
	@:

$(il_dates_subdir)%.il_date : %.m
	$(MCG) $(ALL_GRADEFLAGS) $(ALL_MCGFLAGS) \
		--il-only $(*F) $(ERR_REDIRECT)

# These rules are only available in *il* backends, because we'd like to avoid
# processing user code that is in a .cpp file, and we'd like to avoid going via
# IL to generate a DLL if we are in a non-IL grade.
ifeq ($(findstring il,$(GRADE)),il)

$(os_subdir)%.dll : %.cs
	$(CSC) /t:library /lib:`$(FIX_PATH_FOR_CSC) $(MERC_DLL_DIR)` \
		/out:$@ $(CSHARP_ASSEMBLY_REFS-$*) $(ALL_CSCFLAGS) $<

$(os_subdir)%.dll : %.il
	$(ILASM) $(ALL_ILASMFLAGS) /dll /quiet /OUT=$@ $<

mercury.sn:
	cp $(MERC_DLL_DIR)/mercury.sn .
endif

# The `touch' is necessary, since otherwise if
# the old .err file was of size zero and
# the new .err file is also of size zero,
# the time-stamp doesn't get updated!
# (Is that a bug in unix? In bash?)
# zs: It is neither. The timestamp is updated by the write system call:
# if the new file is of zero size, write is never called.
# touch has code to test specifically for this situation,
# and adds a byte to the file and then removes it.

.m.err:
	$(MCE) $(ALL_GRADEFLAGS) $(ALL_MCFLAGS) $(*F) $(ERR_REDIRECT)
	@touch $@

endif	# MMAKE_USE_MMC_MAKE != yes

.m.ugly:
	$(MC) --convert-to-mercury $(ALL_GRADEFLAGS) $(ALL_MCFLAGS) $(*F)

#-----------------------------------------------------------------------------#
#
# Rules for compiling C files in the user's source directory.
#

.c.$O:
	$(MGNUC) $(ALL_GRADEFLAGS) $(ALL_MGNUCFLAGS) -c $< $(OBJFILE_OPT)$@

.c.pic_o:
	$(MGNUC) $(ALL_GRADEFLAGS) $(ALL_MGNUCFLAGS) $(CFLAGS_FOR_PIC) \
		-c $< $(OBJFILE_OPT)$@

.c.s:
	$(MGNUC) $(ALL_GRADEFLAGS) $(ALL_MGNUCFLAGS) -S $< -o $@

.c.pic_s:
	$(MGNUC) $(ALL_GRADEFLAGS) $(ALL_MGNUCFLAGS) $(CFLAGS_FOR_PIC) \
		-S $< -o $@

.c.i:
	$(MGNUC) $(ALL_GRADEFLAGS) $(ALL_MGNUCFLAGS) -E $< > $@


#-----------------------------------------------------------------------------#
#
# Rules for compiling C files in a subdirectory.
# Note that we need both these rules and the ones above,
# since even if the compiler generates all of its files in subdirectories,
# the user may have some C files of their own which need to be compiled.
#

ifneq ($(MMAKE_USE_MMC_MAKE),yes)

ifneq ("$(cs_subdir)","")

$(os_subdir)%.$O : $(cs_subdir)%.c
	$(MGNUC) $(ALL_GRADEFLAGS) $(ALL_MGNUCFLAGS) -c $< $(OBJFILE_OPT)$@

$(os_subdir)%.pic_o : $(cs_subdir)%.c
	$(MGNUC) $(ALL_GRADEFLAGS) $(ALL_MGNUCFLAGS) $(CFLAGS_FOR_PIC) \
		-c $< -o $@

%.s: $(cs_subdir)%.c
	$(MGNUC) $(ALL_GRADEFLAGS) $(ALL_MGNUCFLAGS) -S $< -o $@

%.pic_s: $(cs_subdir)%.c
	$(MGNUC) $(ALL_GRADEFLAGS) $(ALL_MGNUCFLAGS) $(CFLAGS_FOR_PIC) \
		-S $< -o $@

%.i: $(cs_subdir)%.c
	$(MGNUC) $(ALL_GRADEFLAGS) $(ALL_MGNUCFLAGS) -E $< > $@

endif # $(cs_subdir) != ""

endif # $(MMAKE_USE_MMC_MAKE) != yes

#-----------------------------------------------------------------------------#
#
# Rules for compiling IL files in the user's source directory.
# Note that we need both these rules and the ones above,
# since even if the compiler generates all of its files in subdirectories,
# the user may have some il or C# files of their own which need to be
# compiled.
#
# To avoid possible problems with invoking these commands unintentionally,
# we only activate these rules when in an IL grade.
#

ifeq ($(findstring il,$(GRADE)),il)

.il.dll:
	$(ILASM) $(ALL_ILASMFLAGS) /dll /quiet /OUT=$@ $<

.il.exe:
	$(ILASM) $(ALL_ILASMFLAGS) /quiet /OUT=$@ $<

.cs.dll:
	$(CSC) /t:library /lib:`$(FIX_PATH_FOR_CSC) $(MERC_DLL_DIR)` \
		/out:$@ $(CSHARP_ASSEMBLY_REFS-$*) $(EXTRA_CSCFLAGS) $<

.cs.exe:
	$(CSC) /lib:`$(FIX_PATH_FOR_CSC) $(MERC_DLL_DIR)` /out:$@ \
		$(CSHARP_ASSEMBLY_REFS-$*) $(EXTRA_CSCFLAGS) $<

endif # $(findstring il,$(GRADE)) != ""

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

ifeq ($(MMAKE_USE_MMC_MAKE),yes)

# Always attempt to rebuild these files, even if they exist.
.PHONY: $(ALL_MC_BUILD_FILES) *.err
$(ALL_MC_BUILD_FILES):
	$(MCM) $@

%.err:
	$(MCM) $@

# If we don't know how to make the file, try using `mmc --make'.
.DEFAULT:
	$(MCM) $@

clean_local:
	$(MCM) $(MERCURY_MAIN_MODULES:%=%.clean)

realclean_local:
	$(MCM) $(MERCURY_MAIN_MODULES:%=%.realclean)

endif # $(MMAKE_USE_MMC_MAKE) == yes

#-----------------------------------------------------------------------------#
#
# Targets for cleaning up.
#
# Note that the actions for most of these targets are in the
# automatically generated `.d' files.
#

.PHONY: clean realclean clean_prof_files

clean_prof_files:
	-rm -f Prof.CallPair Prof.Counts Prof.Decl Prof.MemWords Prof.MemCells

#
# The `clean' and `realclean' targets are implemented via `clean_local'
# and `realclean_local'.  This allows a user to add rules in their
# Mmakefile to do a recursive mmake clean, for example, while still being
# able to use the local versions in their original form.
#

.PHONY: clean_local realclean_local

realclean: realclean_local

clean: clean_local

realclean_local: clean_local

clean_local: clean_prof_files

#-----------------------------------------------------------------------------#
#
# Targets for building and installing libraries.
#

# Note: the `lib%.install_ints' rule is generated in each module's `.dep'
# file so it can be more easily customised based on the desired level of
# intermodule optimisation.  Likewise the `lib%.install_grade_hdrs' is also
# generated in the `.dep' file, since it depends on the setting of
# the `--high-level-code' option.

.PHONY: lib%.install
lib%.install: lib%.install_ints lib%.install_hdrs lib%.install_library
	$(MMAKE) lib$*.install_grades

.PHONY: lib%.install_grade_init
lib%.install_grade_init: %.init install_grade_dirs
	$(INSTALL) `vpath_find $*.init` $(INSTALL_GRADE_MODULE_DIR)

.PHONY: lib%.install_library
lib%.install_library: lib%.$A lib%.$(EXT_FOR_SHARED_LIB) \
			install_grade_dirs lib%.install_grade_hdrs \
			lib%.install_opts lib%.install_grade_init
	$(INSTALL) `vpath_find lib$*.$A lib$*.$(EXT_FOR_SHARED_LIB)` \
			$(INSTALL_MERC_LIB_DIR)
	$(RANLIB) $(RANLIBFLAGS) $(INSTALL_MERC_LIB_DIR)/lib$*.$A

# XXX grade_files only contains the files for the default grade, not the
# current grade in each iteration of the loop over ALL_LIBGRADES below.
lib%.install_grades:
	rm -rf tmp_dir && \
	mkdir tmp_dir && \
	grade_files="$(foreach ext,$(GRADE_SUBDIR_EXTS),$($*.$(ext)s))" && \
	for file in x $$grade_files; do \
		if [ "$$file" != "x" ]; then \
			mv -f $$file tmp_dir > /dev/null 2>&1; \
			true; \
		fi; \
	done && \
	{ mv -f $(deps_subdir)$*.dep $(deps_subdir)$*.dv \
		*.a *.so tmp_dir || true; } && \
	for grade in $(ALL_LIBGRADES); do \
		if [ "$$grade" != "$(GRADE)" ]; then \
			$(MMAKE) GRADE=$$grade $*.depend || \
				exit 1; \
			$(MMAKE) GRADE=$$grade lib$*.install_library || \
				exit 1; \
			for file in x $$grade_files; do \
				if [ "$$file" != "x" ]; then \
					rm -f $$file; \
				fi; \
			done; \
			rm -f $(deps_subdir)$*.dep $(deps_subdir)$*.dv \
				*.a *.so; \
		fi; \
	done && \
	for file in x $$grade_files; do \
		if [ "$$file" != "x" ]; then \
		    mv -f tmp_dir/`basename $$file` $$file > /dev/null 2>&1; \
		    true; \
		fi; \
	done && \
	{ mv -f tmp_dir/*.dep tmp_dir/*.dv $(deps_subdir).; \
		mv -f tmp_dir/* .; rmdir tmp_dir; true; }

.PHONY: install_lib_dirs
install_lib_dirs:
	-[ -d $(INSTALL_INT_DIR) ] || $(INSTALL_MKDIR) $(INSTALL_INT_DIR)
	-[ -d $(INSTALL_INC_DIR) ] || $(INSTALL_MKDIR) $(INSTALL_INC_DIR)
	-[ -d $(INSTALL_MODULE_DIR) ] || $(INSTALL_MKDIR) $(INSTALL_MODULE_DIR)
	# The following is needed to support the `--use-subdirs' option
	-[ -d $(INSTALL_INT_DIR)/Mercury ] || \
		$(INSTALL_MKDIR) $(INSTALL_INT_DIR)/Mercury

.PHONY: install_grade_dirs
install_grade_dirs: #install_lib_dirs
	-[ -d $(INSTALL_MERC_LIB_DIR) ] || \
		$(INSTALL_MKDIR) $(INSTALL_MERC_LIB_DIR)
	-[ -d $(INSTALL_GRADE_INC_DIR) ] || \
		$(INSTALL_MKDIR) $(INSTALL_GRADE_INC_DIR)
	-[ -d $(INSTALL_GRADE_INT_DIR) ] || \
		$(INSTALL_MKDIR) $(INSTALL_GRADE_INT_DIR)
	-[ -d $(INSTALL_GRADE_MODULE_DIR) ] || \
		$(INSTALL_MKDIR) $(INSTALL_GRADE_MODULE_DIR)
	# The following is needed to support the `--use-subdirs' option
	-[ -d $(INSTALL_GRADE_INC_DIR)/Mercury ] || \
		$(INSTALL_MKDIR) $(INSTALL_GRADE_INC_DIR)/Mercury
	-[ -d $(INSTALL_GRADE_INT_DIR)/Mercury ] || \
		$(INSTALL_MKDIR) $(INSTALL_GRADE_INT_DIR)/Mercury

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