# **************************************************************************** #
#                                                                              #
#                                                         :::      ::::::::    #
#    Makefile                                           :+:      :+:    :+:    #
#                                                     +:+ +:+         +:+      #
#    By: acossari <acossari@student.codam.nl>       +#+  +:+       +#+         #
#                                                 +#+#+#+#+#+   +#+            #
#    Created: 2026/08/19 10:05:52 by acossari          #+#    #+#              #
#    Updated: 2026/08/20 22:18:47 by acossari         ###   ########.fr        #
#                                                                              #
# **************************************************************************** #

NAME      := webserv

SRC_DIR   := src
OBJ_DIR   := obj
INC_DIR   := include

CXX       := g++
# EXTRA_CXXFLAGS is the slot for flags added from the command line, for example
# make EXTRA_CXXFLAGS="-g3 -fsanitize=address". CXXFLAGS itself must never be
# overridden that way, it carries the warning flags that have to stay on.
CXXFLAGS  := -Wall -Wextra -Werror -std=c++23 -I$(INC_DIR) $(EXTRA_CXXFLAGS)
# The C++ standard library goes inside the binary instead of being loaded from
# the system at startup. A recent compiler emits references to symbol versions
# that an older system libstdc++.so.6 does not carry, and that failure shows up
# when the program is started, not when it is linked.
LDFLAGS   := -static-libstdc++ -static-libgcc

CLANG        ?= clang++
CLANG_TIDY   ?= clang-tidy
CLANG_FORMAT ?= clang-format

# Separate object directory and binary for the clang build. Sharing obj/ would
# link a fresh g++ object with a leftover clang one, and the error looks like a
# bug in the source instead of an old file.
CLANG_NAME    := $(NAME)-clang
CLANG_OBJ_DIR := $(OBJ_DIR)/clang

# libstdc++ is the GNU library and ships with g++, libc++ is the LLVM one and
# ships with clang. On Linux clang usually sits on libstdc++ anyway, and that
# pairing cannot build this project:
#
#   clang 18 with libstdc++ : std::expected not available
#   clang 18 with libc++    : std::expected available
#
# So every clang pass gets libc++. g++ never sees this flag.
CLANG_STDLIB ?= -stdlib=libc++

# find returns files in filesystem order, which is not the same on every
# machine. sort keeps the compile and link lines stable, so build logs and
# clang-tidy output stay comparable.
#SRCS      := $(sort $(shell find $(SRC_DIR) -type f -name '*.cpp'))

SRCS       := src/Log.cpp src/main.cpp src/Server.cpp \
			 src/config/Config.cpp  src/config/ConfigurationParser.cpp src/config/LocationConfig.cpp src/config/ServerConfig.cpp \
			 src/event/Epoll.cpp src/event/EventToken.cpp  \
			 src/net/ByteBuffer.cpp src/net/Connection.cpp src/net/FileDescriptor.cpp src/net/Listener.cpp src/net/ListenerPlan.cpp src/net/PauseMask.cpp src/net/SlotPool.cpp \
			 src/http/Request.cpp src/http/RequestParser.cpp src/http/Response.cpp


 OBJS      := $(SRCS:$(SRC_DIR)/%.cpp=$(OBJ_DIR)/%.o)
# Make only knows that obj/main.o comes from src/main.cpp, so editing Log.hpp
# would leave the old main.o in place. Each .d adds the missing line, obj/main.o
# also depends on include/Log.hpp, and -include at the bottom pulls them in.
DEPS      := $(OBJS:.o=.d)
HDRS	  := include/config/Config.hpp  include/config/ConfigurationParser.hpp include/config/LocationConfig.hpp include/config/ServerConfig.hpp \
			 include/event/Epoll.hpp include/event/EventToken.hpp  \
			 include/http/HttpStatus.hpp include/http/Request.hpp include/http/RequestParser.hpp include/http/Response.hpp   \
			 include/net/ByteBuffer.hpp include/net/Connection.hpp include/net/FileDescriptor.hpp include/net/Listener.hpp include/net/ListenerPlan.hpp include/net/PauseMask.hpp include/net/SlotPool.hpp   \
			 include/Log.hpp include/Result.hpp include/Server.hpp \


#HDRS      := $(sort $(shell find $(INC_DIR) $(SRC_DIR) -type f \
#               \( -name '*.hpp' -o -name '*.tpp' \)))

all: $(NAME)

$(NAME): $(OBJS)
	$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $(NAME)

# -MMD writes the .d file described above. -MP adds an empty rule for every
# header in it, which matters after a rename: the old .d still asks for the old
# path and make stops, having no way to build that file. The empty rule says the
# header needs no recipe, so make moves on and recompiles.
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
	@mkdir -p $(dir $@)
	$(CXX) $(CXXFLAGS) -MMD -MP -c $< -o $@

# Reports only, never fails the build: WarningsAsErrors is empty in .clang-tidy
# and all does not depend on this. clang-tidy parses the code itself, so it
# needs the same flags the compiler gets (everything after the --).
tidy: $(SRCS)
	$(CLANG_TIDY) $(SRCS) -- $(CXXFLAGS) $(CLANG_STDLIB)

# Same sources through the other compiler and standard library, into files of
# its own, so the normal build is untouched. Worth running because the two
# compilers do not warn about the same things. Needs libc++ 18 or newer, the
# first release that ships <print>.
check-clang:
	$(MAKE) --no-print-directory NAME=$(CLANG_NAME) OBJ_DIR=$(CLANG_OBJ_DIR) \
	        CXX=$(CLANG) EXTRA_CXXFLAGS="$(CLANG_STDLIB)"

format:
	$(CLANG_FORMAT) -i $(SRCS) $(HDRS)

format-check:
	$(CLANG_FORMAT) --dry-run --Werror $(SRCS) $(HDRS)

clean:
	rm -rf $(OBJ_DIR)

fclean: clean
	rm -f $(NAME) $(CLANG_NAME)

re: fclean all

-include $(DEPS)

.PHONY: all clean fclean re tidy check-clang format format-check
