# Semana 6: ordenamiento y búsqueda binaria. 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-sorts       prueba solo la sesión 1 del laboratorio
#   make test-autocomplete  prueba solo la sesión 2 del laboratorio
#   make test-lab         prueba todo su laboratorio; falla hasta que lo terminen
#   make bench-sorts      mide sus ordenamientos, con -O2 y sin sanitizers
#   make bench-query      mide sus consultas, con -O2 y sin sanitizers
#   make clean            borra lo generado
#
# Los programas de errors/ tienen errores a propósito. No se compilan con make:
# los compilan las pruebas, y ustedes, con los comandos de los apuntes.

CXX = g++
CXXFLAGS = -Wall -Wextra -std=c++20 -g -fsanitize=address,undefined
BENCHFLAGS = -Wall -Wextra -std=c++20 -O2
LAB_DIR ?= lab
DATA ?= ../../data
BUILD = build
PROGRAMS = trace_merge trace_partition trace_search comparators test_examples
DATA_PROGRAMS = stability byte_order
BENCHES = count_sorts time_sorts word_search
COMMON_HEADERS = int_sorts.h inputs.h bench.h lab/terms_io.h
LAB_HEADERS = $(LAB_DIR)/sorts.h $(LAB_DIR)/autocomplete.h lab/fixed_pivot.h lab/terms_io.h lab/not_implemented.h

.PHONY: all lab test test-sorts test-autocomplete test-lab bench-sorts bench-query clean

all: $(PROGRAMS:%=$(BUILD)/%) $(DATA_PROGRAMS:%=$(BUILD)/%) $(BENCHES:%=$(BUILD)/%) $(BUILD)/byte_order_signed $(BUILD)/byte_order_unsigned

$(PROGRAMS:%=$(BUILD)/%) $(DATA_PROGRAMS:%=$(BUILD)/%): $(BUILD)/%: %.cpp $(COMMON_HEADERS) | $(BUILD)
	$(CXX) $(CXXFLAGS) $< -o $@

# El mismo programa, con char con signo y sin signo, sea cual sea la máquina.
$(BUILD)/byte_order_signed: byte_order.cpp lab/terms_io.h | $(BUILD)
	$(CXX) $(CXXFLAGS) -fsigned-char $< -o $@

$(BUILD)/byte_order_unsigned: byte_order.cpp lab/terms_io.h | $(BUILD)
	$(CXX) $(CXXFLAGS) -funsigned-char $< -o $@

# Las mediciones van con -O2 y sin sanitizers.
$(BENCHES:%=$(BUILD)/%): $(BUILD)/%: %.cpp $(COMMON_HEADERS) | $(BUILD)
	$(CXX) $(BENCHFLAGS) $< -o $@

# LAB_DIR va primero: así las pruebas toman el código de esa carpeta.
LAB_INCLUDES = -I$(LAB_DIR) -Ilab -I.

$(BUILD)/$(LAB_DIR)/lab_tests: lab/tests/lab_tests.cpp lab/tests/tracked.h $(LAB_HEADERS) | $(BUILD)/$(LAB_DIR)
	$(CXX) $(CXXFLAGS) $(LAB_INCLUDES) $< -o $@

# Las mismas pruebas con char con signo, como en x86-64: una comparación char por char
# que funciona en ARM falla aquí, y al revés.
$(BUILD)/$(LAB_DIR)/lab_tests_signed: lab/tests/lab_tests.cpp lab/tests/tracked.h $(LAB_HEADERS) | $(BUILD)/$(LAB_DIR)
	$(CXX) $(CXXFLAGS) -fsigned-char $(LAB_INCLUDES) $< -o $@

$(BUILD)/$(LAB_DIR)/autocomplete: lab/tests/autocomplete_main.cpp $(LAB_HEADERS) | $(BUILD)/$(LAB_DIR)
	$(CXX) $(CXXFLAGS) $(LAB_INCLUDES) $< -o $@

$(BUILD)/$(LAB_DIR)/bench_sorts: lab/tests/bench_sorts.cpp $(LAB_HEADERS) bench.h | $(BUILD)/$(LAB_DIR)
	$(CXX) $(BENCHFLAGS) $(LAB_INCLUDES) $< -o $@

$(BUILD)/$(LAB_DIR)/bench_query: lab/tests/bench_query.cpp $(LAB_HEADERS) bench.h | $(BUILD)/$(LAB_DIR)
	$(CXX) $(BENCHFLAGS) $(LAB_INCLUDES) $< -o $@

$(BUILD) $(BUILD)/$(LAB_DIR):
	mkdir -p $@

LAB_BINARIES = lab_tests lab_tests_signed autocomplete bench_sorts bench_query

lab: $(LAB_BINARIES:%=$(BUILD)/$(LAB_DIR)/%)

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

test-sorts: lab
	DATA=$(DATA) LAB_DIR=$(LAB_DIR) python3 -m unittest -v test_lab.TestSorts

test-autocomplete: lab
	DATA=$(DATA) LAB_DIR=$(LAB_DIR) python3 -m unittest -v test_lab.TestAutocomplete test_lab.TestSignedChar

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

bench-sorts: $(BUILD)/$(LAB_DIR)/bench_sorts
	$<

bench-query: $(BUILD)/$(LAB_DIR)/bench_query
	$< $(DATA)/terminos.tsv

clean:
	rm -rf $(BUILD) __pycache__
