############################################################
# Define subdirectories
#

CMP = $(dir compiler)
SYS = $(dir system)
SIM = $(dir simulator)
TAB = $(dir tables)
DIS = $(dir disassembler)
FNT = $(dir front)
TBL = $(dir tables)
LOD = $(dir loader)
LNK = $(dir linker)
TST = $(dir test)
INC = $(dir include)

############################################################
# Compile flags
#

OCAMLINCLUDES += $(CMP) $(DIS) $(SIM) $(LOD)
OCAMLFLAGS= -w -A
CFLAGS += -g

############################################################
# Compilation files
#

CMP_ML[] =
    $(CMP)/absyn
    $(CMP)/annvariables
    $(CMP)/bytecode
    $(CMP)/clausegen
    $(CMP)/clauses
    $(CMP)/codegen
    $(CMP)/compile
    $(CMP)/errormsg
    $(CMP)/instr
    $(CMP)/lplex
    $(CMP)/lpyacc
    $(CMP)/option
    $(CMP)/parse
    $(CMP)/pervasive
    $(CMP)/pervasiveutils
    $(CMP)/preabsyn
    $(CMP)/processclauses
    $(CMP)/registers
    $(CMP)/spitcode
    $(CMP)/symbol
    $(CMP)/table
    $(CMP)/translate
    $(CMP)/typereduction
    $(CMP)/types

DEP_ML[] =
    $(CMP)/compile
    $(CMP)/lplex
    $(CMP)/lpyacc
    $(CMP)/errormsg
    $(CMP)/symbol
    $(CMP)/preabsyn
    $(CMP)/table

PAR_ML[] =
    $(CMP)/absyn
    $(CMP)/clauses
    $(CMP)/compile
    $(CMP)/errormsg
    $(CMP)/explicit
    $(CMP)/lplex
    $(CMP)/lpyacc
    $(CMP)/option
    $(CMP)/parse
    $(CMP)/pervasive
    $(CMP)/pervasiveutils
    $(CMP)/preabsyn
    $(CMP)/symbol
    $(CMP)/table
    $(CMP)/translate
    $(CMP)/types

DIS_ML[] =
    $(DIS)/context
    $(DIS)/disassembly
    $(DIS)/label

FNT_ML[] =
    $(FNT)/parseargs

FNT_C[] =
    $(FNT)/ccode_stubs
    $(FNT)/front_c
    $(FNT)/query_c
    $(FNT)/readterm_c
    $(FNT)/ocaml_wrap

FNT_ML_TO_C[] =
    $(FNT)/module
    $(FNT)/query
    $(FNT)/front
    $(FNT)/readterm
    $(FNT)/simerrors

SIM_C[] =
    $(SIM)/abstmachine
    $(SIM)/dataformats
    $(SIM)/hnorm
    $(SIM)/hnormlocal
    $(SIM)/hopu
    $(SIM)/io-datastructures
    $(SIM)/mcstring
    $(SIM)/printterm
    $(SIM)/simdispatch
    $(SIM)/siminit
    $(SIM)/siminstr
    $(SIM)/siminstrlocal
    $(SIM)/simulator
    $(SIM)/trail
    $(SIM)/types
    $(SIM)/builtins/builtins
    $(SIM)/builtins/compexp
    $(SIM)/builtins/evalexp
    $(SIM)/builtins/io
    $(SIM)/builtins/meta
    $(SIM)/builtins/readterm

SYS_C[] =
    $(SYS)/error
    $(SYS)/memory
    $(SYS)/message
    $(SYS)/stream

TBL_C[] =
    $(TBL)/instructions
    $(TBL)/pervasives
    $(TBL)/pervinit

LOD_ML[] =
    $(LOD)/loadmodtab

LOD_C[] =
    $(LOD)/bvrtab
    $(LOD)/code
    $(LOD)/const
    $(LOD)/file
    $(LOD)/hashtab
    $(LOD)/implgoal
    $(LOD)/importtab
    $(LOD)/kind
    $(LOD)/loader
    $(LOD)/loadmodtab
    $(LOD)/searchtab
    $(LOD)/strings
    $(LOD)/tyskel

LNK_C[] =
    $(LNK)/bvrtab
    $(LNK)/CallResolution
    $(LNK)/code
    $(LNK)/const
    $(LNK)/file
    $(LNK)/hashtab
    $(LNK)/implgoal
    $(LNK)/importtab
    $(LNK)/kind
    $(LNK)/module
    $(LNK)/linker_message
    $(LNK)/rename
    $(LNK)/stringspace
    $(LNK)/tree
    $(LNK)/tyskel
    $(LNK)/vector
    $(LNK)/VectorRW
    $(FNT)/linker_c

INC_C[] =
    $(INC)/obstack

