############################################################################################## # # # /$$$$$$ /$$ /$$ /$$ # # /$$__ $$ | $$$ /$$$ | $$ # # | $$ \__/ /$$$$$$ /$$$$$$$$ /$$ /$$ | $$$$ /$$$$ /$$$$$$ | $$ /$$ /$$$$$$ # # | $$ /$$__ $$|____ /$$/| $$ | $$ | $$ $$/$$ $$ |____ $$| $$ /$$/ /$$__ $$ # # | $$ | $$ \ $$ /$$$$/ | $$ | $$ | $$ $$$| $$ /$$$$$$$| $$$$$$/ | $$$$$$$$ # # | $$ $$| $$ | $$ /$$__/ | $$ | $$ | $$\ $ | $$ /$$__ $$| $$_ $$ | $$_____/ # # | $$$$$$/| $$$$$$/ /$$$$$$$$| $$$$$$$ | $$ \/ | $$| $$$$$$$| $$ \ $$| $$$$$$$ # # \______/ \______/ |________/ \____ $$ |__/ |__/ \_______/|__/ \__/ \_______/ # # /$$ | $$ # # ))) | $$$$$$/ Version 2.0.1 # # ((( \______/ # # +-----+ __..--''``---....___ _..._ __ # # | |] / // // // /// //_.-' .-/"; ` ``<._ ``.''_ `. / // / # # `-----' // // /// /// ///_.-' _..--.'_ \ `( ) ) // // # # / / // / /// / /// / (_..-' // (< _ ;_..__ ; `' / /// # # /// // / / // /// / / // // // `-._,_)' // / ``--...____..-' /// / // # # / // / /// // /// / / // // // /// // / /// // // /// / / /// / / /// // # ############################################################################################## MAKEFLAGS += --no-print-directory ifndef IN_NIX_DEVELOP BARE_GOALS := clean clean_self fclean help NIX_GOALS := $(filter-out $(BARE_GOALS),$(or $(MAKECMDGOALS),all)) .PHONY: $(or $(MAKECMDGOALS),all) _nix_develop $(filter $(BARE_GOALS),$(MAKECMDGOALS)): @$(MAKE) IN_NIX_DEVELOP=1 $@ ifneq ($(NIX_GOALS),) $(NIX_GOALS): _nix_develop @: _nix_develop: @nix develop --option warn-dirty false --quiet --command $(MAKE) $(NIX_GOALS) endif else MAKEFLAGS += -j$(shell nproc) .PHONY: all bonus debug clean clean_self fclean re sane help version NAME = MAKE_MODE ?= release MAKE_MODE_STAMP = obj/.mode_$(MAKE_MODE) LAST_MODE := $(or $(firstword $(patsubst obj/.mode_%,%,$(wildcard obj/.mode_*))),release) # Colors ESC := $(shell printf '\033') GREEN = $(ESC)[32m BLUE = $(ESC)[34m RED = $(ESC)[31m RESET = $(ESC)[0m # Compiler COMPILER = c++ BASE_FLAGS = \ -Wall -Wextra -std=c++98 \ -Werror=vla -pedantic-errors -fstrict-flex-arrays=3 -Werror=int-conversion -Werror=incompatible-pointer-types -Werror=implicit-function-declaration -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wold-style-cast -Wconversion \ -MMD -MP \ -flto=thin RELEASE_FLAGS = \ -Werror \ -O3 -march=native DEBUG_FLAGS = \ -gfull -O1 -fno-builtin -mno-omit-leaf-frame-pointer -fno-omit-frame-pointer -DDEBUG=true SANE_FLAGS = \ -fsanitize=address,pointer-compare,pointer-subtract,leak,undefined,shift,shift-exponent,shift-base,integer-divide-by-zero,unreachable,vla-bound,null,signed-integer-overflow,bounds,alignment,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,pointer-overflow,builtin -fsanitize-address-use-after-scope # Libraries LIB_DIRS = LIB_FILES = LDFLAGS = -fuse-ld=mold # Directories SRC = src OBJ = obj/$(MAKE_MODE) INCLUDES = -Iinclude -Isrc $(foreach lib,$(LIB_DIRS),-I$(lib)/include) # Sources SRC_FILES := \ main.cpp SRCS := $(addprefix $(SRC)/,$(SRC_FILES)) OBJS := $(patsubst $(SRC)/%.cpp,$(OBJ)/%.o,$(SRCS)) DEPS := $(OBJS:.o=.d) ifeq ($(MAKE_MODE),release) CFLAGS = $(BASE_FLAGS) $(RELEASE_FLAGS) LIB_TARGET = all else ifeq ($(MAKE_MODE),debug) CFLAGS = $(BASE_FLAGS) $(DEBUG_FLAGS) LIB_TARGET = debug else ifeq ($(MAKE_MODE),sane) CFLAGS = $(BASE_FLAGS) $(DEBUG_FLAGS) $(SANE_FLAGS) LIB_TARGET = sane else $(error Unknown mode) endif endif endif all: $(NAME) compile_commands.json compile_commands.json: $(OBJS) @echo "$(BLUE)Generating compile_commands.json$(RESET)" @sed -e '1s/^/[/' -e '$$s/,$$/]/' $(OBJS:.o=.o.json) > $@ bonus: all debug: @$(MAKE) MAKE_MODE=debug sane: @$(MAKE) MAKE_MODE=sane $(OBJ)/%.o: $(SRC)/%.cpp @mkdir -p $(@D) @echo "$(BLUE)Compiling$(RESET) $<..." @$(COMPILER) $(CFLAGS) $(INCLUDES) -MJ $@.json -c $< -o $@ libs: @set -e; \ for lib in $(LIB_DIRS); do \ echo "$(BLUE)Building $$lib in $(MAKE_MODE) mode...$(RESET)"; \ if [ "$(LIB_TARGET)" = "sane" ] && [ "$$lib" != "libft" ]; then \ $(MAKE) -C $$lib debug; \ else \ $(MAKE) -C $$lib $(LIB_TARGET); \ fi; \ done $(MAKE_MODE_STAMP): @echo "$(GREEN)Building in $(MAKE_MODE) mode$(RESET)" @rm -f obj/.mode_* @mkdir -p obj @touch $@ $(NAME): $(MAKE_MODE_STAMP) $(OBJS) | libs @echo "$(GREEN)Linking$(RESET) $@..." @$(COMPILER) $(CFLAGS) $(OBJS) $(LIB_FILES) -o $@ $(LDFLAGS) @echo "$(GREEN)Successfully compiled $(NAME)!$(RESET)" clean_self: @echo "$(RED)Cleaning$(RESET) $(NAME)'s object files..." @rm -rf obj clean: clean_self @for lib in $(LIB_DIRS); do \ $(MAKE) -s -C $$lib clean; \ done fclean: clean_self @echo "$(RED)Removing$(RESET) $(NAME)..." @rm -f $(NAME) @echo "$(RED)Removing$(RESET) compile_commands.json..." @rm -f compile_commands.json @for lib in $(LIB_DIRS); do \ $(MAKE) -s -C $$lib fclean; \ done re: fclean @$(MAKE) MAKE_MODE=$(if $(filter command line,$(origin MAKE_MODE)),$(MAKE_MODE),$(LAST_MODE)) version: @echo "$(RED)Cozy Make version:$(RESET) 2.0.1" @$(COMPILER) --version help: @echo "$(GREEN)Available targets:$(RESET)" @echo " $(BLUE)all $(RESET)- Build in release mode (default)" @echo " $(BLUE)bonus $(RESET)- Build in release mode with bonus" @echo " $(BLUE)debug $(RESET)- Build with debug symbols" @echo " $(BLUE)sane $(RESET)- Build with sanitizers" @echo " $(BLUE)clean $(RESET)- Remove object files" @echo " $(BLUE)fclean $(RESET)- Remove all build artifacts" @echo " $(BLUE)re $(RESET)- Rebuild in the last used mode or release unless specified" @echo " $(BLUE)version $(RESET)- Prints the version of Cozy Make and the compiler" -include $(DEPS) endif