CC = LC_ALL=C g++
CFLAGS += -std=c++17 -pipe -Wall -Wextra -Werror
CFLAGS += -Wconversion -Wsign-conversion -Wformat-security -Winline -Wno-unused-parameter -Wno-pointer-arith
CFLAGS += -march=native
CFLAGS += -include config.hpp
CFLAGS += -Ofast -flto -fwhole-program -ffast-math -fsingle-precision-constant -ffp-contract=fast
LFLAGS += -Ofast -flto -fwhole-program -ffast-math -fsingle-precision-constant -ffp-contract=fast
LFLAGS += -pthread -lX11 -lXext
LFLAGS += -pipe
NAME = maze-tracer
SOURCES = $(wildcard *.cpp)
HEADERS = $(wildcard *.hpp)
OBJECTS = $(SOURCES:.cpp=.o)
# default targets, build in 'release mode'
.PHONY: build
build: CFLAGS += -DNDEBUG -fno-stack-protector
build: LFLAGS += -no-pie -Wl,-z,relro,-z,now
build: $(NAME)
$(NAME): $(OBJECTS)
$(CC) -o $(@) $(^) $(LFLAGS)
@#which checksec >/dev/null 2>&1 && checksec --format=cli --file=$(@) || true
@which toilet >/dev/null 2>&1 && toilet --font smblock --filter gay "# $(@) #" || true
%.o: %.cpp $(HEADERS) Makefile
$(CC) $(CFLAGS) -o $(@) -c $(<)
# debug run targets
.PHONY: run
run: $(NAME)
./$(NAME)
.PHONY: run-vg
run-vg: CFLAGS += -Og -g
run-vg: LFLAGS += -Og
run-vg: $(NAME)
valgrind --leak-check=full --show-reachable=yes --track-origins=yes --error-exitcode=42 ./$(NAME)
.PHONY: run-gdb
run-gdb: CFLAGS += -Og -g
run-gdb: LFLAGS += -Og
run-gdb: $(NAME)
gdb -ex run --args ./$(NAME)
# benchmarking
.PHONY: benchmark
benchmark: CFLAGS += -DNDEBUG -DUSE_X=0 -DUSE_LOG_STATS=0
benchmark: $(NAME)
./$(NAME) -b -s 666
.PHONY: callgrind
callgrind: CFLAGS += -DNDEBUG -DUSE_X=0 -DUSE_LOG_STATS=0 -Og -g
callgrind: LFLAGS += -Og
callgrind: callgrind.txt callgrind.png
callgrind.out: $(NAME)
valgrind --tool=callgrind --callgrind-out-file=callgrind.out ./$(<) -b -s 666
callgrind.txt: callgrind.out
callgrind_annotate --inclusive=yes --show-percs=yes --tree=both $(<) > $(@)
callgrind.png: callgrind.out
gprof2dot --format=callgrind --node-label=total-time-percentage --strip -n 0.1 -e 0.0 ${<} | dot -Tpng -o ${@}
# gcc profiling and profiled build for even more optimized release build
.PHONY: profile
profile: CFLAGS += -DNDEBUG -DUSE_X=0
profile: CFLAGS += -fprofile-generate -fprofile-arcs -ftest-coverage
profile: LFLAGS += -fprofile-generate -fprofile-arcs
profile: main.gcda main.cpp.gcov profile/index.html
main.gcda: clean.o $(NAME)
@rm -f -- *.gcda
./$(NAME) -b -s 666
main.cpp.gcov: main.gcda
gcov --branch-probabilities --function-summaries --use-colors --use-hotness-colors --demangled-names --relative-only *.gcda >/dev/null
main.info: main.gcda
lcov --capture --no-external --rc lcov_branch_coverage=1 --directory . --output-file $(@)
profile/index.html: main.info
genhtml --legend --branch-coverage --function-coverage --missed --demangle-cpp --output-directory $(dir $(@)) $(<)
.PHONY: profiled
profiled: CFLAGS += -Wno-coverage-mismatch -fprofile-use -fprofile-correction
profiled: LFLAGS += -fprofile-use -fprofile-correction
profiled: CFLAGS += -DNDEBUG -fno-stack-protector
profiled: LFLAGS += -no-pie -Wl,-z,relro,-z,now
profiled: clean.o $(NAME)
@# XXX: -fprofile-partial-training - unrecognized command line option
# doxygen
.PHONY: docs
docs: docs/index.html
doxygen-awesome.css:
@# https://github.com/jothepro/doxygen-awesome-css
wget -nv -O $(@) https://raw.githubusercontent.com/jothepro/doxygen-awesome-css/main/doxygen-awesome.css
docs/index.html: $(SOURCES) $(HEADERS) Doxyfile doxygen-awesome.css
@mkdir -p $(dir $(@))
echo "@INCLUDE = Doxyfile\nPROJECT_NAME = $(NAME)\nINPUT = ./\nOUTPUT_DIRECTORY = $(dir $(@))\nHTML_EXTRA_STYLESHEET = doxygen-awesome.css" | doxygen -
# linting
.PHONY: check lint clean.o clean
check: $(SOURCES) $(HEADERS)
clang-tidy --warnings-as-errors='*' $(^) -- $(CFLAGS)
lint: $(SOURCES) $(HEADERS)
clang-format --dry-run -Werror -style=file -- $(^)
# clean
.PHONY: clean.o clean
clean.o:
@rm -f -- $(NAME) $(wildcard *.o)
clean: clean.o
@rm -f -- $(wildcard *.gcda) $(wildcard *.gcno) $(wildcard *.gcov) $(wildcard *.info) $(wildcard callgrind.*)
@rm -rf -- ./profile/ ./docs/ *.css