CC ?= clang
STD = c17
AR = ar
TARGET = rayforce
VERSION_MAJOR := $(shell grep 'RAY_VERSION_MAJOR' include/rayforce.h | head -1 | awk '{print $$3}')
VERSION_MINOR := $(shell grep 'RAY_VERSION_MINOR' include/rayforce.h | head -1 | awk '{print $$3}')
VERSION_PATCH := $(shell grep 'RAY_VERSION_PATCH' include/rayforce.h | head -1 | awk '{print $$3}')
VERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH)
GIT_HASH := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
BUILD_DATE := $(shell date -u +%Y-%m-%d)
WARNS = -Wall -Wextra -Werror -Wstrict-prototypes -Wno-unused-parameter
DEFS = -DRAYFORCE_GIT_COMMIT=\"$(GIT_HASH)\" -DRAYFORCE_BUILD_DATE=\"$(BUILD_DATE)\"
INCLUDES = -Iinclude -Isrc
UNAME_S := $(shell uname -s)
DEBUG_CFLAGS = -fPIC $(WARNS) -std=$(STD) -g -O0 -march=native -DDEBUG \
-fsanitize=address,undefined -fno-omit-frame-pointer
RELEASE_CFLAGS = -fPIC $(WARNS) -std=$(STD) -O3 -march=native \
-funroll-loops -fomit-frame-pointer -fno-math-errno
COVERAGE_CFLAGS = -fPIC $(WARNS) -std=$(STD) -g -O0 -march=native -DDEBUG \
-fno-omit-frame-pointer -fprofile-instr-generate -fcoverage-mapping
COVERAGE_LDFLAGS = -fprofile-instr-generate -fcoverage-mapping
ifeq ($(UNAME_S),Linux)
LIBS = -lm -lpthread
RELEASE_LDFLAGS = -Wl,--gc-sections -Wl,--as-needed
else
LIBS = -lm
RELEASE_LDFLAGS = -Wl,-dead_strip
endif
DEBUG_LDFLAGS = -fsanitize=address,undefined
CFLAGS = $(DEBUG_CFLAGS)
LDFLAGS = $(DEBUG_LDFLAGS)
LIB_SRC = $(wildcard src/*/*.c)
LIB_SRC := $(filter-out src/app/main.c, $(LIB_SRC))
LIB_OBJ = $(LIB_SRC:.c=.o)
MAIN_SRC = src/app/main.c
MAIN_OBJ = $(MAIN_SRC:.c=.o)
TEST_SRC = $(wildcard test/*.c)
TEST_OBJ = $(TEST_SRC:.c=.o)
default: debug
%.o: %.c
$(CC) -c $(CFLAGS) $(DEFS) $(INCLUDES) -o $@ $<
$(TARGET): $(LIB_OBJ) $(MAIN_OBJ)
$(CC) $(CFLAGS) -o $(TARGET) $(LIB_OBJ) $(MAIN_OBJ) $(LIBS) $(LDFLAGS)
debug: CFLAGS = $(DEBUG_CFLAGS)
debug: LDFLAGS = $(DEBUG_LDFLAGS)
debug: $(TARGET)
release: CFLAGS = $(RELEASE_CFLAGS)
release: LDFLAGS = $(RELEASE_LDFLAGS)
release: $(TARGET)
lib: CFLAGS = $(RELEASE_CFLAGS)
lib: $(LIB_OBJ)
$(AR) rc lib$(TARGET).a $(LIB_OBJ)
test: CFLAGS = $(DEBUG_CFLAGS)
test: LDFLAGS = $(DEBUG_LDFLAGS)
test: $(TARGET) $(LIB_OBJ) $(TEST_OBJ)
$(CC) $(CFLAGS) -o $(TARGET).test $(LIB_OBJ) $(TEST_OBJ) $(LIBS) $(LDFLAGS) -Itest
./$(TARGET).test
coverage:
@command -v clang >/dev/null || { echo "coverage: clang not found"; exit 1; }
@command -v llvm-profdata >/dev/null || { echo "coverage: llvm-profdata not found"; exit 1; }
@command -v llvm-cov >/dev/null || { echo "coverage: llvm-cov not found"; exit 1; }
$(MAKE) clean
rm -f cov-*.profraw default.profraw coverage.profdata
rm -rf coverage_html
LLVM_PROFILE_FILE='cov-%p.profraw' $(MAKE) test \
CC=clang \
DEBUG_CFLAGS='$(COVERAGE_CFLAGS)' \
DEBUG_LDFLAGS='$(COVERAGE_LDFLAGS)'
llvm-profdata merge -sparse cov-*.profraw -o coverage.profdata
llvm-cov show ./$(TARGET).test \
-instr-profile=coverage.profdata \
-format=html -output-dir=coverage_html \
-show-line-counts-or-regions \
-ignore-filename-regex='test/.*|/usr/.*'
@echo
@echo "=== coverage summary ==="
@llvm-cov report ./$(TARGET).test \
-instr-profile=coverage.profdata \
-ignore-filename-regex='test/.*|/usr/.*' 2>/dev/null | tail -3
@echo
@echo "→ coverage_html/index.html"
clean:
-rm -f $(LIB_OBJ) $(MAIN_OBJ) $(TEST_OBJ)
-rm -f $(TARGET) $(TARGET).test lib$(TARGET).a
-rm -rf build build_release
-rm -f rf_test_*.csv
-rm -f cov-*.profraw default.profraw coverage.profdata
-rm -rf coverage_html
.PHONY: default debug release lib test coverage clean