#
# Copyright (c) 2003, 2004 The University of Wroclaw.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#    1. Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#    2. Redistributions in binary form must reproduce the above copyright
#       notice, this list of conditions and the following disclaimer in the
#       documentation and/or other materials provided with the distribution.
#    3. The name of the University may not be used to endorse or promote
#       products derived from this software without specific prior
#       written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
# NO EVENT SHALL THE UNIVERSITY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#

# Include configuration determined by configure script.
include ../config.mak

############################################################
# VARIABLES
############################################################

COMPILER_PATH = ../boot/
NCC_FLAGS     = -pedantic-lexer $(NEM_FLAGS)
COMPILER      = $(COMPILER_PATH)ncc.exe
COMPILER_DEP  = $(COMPILER_PATH)ncc.exe $(COMPILER_PATH)Nemerle.Macros.dll
EXECUTE       = $(NET_ENGINE) $(NET_FLAGS)
RUN_COMPILER  = $(Q)$(TIME) $(EXECUTE) $(COMPILER) -no-stdlib -r:mscorlib -r:System $(NCC_FLAGS)

GENERIC_SRC =

NEMERLE_DLL_SRC = \
	../lib/internal-numbered.n	\
	../lib/internal.n		\
	../lib/core.n			\
	../lib/getopt.n			\
	../lib/hashtable.n		\
	../lib/icollection.n		\
	../lib/ienumerable.n		\
	../lib/ienumerator.n		\
	../lib/input.n			\
	../lib/linkedlist.n		\
	../lib/list.n			\
	../lib/option.n			\
	../lib/queue.n			\
	../lib/stack.n			\
	../lib/tree.n			\
	../lib/idictionaryenumerator.n	\
	../lib/idictionary.n		\
	../lib/dictionaryentry.n	\
	../lib/heap.n			\
	../lib/icomparable.n		\
	../lib/narray.n			\
	../lib/nstring.n                \


NEMERLE_COMPILER_DLL_SRC = \
	internaltypes.n \
	constantfolder.n \
	numerictype.n \
	cgexpr.n \
	cgopt.n \
	external.n \
	xmldump.n \
	cgil.n \
	cgmatch.n \
	globalenv.n \
	localvalue.n \
	macros.n \
	macroregistry.n \
	members.n \
	util.n \
	scan_globals.n \
	flags.n \
	lexer.n \
	cgtree.n \
	passes.n \
	tycon.n \
	typingcontext.n \
	typattern.n \
	tyexpr.n \
	typebuilder.n \
	ast.n \
	parsetree.n \
	typedtree.n \
	parser.n \
	tycodec.n \
	tyvars.n \
	tyutil.n \
	itypemodifier.n \
	attribute.n \



NCC_EXE_SRC       = main.n

STDMACROS_DLL_SRC = \
        ../macros/core.n \
	../macros/operators.n \
        ../macros/io.n \

DISTFILES = \
	ChangeLog                   \
	Makefile                    \
	$(NEMERLE_COMPILER_DLL_SRC) \
	$(NCC_EXE_SRC)              \

LIBDISTFILES = \
	../lib/ChangeLog   \
	../lib/STDLIB      \
	../lib/TODO        \
	../lib/Makefile    \
	$(NEMERLE_DLL_SRC) \


############################################################
# OUTPUT
############################################################

COMPARE = @echo COMPARE $1 $2 $3
DEAS    = @echo DASM    $1 $2
AOT     = @echo NGEN    $1
COMP    = @echo COMPILE $1
MKDIR   = @echo MKDIR   $1
TAR     = @echo TAR     $1
CP      = @echo CP      $1
INST	= @echo INSTALL $1

############################################################
# TARGETS
############################################################


# Default rule is to build a compiler.  It is mainly used by
# developers as they are the only people invoking make from
# inside this directory.  All other people should invoke
# make boot, or have it invoked from the top-level make.
all: stage1

# This is necessary to make sure, that configuration file
# has been generated, and it is up to date.
../config.mak:
	$(Q)cd .. && $(MAKE) config.mak

stage1:
	$(Q)$(MAKE) STAGE=$@ COMPILER_PATH=../boot/ aux-stage