DIS_MAIN = $(FNT)/disassemblerfront
CMP_MAIN = $(FNT)/compilerfront
SIM_MAIN = $(FNT)/simulatorfront
LNK_MAIN = $(FNT)/linkerfront
DEP_MAIN = $(FNT)/dependfront
PAR_MAIN = $(FNT)/parsefront

############################################################
# Platform specific changes
#

if $(mem $(SYSNAME), Linux)
    YACC = bison -by
    LEX = flex
    export

if $(mem $(OSTYPE), Cygwin Win32)
    YACC = bison -by
    LEX = flex
    CC = i686-pc-mingw32-gcc
    INC_C[] += $(INC)/byteswap $(INC)/search
    export

if $(mem $(SYSNAME), Darwin)
    INC_C[] += $(INC)/byteswap $(INC)/search
    export

if $(mem $(SYSNAME), OpenBSD)
    INC_C[] += $(INC)/search
    export


############################################################
# Generated Files
#

.SUBDIRS: tables_gen

INSTR_ML_FILES[] =
    $(CMP)/instr.mli
    $(CMP)/instr.ml

INSTR_C_FILES[] =
    $(TBL)/instructions.h
    $(TBL)/instructions.c
    $(SIM)/simdispatch.c

INSTR_FILES[] =
    $(INSTR_ML_FILES)
    $(INSTR_C_FILES)

PERV_ML_FILES[] =
    $(CMP)/pervasive.mli
    $(CMP)/pervasive.ml

PERV_C_FILES[] =
    $(TBL)/pervasives.h
    $(TBL)/pervasives.c

PERV_FILES[] =
    $(PERV_ML_FILES)
    $(PERV_C_FILES)

LocalCGeneratedFiles($(INSTR_C_FILES) $(PERV_C_FILES))
LocalOCamlGeneratedFiles($(INSTR_ML_FILES) $(PERV_ML_FILES))

INSTR_GEN = tables_gen/instrformats/instr_gen$(EXE)
$(INSTR_FILES): $(INSTR_GEN)
    cd $(dirname $(INSTR_GEN)) && ./$(basename $(INSTR_GEN))


PERV_GEN = tables_gen/pervasives/perv_gen$(EXE)
PERV_IN = pervasives.in
$(PERV_FILES): $(PERV_GEN)
    cd $(dirname $(PERV_GEN)) && ./$(basename $(PERV_GEN)) $(PERV_IN)

.PHONY: gen
gen: $(INSTR_ML_FILES) $(PERV_ML_FILES) $(INSTR_C_FILES) $(PERV_C_FILES)


############################################################
# Include subdirectories
#

.SUBDIRS: compiler disassembler front include linker loader simulator system tables
    if $(file-exists OMakefile)
        include OMakefile


############################################################
# Build Targets
#

# If the file "prebuilt" exists then assume the binaries are
# already built by a 3rd party tool

if $(not $(file-exists prebuilt))
  OCamlProgram(tjcc, $(CMP_MAIN) $(CMP_ML) $(LOD_ML) $(FNT_ML))

  OCamlProgram(tjdis, $(DIS_MAIN) $(CMP_ML) $(LOD_ML) $(DIS_ML) $(FNT_ML))

  OCamlProgram(tjdepend, $(DEP_MAIN) $(DEP_ML) $(FNT_ML))
  
  OCamlProgram(tjparse, $(PAR_MAIN) $(PAR_ML) $(FNT_ML))

  # The simulator and linker require linking with C code

  section
    StaticCLibrary(libsim, \
      $(SIM_C) $(SYS_C) $(TBL_C) $(FNT_C) $(LOD_C) $(LNK_C) $(INC_C))
    OCAML_CLIBS += libsim
    OCamlProgram(tjsim, \
      $(SIM_MAIN) $(LOD_ML) $(CMP_ML) $(FNT_ML) $(FNT_ML_TO_C))

  section
    StaticCLibrary(liblink, $(SIM_C) $(SYS_C) $(TBL_C) $(LNK_C) $(INC_C))
    OCAML_CLIBS += liblink
    OCamlProgram(tjlink, $(LNK_MAIN) $(FNT_ML))


TJCC = $(CWD)/tjcc$(EXE)
TJSIM = $(CWD)/tjsim$(EXE)
TJDIS = $(CWD)/tjdis$(EXE)
TJLINK = $(CWD)/tjlink$(EXE)
TJDEPEND = $(CWD)/tjdepend$(EXE)
TJPARSE = $(CWD)/tjparse$(EXE)

.PHONY: all
all: $(TJCC) $(TJSIM) $(TJDIS) $(TJLINK) $(TJDEPEND) $(TJPARSE)

############################################################
# Testing Targets
#
# Defined last so that it can see TJCC, etc

if $(file-exists $(TST))
   .SUBDIRS: $(TST)

.PHONY: test
test: compiler-test compiler-negative-test linker-test system-test
