# Semana 3: análisis asintótico y medición. Se usa dentro del entorno del curso.
#
#   make           compila los programas de la clase en build/
#   make lab       compila el laboratorio en build/lab/
#   make test      corre las pruebas de los ejemplos y de los apuntes
#   make test-lab  prueba su laboratorio; falla hasta que lo terminen
#   make clean     borra lo generado
#
# Los programas que cuentan y las pruebas llevan sanitizers. Los que miden tiempos se
# compilan con -O2 y sin sanitizers. Los programas de errors/ miden mal a propósito:
# no se compilan con make, sino con los comandos de los apuntes.

CXX = g++
WARNINGS = -Wall -Wextra -std=c++20
CHECKED = $(WARNINGS) -g -fsanitize=address,undefined
FAST = $(WARNINGS) -O2
SLOW = $(WARNINGS) -O0
BUILD = build
COUNTING = count_loops call_tree cases growth_table test_bench
TIMED = first_timer doubling cache_walk small_n sanitizer_cost

LAB_DIR ?= lab
OUT = $(BUILD)/$(LAB_DIR)
LAB_HEADERS = bench.h lab/check.h lab/work.h lab/mysteries.h lab/measure.h lab/vector_ops.h
LAB_SOURCES = lab/mysteries.cpp $(LAB_DIR)/measure.cpp $(LAB_DIR)/vector_ops.cpp
LAB_TARGETS = lab_tests run_doubling run_doubling_O0 run_session2 run_session2_O0

.PHONY: all lab test test-lab clean

all: $(COUNTING:%=$(BUILD)/%) $(TIMED:%=$(BUILD)/%) $(BUILD)/sanitizer_cost_san

$(COUNTING:%=$(BUILD)/%): $(BUILD)/%: %.cpp bench.h lab/check.h | $(BUILD)
	$(CXX) $(CHECKED) -Ilab $< -o $@

$(TIMED:%=$(BUILD)/%): $(BUILD)/%: %.cpp bench.h | $(BUILD)
	$(CXX) $(FAST) $< -o $@

# La misma medición, ahora con sanitizers: solo para comparar.
$(BUILD)/sanitizer_cost_san: sanitizer_cost.cpp bench.h | $(BUILD)
	$(CXX) $(FAST) -fsanitize=address,undefined $< -o $@

$(OUT)/lab_tests: lab/lab_tests.cpp $(LAB_SOURCES) $(LAB_HEADERS) | $(OUT)
	$(CXX) $(CHECKED) -I. -Ilab lab/lab_tests.cpp $(LAB_SOURCES) -o $@

$(OUT)/run_doubling: lab/run_doubling.cpp $(LAB_SOURCES) $(LAB_HEADERS) | $(OUT)
	$(CXX) $(FAST) -I. -Ilab lab/run_doubling.cpp $(LAB_SOURCES) -o $@

$(OUT)/run_doubling_O0: lab/run_doubling.cpp $(LAB_SOURCES) $(LAB_HEADERS) | $(OUT)
	$(CXX) $(SLOW) -I. -Ilab lab/run_doubling.cpp $(LAB_SOURCES) -o $@

$(OUT)/run_session2: $(LAB_DIR)/run_session2.cpp $(LAB_SOURCES) $(LAB_HEADERS) | $(OUT)
	$(CXX) $(FAST) -I. -Ilab $(LAB_DIR)/run_session2.cpp $(LAB_SOURCES) -o $@

$(OUT)/run_session2_O0: $(LAB_DIR)/run_session2.cpp $(LAB_SOURCES) $(LAB_HEADERS) | $(OUT)
	$(CXX) $(SLOW) -I. -Ilab $(LAB_DIR)/run_session2.cpp $(LAB_SOURCES) -o $@

$(BUILD):
	mkdir -p $@

$(OUT): | $(BUILD)
	mkdir -p $@

lab: $(LAB_TARGETS:%=$(OUT)/%)

# Si existe solution/, las pruebas también comprueban la solución del laboratorio.
test: all
	$(BUILD)/test_bench
	@if [ -d solution ]; then $(MAKE) --no-print-directory LAB_DIR=solution lab; fi
	python3 -m unittest discover -p 'test_*.py'

test-lab: all lab
	LAB_DIR=$(LAB_DIR) python3 -m unittest -v test_lab

clean:
	rm -rf $(BUILD) __pycache__