stage2:
	$(Q)$(MAKE) STAGE=$@ COMPILER_PATH=out.stage1/ aux-stage

stage3:
	$(Q)$(MAKE) STAGE=$@ COMPILER_PATH=out.stage2/ last-stage

aux-stage:
	$(MKDIR) out.$(STAGE)
	$(Q)mkdir -p out.$(STAGE)
	$(Q)$(MAKE) aux-stage-files

aux-stage-files: \
		out.$(STAGE)/Nemerle.$(STAGE).dll \
		out.$(STAGE)/Nemerle.Compiler.$(STAGE).dll \
		out.$(STAGE)/Nemerle.Macros.dll \
		out.$(STAGE)/ncc.exe

last-stage:
	$(MKDIR) out.$(STAGE)
	$(Q)mkdir -p out.$(STAGE)
	$(Q)$(MAKE) last-stage-files

last-stage-files: \
		out.$(STAGE)/Nemerle.dll \
		out.$(STAGE)/Nemerle.Compiler.dll \
		out.$(STAGE)/Nemerle.Macros.dll \
		out.$(STAGE)/ncc.exe

lib:
	$(MAKE) STAGE=stage1 out.stage1/Nemerle.stage1.dll

boot: stage1 stage2 stage3 compare ngen-stage3

ngen-stage3:
	$(AOT) Nemerle.dll
	$(Q)$(NGEN) out.stage3/Nemerle.dll
	$(AOT) Nemerle.Compiler.dll
	$(Q)$(NGEN) out.stage3/Nemerle.Compiler.dll
	$(AOT) Nemerle.Macros.dll
	$(Q)$(NGEN) out.stage3/Nemerle.Macros.dll
	$(AOT) ncc.exe
	$(Q)$(NGEN) out.stage3/ncc.exe

compare:
	$(Q)$(MAKE) compare-one-with-stage CMP_TARGET=Nemerle
	$(Q)$(MAKE) compare-one-with-stage CMP_TARGET=Nemerle.Compiler
	$(Q)$(MAKE) compare-one CMP_TARGET=Nemerle.Macros.dll
	$(Q)$(MAKE) compare-one CMP_TARGET=ncc.exe

compare-one:
	$(Q)test -f out.stage2/$(CMP_TARGET)
	$(Q)test -f out.stage3/$(CMP_TARGET) 
	$(DEAS) [stage2] $(CMP_TARGET)
	$(Q)$(DASM) out.stage2/$(CMP_TARGET) | \
		grep -v -E '(^//|// GUID|MVID)' \
		| sed -e 's/\.stage2//g' > $(CMP_TARGET)2.il
	$(DEAS) [stage3] $(CMP_TARGET)
	$(Q)$(DASM) out.stage3/$(CMP_TARGET) | \
		grep -v -E '(^//|// GUID|MVID)' \
		| sed -e 's/\.stage2//g' > $(CMP_TARGET)3.il
	$(COMPARE) [stage2] [stage3] $(CMP_TARGET)
	$(Q)diff -u -w $(CMP_TARGET)2.il $(CMP_TARGET)3.il
	$(Q)rm -f $(CMP_TARGET)2.il $(CMP_TARGET)3.il

compare-one-with-stage:
	$(Q)test -f out.stage2/$(CMP_TARGET).stage2.dll
	$(Q)test -f out.stage3/$(CMP_TARGET).dll
	$(DEAS) [stage2] $(CMP_TARGET)
	$(Q)$(DASM) out.stage2/$(CMP_TARGET).stage2.dll | \
		grep -v -E '(^//|// GUID|MVID)' \
		| sed -e 's/\.stage2//g' > $(CMP_TARGET)2.il
	$(DEAS) [stage3] $(CMP_TARGET)
	$(Q)$(DASM) out.stage3/$(CMP_TARGET).dll | \
		grep -v -E '(^//|// GUID|MVID)' \
		| sed -e 's/\.stage2//g' > $(CMP_TARGET)3.il
	$(COMPARE) [stage2] [stage3] $(CMP_TARGET)
	$(Q)diff -u -w $(CMP_TARGET)2.il $(CMP_TARGET)3.il
	$(Q)rm -f $(CMP_TARGET)2.il $(CMP_TARGET)3.il

