################################################################################
# General Variables #
################################################################################
BASE_NAME := Main
CASES_INPUT := $(sort $(wildcard *.in))
CASES_OUTPUT := $(sort $(wildcard *.out))
TESTS := $(filter $(basename $(CASES_INPUT)),$(basename $(CASES_OUTPUT)))
SHELL := /bin/sh
LIMITER ?= timeout
LIMITER_FLAGS ?= --preserve-status -s SIGKILL 10s
export TIME=real %es\nuser %Us\nsys %Ss\nmem %MKB
################################################################################
# Compilation/Execution Variables #
################################################################################
CC ?= gcc
CC_FLAGS ?= -Wall -Wextra -pedantic -Wshadow -Wformat=2 -Wfloat-equal \
-Wconversion -Wlogical-op -Wshift-overflow=2 -Wduplicated-cond \
-Wcast-qual -Wcast-align -Wno-unused-result -Wno-sign-conversion
CXX ?= g++
CXX_FLAGS ?= -Wall -Wextra -pedantic -Wshadow -Wformat=2 -Wfloat-equal \
-Wconversion -Wlogical-op -Wshift-overflow=2 -Wduplicated-cond \
-Wcast-qual -Wcast-align -Wno-unused-result -Wno-sign-conversion
JC ?= javac
JC_FLAGS ?= -g
JAVA ?= java
JAVA_FLAGS ?=
PYTHON ?= python3
PYTHON_FLAGS ?=
RUBY ?= ruby
RUBY_FLAGS ?=
################################################################################
# File Variables #
################################################################################
COMPILED_SRCS :=
COMPILED_OBJS :=
INTERPRETED_SRCS :=
RESULTS :=
ifneq (,$(wildcard ./$(BASE_NAME).c))
COMPILED_SRCS += $(BASE_NAME).c
COMPILED_OBJS += $(BASE_NAME).c.exe
RESULTS += $(addsuffix .$(BASE_NAME).c.exe.res,$(TESTS))
endif
ifneq (,$(wildcard ./$(BASE_NAME).cpp))
COMPILED_SRCS += $(BASE_NAME).cpp
COMPILED_OBJS += $(BASE_NAME).cpp.exe
RESULTS += $(addsuffix .$(BASE_NAME).cpp.exe.res,$(TESTS))
endif
ifneq (,$(wildcard ./$(BASE_NAME).java))
COMPILED_SRCS += $(BASE_NAME).java
COMPILED_OBJS += $(BASE_NAME).class
RESULTS += $(addsuffix .$(BASE_NAME).class.res,$(TESTS))
endif
ifneq (,$(wildcard ./$(BASE_NAME).py))
INTERPRETED_SRCS += $(BASE_NAME).py
RESULTS += $(addsuffix .$(BASE_NAME).py.res,$(TESTS))
endif
ifneq (,$(wildcard ./$(BASE_NAME).rb))
INTERPRETED_SRCS += $(BASE_NAME).rb
RESULTS += $(addsuffix .$(BASE_NAME).rb.res,$(TESTS))
endif
STATS := $(patsubst %.res,%.stat,$(RESULTS))
CLEANABLE := $(filter $(COMPILED_OBJS) $(RESULTS) $(STATS),$(wildcard *))
################################################################################
# Phony Rules #
################################################################################
.PHONY: all build clean retest test
all: test
build: $(COMPILED_OBJS)
clean:
ifneq (,$(CLEANABLE))
rm $(CLEANABLE)
endif
retest: clean test
test: build $(RESULTS) $(STATS) $(CASES_OUTPUT)
@pass=0; \
fail=0; \
for test in $(patsubst %.res,%,$(RESULTS)); do \
echo "########################################"; \
printf "# %-29s # %s #\n" $$test \
$$(diff $$test.res "$$(echo "$$test" | cut -f 1 -d '.').out" \
2>&1>/dev/null && echo 'PASS' || echo 'FAIL'); \
echo "########################################"; \
cat $$test.stat; \
echo "########################################"; \
diff --color $$test.res "$$(echo "$$test" | cut -f 1 -d '.').out" \
&& pass=$$((pass + 1)) || fail=$$((fail + 1)); \
echo ; \
done; \
echo "########################################"; \
printf "# TOTAL: %-5s # PASS: %-3s # FAIL: %-3s #\n" \
$$((pass + fail)) $$pass $$fail; \
echo "########################################"
################################################################################
# Compiling Rules #
################################################################################
$(BASE_NAME).c.exe: $(BASE_NAME).c
$(CC) $(CC_FLAGS) $^ -o $@
$(BASE_NAME).cpp.exe: $(BASE_NAME).cpp
$(CXX) $(CXX_FLAGS) $^ -o $@
$(BASE_NAME).class: $(BASE_NAME).java
$(JC) $(JC_FLAGS) $^
################################################################################
# Running rules #
################################################################################
%.$(BASE_NAME).c.exe.res %.$(BASE_NAME).c.exe.stat: %.in $(BASE_NAME).c.exe
-@\time $(LIMITER) $(LIMITER_FLAGS) ./$(BASE_NAME).c.exe < $*.in \
> $*.$(BASE_NAME).c.exe.res 2> $*.$(BASE_NAME).c.exe.stat
%.$(BASE_NAME).cpp.exe.res: %.in $(BASE_NAME).cpp.exe
-@\time $(LIMITER) $(LIMITER_FLAGS) ./$(BASE_NAME).cpp.exe < $*.in \
> $*.$(BASE_NAME).cpp.exe.res 2> $*.$(BASE_NAME).cpp.exe.stat
%.$(BASE_NAME).class.res: %.in $(BASE_NAME).class
-@\time $(LIMITER) $(LIMITER_FLAGS) $(JAVA) $(JAVA_FLAGS) $(BASE_NAME) \
< $*.in > $*.$(BASE_NAME).class.res 2> $*.$(BASE_NAME).class.stat
%.$(BASE_NAME).py.res: %.in $(BASE_NAME).py
-@\time $(LIMITER) $(LIMITER_FLAGS) $(PYTHON) $(PYTHON_FLAGS) \
$(BASE_NAME).py < $*.in > $*.$(BASE_NAME).py.res \
2> $*.$(BASE_NAME).py.stat
%.$(BASE_NAME).rb.res: %.in $(BASE_NAME).rb
-@\time $(LIMITER) $(LIMITER_FLAGS) $(RUBY) $(RUBY_FLAGS) \
$(BASE_NAME).rb < $*.in > $*.$(BASE_NAME).rb.res \
2> $*.$(BASE_NAME).rb.stat