144 lines
5.4 KiB
Makefile
144 lines
5.4 KiB
Makefile
# ==============================================================================
|
|
# 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
|