out.$(STAGE)/Nemerle.dll out.$(STAGE)/Nemerle.$(STAGE).dll: \
		$(COMPILER_DEP) $(NEMERLE_DLL_SRC)
	$(COMP) [$(STAGE)] Nemerle.dll
	$(Q)$(RUN_COMPILER) -target-library -out:$@ $(GENERIC_SRC) $(NEMERLE_DLL_SRC)

out.$(STAGE)/Nemerle.Compiler.dll: \
		$(COMPILER_DEP) out.$(STAGE)/Nemerle.dll $(NEMERLE_COMPILER_DLL_SRC)
	$(COMP) [$(STAGE)] Nemerle.Compiler.dll
	$(Q)$(RUN_COMPILER) -target-library -out:$@ \
		-reference:out.$(STAGE)/Nemerle.dll \
		$(GENERIC_SRC) $(NEMERLE_COMPILER_DLL_SRC)

out.$(STAGE)/Nemerle.Compiler.$(STAGE).dll: \
		$(COMPILER_DEP) out.$(STAGE)/Nemerle.$(STAGE).dll $(NEMERLE_COMPILER_DLL_SRC)
	$(COMP) [$(STAGE)] Nemerle.Compiler.dll
	$(Q)$(RUN_COMPILER) -target-library -out:$@ \
		-reference:out.$(STAGE)/Nemerle.$(STAGE).dll \
		$(GENERIC_SRC) $(NEMERLE_COMPILER_DLL_SRC)

out.stage1/Nemerle.Macros.dll: $(COMPILER_DEP) out.stage1/Nemerle.stage1.dll \
		out.stage1/Nemerle.Compiler.stage1.dll $(STDMACROS_DLL_SRC)
	$(COMP) [stage1] Nemerle.Macros.dll
	$(Q)$(RUN_COMPILER) -target-library -out:$@ \
		-reference:out.stage1/Nemerle.stage1.dll \
		-reference:out.stage1/Nemerle.Compiler.stage1.dll \
		$(GENERIC_SRC) $(STDMACROS_DLL_SRC)

out.stage2/Nemerle.Macros.dll: $(COMPILER_DEP) out.stage2/Nemerle.stage2.dll \
		out.stage2/Nemerle.Compiler.stage2.dll $(STDMACROS_DLL_SRC)
	$(COMP) [stage2] Nemerle.Macros.dll
	$(Q)$(RUN_COMPILER) -target-library -out:$@ \
		-reference:out.stage2/Nemerle.stage2.dll \
		-reference:out.stage2/Nemerle.Compiler.stage2.dll \
		$(GENERIC_SRC) $(STDMACROS_DLL_SRC)

out.stage3/Nemerle.Macros.dll: $(COMPILER_DEP) out.$(STAGE)/Nemerle.dll \
		out.$(STAGE)/Nemerle.Compiler.dll $(STDMACROS_DLL_SRC)
	$(COMP) [stage3] Nemerle.Macros.dll
	$(Q)$(RUN_COMPILER) -target-library -out:$@ \
		-reference:out.$(STAGE)/Nemerle.dll \
		-reference:out.$(STAGE)/Nemerle.Compiler.dll \
		$(GENERIC_SRC) $(STDMACROS_DLL_SRC)

out.stage1/ncc.exe: $(COMPILER_DEP) out.stage1/Nemerle.stage1.dll \
		out.stage1/Nemerle.Compiler.stage1.dll $(NCC_EXE_SRC)
	$(COMP) [stage1] ncc.exe
	$(Q)$(RUN_COMPILER) -target-exe -out:$@ \
		-reference:out.stage1/Nemerle.stage1.dll \
		-reference:out.stage1/Nemerle.Compiler.stage1.dll \
		$(GENERIC_SRC) $(NCC_EXE_SRC)

