# ============================================================================== # Toolchain & Executables # ============================================================================== LLVM_DIR ?= /opt/homebrew/opt/llvm/bin CC := $(LLVM_DIR)/clang LLVM_PROFDATA := $(LLVM_DIR)/llvm-profdata LLVM_COV := $(LLVM_DIR)/llvm-cov CPPCHECK := cppcheck # libstr is populated by CMake's FetchContent (run `cmake -B build` once) LIBSTR_DIR := build/_deps/libstr-src # ============================================================================== # Flags & Directories # ============================================================================== CFLAGS := -std=c23 -Wall -Wextra -Wpedantic -Wshadow \ -Wconversion -Wsign-conversion \ -g -O1 -fno-omit-frame-pointer SAN_FLAGS := -fsanitize=address,undefined INCLUDES := -Iinclude -Isrc/lib -Isrc/lib/int -Isrc/lib/utils ASAN_ENV := ASAN_OPTIONS="allocator_may_return_null=1:detect_stack_use_after_return=1" \ UBSAN_OPTIONS="halt_on_error=1:print_stacktrace=1" CPPCHECK_FLAGS := --enable=all \ --inconclusive \ --error-exitcode=1 \ --check-level=exhaustive \ --suppress=missingIncludeSystem \ --suppress=unmatchedSuppression \ --suppress=unusedFunction \ --suppress=staticFunction \ --inline-suppr \ $(INCLUDES) # Sources & Build Directories SRCS := src/lib/int/int.c src/lib/utils/utils.c TEST_SRC := tests/test_learn.c FUZZ_SRC := tests/fuzz_char.c STRING_SRCS := src/string.c src/utils.c $(LIBSTR_DIR)/src/string.c TEST_STRING_SRC := tests/test_string.c BIN_DIR := tests/bin CACHE_DIR := tests/cache TEST_BIN := $(BIN_DIR)/test_learn_runner TSAN_BIN := $(BIN_DIR)/test_tsan_runner FUZZ_BIN := $(BIN_DIR)/fuzz_char_runner COV_BIN := $(BIN_DIR)/test_cov_runner TEST_STRING_BIN := $(BIN_DIR)/test_string_runner # ============================================================================== # Targets & Workflow Rules # ============================================================================== .PHONY: all test test-string sanitize check check-sources analyze cppcheck fuzz cov-build cov clean all: test $(BIN_DIR) $(CACHE_DIR): @mkdir -p $@ # --- Compilation Targets --- $(TEST_BIN): $(SRCS) $(TEST_SRC) | $(BIN_DIR) $(CC) $(CFLAGS) $(SAN_FLAGS) $(INCLUDES) $^ -o $@ $(TEST_STRING_BIN): $(STRING_SRCS) $(TEST_STRING_SRC) | $(BIN_DIR) $(CC) $(CFLAGS) $(SAN_FLAGS) $(INCLUDES) -I$(LIBSTR_DIR)/include $^ -o $@ $(TSAN_BIN): $(SRCS) $(TEST_SRC) | $(BIN_DIR) $(CC) $(CFLAGS) -fsanitize=thread $(INCLUDES) $^ -o $@ $(FUZZ_BIN): $(SRCS) $(FUZZ_SRC) | $(BIN_DIR) $(CC) $(CFLAGS) -fsanitize=fuzzer,address,undefined $(INCLUDES) $^ -o $@ # --- Testing & Sanitizer Suites --- test: $(TEST_BIN) @echo "=== Running Unit Tests (ASan + UBSan) ===" @$(ASAN_ENV) ./$(TEST_BIN) test-string: $(TEST_STRING_BIN) @echo "=== Running vec_string Unit Tests (ASan + UBSan) ===" @$(ASAN_ENV) ./$(TEST_STRING_BIN) sanitize: $(TEST_BIN) $(TSAN_BIN) @echo "\n=== [1/2] Running Address + UndefinedBehavior Sanitizers ===" @$(ASAN_ENV) ./$(TEST_BIN) @echo "\n=== [2/2] Running ThreadSanitizer ===" @./$(TSAN_BIN) @echo "\n>>> Sanitizers passed with zero defects." # Unified master check: runtime sanitizers, static analyzer, and cppcheck check: sanitize analyze cppcheck @echo "\n==============================================" @echo " ALL TESTS, SANITIZERS & STATIC CHECKS PASSED " @echo "==============================================" fuzz: $(FUZZ_BIN) @echo "=== Starting Fuzzer (Press Ctrl+C to stop) ===" @$(ASAN_ENV) ./$(FUZZ_BIN) -max_total_time=60 # --- Coverage Profiling --- cov-build: $(SRCS) $(TEST_SRC) | $(BIN_DIR) $(CC) $(CFLAGS) $(SAN_FLAGS) -fprofile-instr-generate -fcoverage-mapping $(INCLUDES) $^ -o $(COV_BIN) cov: cov-build | $(CACHE_DIR) @echo "=== Recording Coverage Profile Data ===" @$(ASAN_ENV) LLVM_PROFILE_FILE="$(CACHE_DIR)/test_char.profdata_raw" ./$(COV_BIN) @$(LLVM_PROFDATA) merge -sparse $(CACHE_DIR)/test_char.profdata_raw -o $(CACHE_DIR)/test_char.profdata @echo "\n=== Line & Branch Coverage Report: src/lib/char/char.c ===" @$(LLVM_COV) report $(COV_BIN) -instr-profile=$(CACHE_DIR)/test_char.profdata src/lib/char/char.c @$(LLVM_COV) show $(COV_BIN) -instr-profile=$(CACHE_DIR)/test_char.profdata src/lib/char/char.c --format=html > coverage.html @echo "\nDetailed HTML report written to coverage.html." # --- Static Analysis & Object Checking --- check-sources: | $(BIN_DIR) @echo "=== Compiling Sources to Object Files (ASan + UBSan) ===" $(CC) $(CFLAGS) $(SAN_FLAGS) $(INCLUDES) -c src/lib/char/char.c -o $(BIN_DIR)/char.o $(CC) $(CFLAGS) $(SAN_FLAGS) $(INCLUDES) -c src/lib/utils/utils.c -o $(BIN_DIR)/utils.o @echo "Library sources compiled cleanly." analyze: @echo "=== Running Clang Static Analyzer ===" @$(CC) $(CFLAGS) $(INCLUDES) \ --analyze \ -Xanalyzer -analyzer-output=text \ -Xanalyzer -analyzer-checker=core,unix,deadcode,security \ $(SRCS) @echo "Clang Static Analyzer complete: zero defects." cppcheck: @echo "=== Running Cppcheck Static Analysis ===" @$(CPPCHECK) $(CPPCHECK_FLAGS) include/ src/ @echo "Cppcheck passed with zero defects." # --- Housekeeping --- clean: rm -rf $(BIN_DIR)/* $(CACHE_DIR)/* coverage.html