CC      = gcc
CFLAGS  = -Wall -Wextra -std=c99
TARGET  = factorielle
SRC     = factorielle.c

.PHONY: all run clean asm asm2exe perf hex hex-code disasm debug

all: $(TARGET)

$(TARGET): $(SRC)
	$(CC) $(CFLAGS) -o $@ $<

run: $(TARGET)
	./$(TARGET)

# assembleur standard (-O0 implicite)
$(TARGET).s: $(SRC)
	$(CC) $(CFLAGS) -S -o $@ $<

asm: $(TARGET).s

# compiler l'assembleur en exécutable
asm2exe: $(TARGET).s
	$(CC) $(CFLAGS) -o $(TARGET)-asm $<
	./$(TARGET)-asm

# comparer les optimisations
OPT_LEVELS = O0 O1 O2 O3 Os
PERF_DIR   = perf

perf: $(TARGET)
	mkdir -p $(PERF_DIR)
	@echo "=== Comparaison des optimisations ==="
	@for opt in $(OPT_LEVELS); do \
	    echo; \
	    echo "--- -$$opt ---"; \
	    $(CC) $(CFLAGS) -$$opt -S -o $(PERF_DIR)/$(TARGET)-$$opt.s $(SRC); \
	    $(CC) $(CFLAGS) -$$opt -o $(PERF_DIR)/$(TARGET)-$$opt $(SRC); \
	    echo "  taille: $$(wc -c < $(PERF_DIR)/$(TARGET)-$$opt) octets"; \
	    echo -n "  temps: "; \
	    command time -p ./$(PERF_DIR)/$(TARGET)-$$opt > /dev/null 2>&1; \
	    echo -n "  lignes asm: "; \
	    wc -l < $(PERF_DIR)/$(TARGET)-$$opt.s; \
	done
	@echo; echo "Voir les assembleurs dans $(PERF_DIR)/"

# affichage du binaire en hexadécimal
hex: $(TARGET)
	xxd $(TARGET) | head -80

# juste la section .text (le code) en hexadécimal
hex-code: $(TARGET)
	objdump -s -j .text $(TARGET)

# désassembleur
disasm: $(TARGET)
	objdump -d -M intel $(TARGET) | head -120

# débogage pas à pas avec gdb
DEBUG_TARGET = $(TARGET)-dbg
DEBUG_FLAGS  = -g -O0

$(DEBUG_TARGET): $(SRC)
	$(CC) $(CFLAGS) $(DEBUG_FLAGS) -o $@ $<

debug: $(DEBUG_TARGET)
	@echo "=== Lancement de gdb ==="
	@echo "Commandes utiles: run, break factorielle, next, step, print n, print res, quit"
	gdb -ex "set pagination off" \
	    -ex "break factorielle" \
	    -ex "run" \
	    -ex "info breakpoints" \
	    ./$(DEBUG_TARGET)

# ======== Calculette s-expression (cours 3) ========

CALC_TARGET = calc
CALC_SRC    = calc.c

.PHONY: calc-run

$(CALC_TARGET): $(CALC_SRC)
	$(CC) $(CFLAGS) -o $@ $<

calc-run: $(CALC_TARGET)
	@echo "Exemples : (+ 2 (* 3 4)), (* (+ 2 3) 4), (- 10 (/ 8 2))"
	echo '(+ 2 (* 3 4))' | ./$(CALC_TARGET)

calc-vm: $(CALC_TARGET)
	@echo "=== Compilation VM de (+ 2 (* 3 4)) ==="
	./$(CALC_TARGET) -vm '(+ 2 (* 3 4))'

calc-file: $(CALC_TARGET)
	@echo "=== Écriture du bytecode dans calc_vm_out.c ==="
	./$(CALC_TARGET) -vm '(* (- 100 5) 2)' -o calc_vm_out.c
	cat calc_vm_out.c

# ======== Machine Virtuelle (cours 2) ========

VM_TARGET = vm
VM_SRC    = vm.c

.PHONY: vm-run vm-asm vm-pas

$(VM_TARGET): $(VM_SRC)
	$(CC) $(CFLAGS) -o $@ $<

vm-run: $(VM_TARGET)
	./$(VM_TARGET)

vm-asm: $(VM_TARGET)
	./$(VM_TARGET) | head -30

vm-pas: $(VM_TARGET)
	@echo "Appuyez sur Entree a chaque instruction"
	./$(VM_TARGET) --pas-a-pas

# ======== Serveur HTTP (cours 4) ========

SERVER_TARGET = server
SERVER_SRC    = server.c

.PHONY: server-run

$(SERVER_TARGET): $(SERVER_SRC)
	$(CC) $(CFLAGS) -o $@ $<

server-run: $(SERVER_TARGET)
	@echo "Lancement sur http://localhost:8080 — Ctrl+C pour arrêter"
	./$(SERVER_TARGET)

# ======== Nettoyage global ========

clean:
	rm -f $(TARGET) $(TARGET).s $(TARGET)-asm $(VM_TARGET) $(CALC_TARGET) $(SERVER_TARGET)
	rm -f calc_vm_out.c
	rm -rf $(PERF_DIR)