out.stage2/ncc.exe: $(COMPILER_DEP) out.stage2/Nemerle.stage2.dll \
		out.stage2/Nemerle.Compiler.stage2.dll $(NCC_EXE_SRC)
	$(COMP) [stage2] ncc.exe
	$(Q)$(RUN_COMPILER) -target-exe -out:$@ \
		-reference:out.stage2/Nemerle.stage2.dll \
		-reference:out.stage2/Nemerle.Compiler.stage2.dll \
		$(GENERIC_SRC) $(NCC_EXE_SRC)

out.stage3/ncc.exe: $(COMPILER_DEP) out.$(STAGE)/Nemerle.dll \
		out.$(STAGE)/Nemerle.Compiler.dll $(NCC_EXE_SRC)
	$(COMP) [stage3] ncc.exe
	$(Q)$(RUN_COMPILER) -target-exe -out:$@ \
		-reference:out.$(STAGE)/Nemerle.dll \
		-reference:out.$(STAGE)/Nemerle.Compiler.dll \
		$(GENERIC_SRC) $(NCC_EXE_SRC)

sync:
	cd out.stage3 ; \
	for x in *.dll *.exe ; do \
		mv -vf ../../boot/$$x ../../boot/$$x.old ; \
		cp -vf $$x.so ../../boot/$$x.so ; \
		cp -vf $$x ../../boot/$$x ; \
	done

.PHONY: boot all tests t test ncc-il

t test: tests

tests:
	$(Q)cd testsuite && $(MAKE)

profile:
	../misc/profiler/runprof

halfboot:
	touch out.stage1/*
	touch out.stage2/Nemerle.stage2.dll
	$(Q)$(MAKE) boot

install:
	$(Q)if test ! -d $(DESTDIR)$(LIBDIR); then $(INSTALL) -d $(DESTDIR)$(LIBDIR); fi
	$(Q)if test ! -d $(DESTDIR)$(BINDIR); then $(INSTALL) -d $(DESTDIR)$(BINDIR); fi
	$(INST) [$(LIBDIR)] Nemerle.Compiler.dll
	$(Q)$(INSTALL) -m 644 out.stage3/Nemerle.Compiler.dll $(DESTDIR)$(LIBDIR)/Nemerle.Compiler.dll
	$(INST) [$(LIBDIR)] Nemerle.dll
	$(Q)$(INSTALL) -m 644 out.stage3/Nemerle.dll $(DESTDIR)$(LIBDIR)/Nemerle.dll
	$(INST) [$(LIBDIR)] Nemerle.Macros.dll
	$(Q)$(INSTALL) -m 644 out.stage3/Nemerle.Macros.dll $(DESTDIR)$(LIBDIR)/Nemerle.Macros.dll
	$(INST) [$(BINDIR)] ncc
	$(Q)if [ "$(NET_ENGINE)" = "" ] ; then \
		$(INSTALL) -m 755 ncc.exe $(DESTDIR)$(BINDIR)/ncc ; \
	else \
		$(INSTALL) -m 755 ncc.exe $(DESTDIR)$(BINDIR)/ncc.exe && \
		echo "#!/bin/sh" > $(DESTDIR)$(BINDIR)/ncc && \
		echo '$(NET_ENGINE) $(BINDIR)/ncc.exe "$$@"' >> $(DESTDIR)$(BINDIR)/ncc ; \
		chmod 755 $(DESTDIR)$(BINDIR)/ncc ; \
	fi

# This target is used to build the tarball.  It is passed the
# directory name, where all files should be copied.
dist:
	$(MKDIR) $(DIR)/ncc
	$(MKDIR) $(DIR)/ncc/testsuite
	$(Q)mkdir $(DIR)/ncc/testsuite
	$(CP) '*.n'
	$(Q)cp $(DISTFILES) $(DIR)/ncc
	$(CP) '../lib/*.n'
	$(Q)cp $(LIBDISTFILES) $(DIR)/lib
	$(Q)mkdir $(DIR)/lib/tests
	$(Q)cp ../lib/tests/*.n $(DIR)/lib/tests
	$(Q)$(MAKE) -C testsuite dist DIR=../$(DIR)/ncc/testsuite

clean:
	cd testsuite && $(MAKE) clean
	rm -f *.exe.so *.dll.so *.pdb core.[0-9]* core
	rm -rf out.stage*
