# This Makefile is meant to be used with GNU Make. It builds EverParse
# validators and parsers corresponding to the data formats specified
# in src/*.3d files, as well as a test program to run them.

# Default rule when `make` is run without argument. This rule MUST
# appear first, so we define it here and make it point to a `world`
# rule that will depend on variables defined in the
# EverParse-generated Makefile.
all: world

# QD_HOME is necessary for the 3d executable. It needs to point to the
# root of the EverParse source tree. However, QD_HOME is not needed if
# you run everparse.sh or everparse.cmd from the binary package.
QD_HOME ?= $(realpath ../../../..)
export QD_HOME

########################################################
# Variables needed by the EverParse-generated Makefile #
########################################################

# EVERPARSE_HOME: root of the EverParse tree (source tree or contents
# of the binary package.)
EVERPARSE_HOME=$(QD_HOME)

# Command to run EverParse: path to either the 3d executable or the
# everparse.sh or everparse.cmd script from the EverParse binary
# package
EVERPARSE_CMD=$(EVERPARSE_HOME)/src/3d/3d

# Output directory for .c/.h files as well as temporary files (.fst,
# .krml, etc.)
EVERPARSE_OUTPUT_DIR=obj

# Input directory containing .3d (and auxiliary .3d.copyright.txt)
# files
EVERPARSE_INPUT_DIR=src

# If a .3d file contains a `refining` clause, then the C compiler must
# be given the include path that contains the .h files pointed to by
# such clauses.
CFLAGS += -I src

#########################################
# Generating and including the Makefile #
#########################################

# Define the name and path of the generated Makefile. We cleverly
# decide to have it generated into the output directory along with all
# temporary files.
everparse_makefile=$(EVERPARSE_OUTPUT_DIR)/EverParse.Makefile

# Create the output directory if it does not exist
$(EVERPARSE_OUTPUT_DIR):
	mkdir -p $@

# Generate the Makefile if any .3d file is modified
$(everparse_makefile): $(wildcard src/*.3d) $(EVERPARSE_OUTPUT_DIR)
	$(EVERPARSE_CMD) --makefile gmake --makefile_name $@ src/Test.3d

# Include the generated Makefile
include $(everparse_makefile)

#############################
# Building the test program #
#############################

# Collect all .o files to be built: add the .o files corresponding to
# the handwritten .c files, as well as those corresponding to the .c
# files generated by EverParse.
all_o_files=$(EVERPARSE_ALL_O_FILES) $(EVERPARSE_OUTPUT_DIR)/main.o

# Compile the handwritten .c file. Since that file depends on .h files
# generated by EverParse, we need to include both the output directory
# and the EverParse library directory into the compiler's include
# path.
$(EVERPARSE_OUTPUT_DIR)/main.o: $(EVERPARSE_INPUT_DIR)/main.c $(EVERPARSE_OUTPUT_DIR)/TestWrapper.h
	$(CC) $(CFLAGS) -I $(EVERPARSE_OUTPUT_DIR) -I $(EVERPARSE_HOME)/src/3d -c -o $@ $<

# Link the test program
$(EVERPARSE_OUTPUT_DIR)/test.exe: $(all_o_files)
	$(CC) $(LDFLAGS) -o $@ $^

# Run the test program
test: $(EVERPARSE_OUTPUT_DIR)/test.exe
	$<

###########
# Cleanup #
###########

# Since everything is output to the same directory, including the
# generated Makefile, it is enough to remove that directory.
clean:
	rm -rf $(EVERPARSE_OUTPUT_DIR)

#######################################################
# Specifying the `world` rule run by the default rule #
#######################################################

# This rule is for continuous integration only (for the purpose of
# testing EverParse.) It can be ignored by users.
ci: $(EVERPARSE_ALL_O_FILES)
	! test -e $(EVERPARSE_OUTPUT_DIR)/EverParse.h
	! test -e $(EVERPARSE_OUTPUT_DIR)/Lib.h
	$(EVERPARSE_CMD) --check_inplace_hash src/Point.3d=$(EVERPARSE_OUTPUT_DIR)/Point.h
	$(EVERPARSE_CMD) --check_inplace_hash src/Point.3d=$(EVERPARSE_OUTPUT_DIR)/Point.c

# Specify the behavior of the default rule
world: ci test

# Declare all phony rules.
# Cf. https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
.PHONY: all world test clean ci
