# retoor CC = gcc CFLAGS = -Wall -Wextra -Werror -pedantic -std=c11 -O3 -march=native -flto CFLAGS_DEBUG = -Wall -Wextra -pedantic -std=c11 -g -O0 -DDEBUG CFLAGS_COV = -Wall -Wextra -pedantic -std=c11 -g -O0 --coverage -fprofile-arcs -ftest-coverage CFLAGS_PROF = -Wall -Wextra -pedantic -std=c11 -O2 -pg INCLUDES = -Iinclude LDFLAGS = -flto LDFLAGS_COV = --coverage SRC_DIR = src INC_DIR = include BUILD_DIR = build TEST_DIR = tests COV_DIR = coverage SRCS = $(SRC_DIR)/lexer.c $(SRC_DIR)/ast.c $(SRC_DIR)/parser.c \ $(SRC_DIR)/nfa.c $(SRC_DIR)/matcher.c $(SRC_DIR)/lorex.c \ $(SRC_DIR)/repl.c $(SRC_DIR)/main.c LIB_SRCS = $(SRC_DIR)/lexer.c $(SRC_DIR)/ast.c $(SRC_DIR)/parser.c \ $(SRC_DIR)/nfa.c $(SRC_DIR)/matcher.c $(SRC_DIR)/lorex.c OBJS = $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(SRCS)) LIB_OBJS = $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(LIB_SRCS)) TARGET = lorex LIB_TARGET = liblorex.a TEST_SRCS = $(TEST_DIR)/test_lexer.c $(TEST_DIR)/test_parser.c \ $(TEST_DIR)/test_nfa.c $(TEST_DIR)/test_matcher.c \ $(TEST_DIR)/test_all.c $(TEST_DIR)/test_integration.c TEST_BINS = $(BUILD_DIR)/test_lexer $(BUILD_DIR)/test_parser \ $(BUILD_DIR)/test_nfa $(BUILD_DIR)/test_matcher \ $(BUILD_DIR)/test_all $(BUILD_DIR)/test_integration .PHONY: all clean test debug coverage lcov profile valgrind help install all: $(BUILD_DIR) $(TARGET) $(BUILD_DIR): mkdir -p $(BUILD_DIR) $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR) $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ $(TARGET): $(OBJS) $(CC) $(OBJS) -o $@ $(LDFLAGS) $(LIB_TARGET): $(LIB_OBJS) ar rcs $@ $(LIB_OBJS) debug: CFLAGS = $(CFLAGS_DEBUG) debug: clean $(TARGET) $(BUILD_DIR)/test_lexer: $(TEST_DIR)/test_lexer.c $(LIB_SRCS) | $(BUILD_DIR) $(CC) $(CFLAGS_DEBUG) $(INCLUDES) $< $(LIB_SRCS) -o $@ $(BUILD_DIR)/test_parser: $(TEST_DIR)/test_parser.c $(LIB_SRCS) | $(BUILD_DIR) $(CC) $(CFLAGS_DEBUG) $(INCLUDES) $< $(LIB_SRCS) -o $@ $(BUILD_DIR)/test_nfa: $(TEST_DIR)/test_nfa.c $(LIB_SRCS) | $(BUILD_DIR) $(CC) $(CFLAGS_DEBUG) $(INCLUDES) $< $(LIB_SRCS) -o $@ $(BUILD_DIR)/test_matcher: $(TEST_DIR)/test_matcher.c $(LIB_SRCS) | $(BUILD_DIR) $(CC) $(CFLAGS_DEBUG) $(INCLUDES) $< $(LIB_SRCS) -o $@ $(BUILD_DIR)/test_all: $(TEST_DIR)/test_all.c $(LIB_SRCS) | $(BUILD_DIR) $(CC) $(CFLAGS_DEBUG) $(INCLUDES) $< $(LIB_SRCS) -o $@ $(BUILD_DIR)/test_integration: $(TEST_DIR)/test_integration.c $(LIB_SRCS) | $(BUILD_DIR) $(CC) $(CFLAGS_DEBUG) $(INCLUDES) $< $(LIB_SRCS) -o $@ $(BUILD_DIR)/benchmark: $(TEST_DIR)/benchmark.c $(LIB_SRCS) | $(BUILD_DIR) $(CC) -O3 -march=native $(INCLUDES) $< $(LIB_SRCS) -o $@ test: $(TEST_BINS) @echo "running lexer tests..." @$(BUILD_DIR)/test_lexer @echo "" @echo "running parser tests..." @$(BUILD_DIR)/test_parser @echo "" @echo "running nfa tests..." @$(BUILD_DIR)/test_nfa @echo "" @echo "running matcher tests..." @$(BUILD_DIR)/test_matcher @echo "" @echo "running comprehensive tests..." @$(BUILD_DIR)/test_all @echo "" @echo "running integration tests..." @$(BUILD_DIR)/test_integration coverage: CFLAGS = $(CFLAGS_COV) coverage: LDFLAGS = $(LDFLAGS_COV) coverage: clean $(BUILD_DIR) $(CC) $(CFLAGS_COV) $(INCLUDES) $(TEST_DIR)/test_all.c $(LIB_SRCS) -o $(BUILD_DIR)/test_coverage $(LDFLAGS_COV) $(BUILD_DIR)/test_coverage gcov -b $(LIB_SRCS) @echo "" @echo "coverage report generated" @mkdir -p $(BUILD_DIR)/coverage @mv *.gcov $(BUILD_DIR)/coverage/ 2>/dev/null || true @mv *.gcda $(BUILD_DIR)/coverage/ 2>/dev/null || true @mv *.gcno $(BUILD_DIR)/coverage/ 2>/dev/null || true lcov: clean $(BUILD_DIR) @mkdir -p $(COV_DIR) $(CC) $(CFLAGS_COV) $(INCLUDES) $(TEST_DIR)/test_integration.c $(LIB_SRCS) -o $(BUILD_DIR)/test_lcov $(LDFLAGS_COV) lcov --zerocounters --directory . $(BUILD_DIR)/test_lcov lcov --capture --directory . --output-file $(COV_DIR)/coverage.info lcov --remove $(COV_DIR)/coverage.info '*/tests/*' --ignore-errors unused --output-file $(COV_DIR)/coverage.info genhtml $(COV_DIR)/coverage.info --output-directory $(COV_DIR)/html @echo "" @echo "lcov html report: $(COV_DIR)/html/index.html" profile: CFLAGS = $(CFLAGS_PROF) profile: clean $(BUILD_DIR) $(CC) $(CFLAGS_PROF) $(INCLUDES) $(TEST_DIR)/test_all.c $(LIB_SRCS) -o $(BUILD_DIR)/test_profile $(BUILD_DIR)/test_profile gprof $(BUILD_DIR)/test_profile gmon.out > $(BUILD_DIR)/profile.txt @echo "" @echo "profile report: $(BUILD_DIR)/profile.txt" @mv gmon.out $(BUILD_DIR)/ 2>/dev/null || true valgrind: $(BUILD_DIR)/test_all valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes \ --error-exitcode=1 $(BUILD_DIR)/test_all valgrind-verbose: $(BUILD_DIR)/test_all valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes \ --verbose --log-file=$(BUILD_DIR)/valgrind.log $(BUILD_DIR)/test_all @echo "valgrind log: $(BUILD_DIR)/valgrind.log" benchmark: $(BUILD_DIR)/benchmark @./$(BUILD_DIR)/benchmark benchmark-quick: $(TARGET) @echo "quick benchmark..." @echo "pattern: [a-z]+@[a-z]+\\.[a-z]+" @time -p sh -c 'for i in $$(seq 1 1000); do ./$(TARGET) "[a-z]+@[a-z]+\\.[a-z]+" "test@example.com" > /dev/null; done' @echo "" @echo "pattern: (a|b)*abb" @time -p sh -c 'for i in $$(seq 1 1000); do ./$(TARGET) "(a|b)*abb" "aabababb" > /dev/null; done' install: $(TARGET) install -d $(DESTDIR)/usr/local/bin install -m 755 $(TARGET) $(DESTDIR)/usr/local/bin/ uninstall: rm -f $(DESTDIR)/usr/local/bin/$(TARGET) clean: rm -rf $(BUILD_DIR) $(TARGET) $(LIB_TARGET) $(COV_DIR) rm -f *.gcov *.gcda *.gcno gmon.out help: @echo "lorex makefile targets:" @echo " all build optimized release binary" @echo " debug build with debug symbols" @echo " test run all tests" @echo " coverage run tests with gcov coverage analysis" @echo " lcov generate html coverage report with lcov" @echo " profile run tests with profiling" @echo " valgrind run tests under valgrind" @echo " benchmark run performance benchmarks" @echo " install install to /usr/local/bin" @echo " uninstall remove from /usr/local/bin" @echo " clean remove build artifacts" @echo " help show this message"