TARGET := vfetch MAIN_SRC := main.c LIB_SRC := lib/miniaudio.c lib/pl_mpeg.c APP_SRCS := $(wildcard src/*.c) OBJS := $(MAIN_SRC:.c=.o) $(LIB_SRC:.c=.o) $(APP_SRCS:.c=.o) DEPS := $(OBJS:.o=.d) PROJECT_SRCS := $(MAIN_SRC) $(APP_SRCS) $(wildcard src/*.h) PKGS := chafa glib-2.0 INSTALL_PATH := /usr/local/bin CC := $(firstword $(shell command -v clang gcc)) ifeq ($(CC),) $(error No compatible C compiler found.) endif PKG_CONFIG := $(shell command -v pkg-config) ifeq ($(PKG_CONFIG),) $(error 'pkg-config' not found.) endif PKG_CFLAGS := $(shell pkg-config --cflags $(PKGS) | sed 's/-I/-isystem /g') PKG_LDFLAGS := $(shell pkg-config --libs $(PKGS)) DEPFLAGS := -MMD -MP CORE_CFLAGS := \ -D_XOPEN_SOURCE=700 \ -std=c11 \ -isystem $(CURDIR)/lib \ $(PKG_CFLAGS) STRICT_CFLAGS := \ -pedantic-errors \ -Wall \ -Wextra \ -Wpedantic \ -Werror \ -Wformat=2 \ -Wformat-security \ -Wformat-nonliteral \ -Wformat-signedness \ -Wstack-protector \ -Wvla \ -Wodr \ -Wstrict-prototypes \ -Wmissing-prototypes \ -Wmissing-declarations \ -Wmissing-include-dirs \ -Wmissing-field-initializers \ -Wredundant-decls \ -Wpointer-arith \ -Wpointer-sign \ -Wabsolute-value \ -Wconversion \ -Wsign-conversion \ -Wundef \ -Winline \ -Wcast-qual \ -Wfloat-equal \ -Wold-style-definition \ -Woverlength-strings \ -Wwrite-strings \ -Wlogical-not-parentheses \ -Wpacked \ -Winit-self \ -Wstrict-overflow=5 \ -Wunused-macros \ -Wunreachable-code \ -Wdate-time \ -Wbad-function-cast \ -Wnested-externs \ -Wswitch-default \ -Wswitch-enum \ -Wuninitialized \ -Wdouble-promotion \ -Wcast-function-type \ -Wnull-dereference \ -Wdisabled-optimization \ -Wno-padded CLANG_SPECIFIC_STRICT_FLAGS := \ -Wcomma \ -Wshadow \ -Wcast-align \ -Wdocumentation \ -Wstrict-aliasing \ -Wpadded-bitfield \ -Wformat-overflow \ -Wformat-truncation \ -Wimplicit-fallthrough GCC_SPECIFIC_STRICT_FLAGS := \ -Walloc-zero \ -Wsuggest-attribute=const \ -Wsuggest-attribute=format \ -Wshadow=local \ -Wcast-align=strict \ -Wimplicit-fallthrough=5 \ -Wstrict-aliasing=2 \ -Wformat-overflow=2 \ -Wformat-truncation=2 \ -Wjump-misses-init \ -Wlogical-op \ -Wuseless-cast \ -Wduplicated-cond \ -Wduplicated-branches \ -Wswitch-unreachable \ -Wpacked-bitfield-compat \ -Wunsafe-loop-optimizations \ -Wtrampolines ALL_STRICT_FLAGS := $(STRICT_CFLAGS) $(CLANG_SPECIFIC_STRICT_FLAGS) $(GCC_SPECIFIC_STRICT_FLAGS) RELEASE_CFLAGS := \ -O3 \ -flto=auto \ -fno-semantic-interposition \ -fstack-protector-strong \ -fstack-clash-protection \ -fPIE \ -D_FORTIFY_SOURCE=2 \ -ffunction-sections \ -fdata-sections \ -fcf-protection \ -march=native DEBUG_CFLAGS_COMMON := -g -Og -fno-omit-frame-pointer -fno-common -flto=auto ANALYZER_FLAGS_GCC := -fanalyzer SANITIZER_ASAN_FLAGS := -fsanitize=address,undefined,leak SANITIZER_TSAN_FLAGS := -fsanitize=thread COMMON_LDFLAGS := -pthread $(PKG_LDFLAGS) -lm -latomic RELEASE_LDFLAGS := -flto=auto -Wl,--gc-sections -Wl,--build-id=none -s -pie .PHONY: all fallback debug debug-threaded check clean install uninstall tidy iwyu format format-check .DELETE_ON_ERROR: CFLAGS := $(CORE_CFLAGS) LDFLAGS := $(COMMON_LDFLAGS) all: CFLAGS += $(RELEASE_CFLAGS) all: LDFLAGS += $(RELEASE_LDFLAGS) all: $(TARGET) fallback: $(TARGET) debug: CC := $(CC) debug: CFLAGS += $(STRICT_CFLAGS) $(DEBUG_CFLAGS_COMMON) $(SANITIZER_ASAN_FLAGS) debug: CFLAGS += $(if $(findstring clang,$(notdir $(CC))),$(CLANG_SPECIFIC_STRICT_FLAGS)) debug: CFLAGS += $(if $(findstring gcc,$(notdir $(CC))),$(GCC_SPECIFIC_STRICT_FLAGS) $(ANALYZER_FLAGS_GCC)) debug: LDFLAGS += $(SANITIZER_ASAN_FLAGS) debug: LDFLAGS += -flto=auto debug: $(TARGET) debug-threaded: CC := $(CC) debug-threaded: CFLAGS += $(STRICT_CFLAGS) $(DEBUG_CFLAGS_COMMON) $(SANITIZER_TSAN_FLAGS) debug-threaded: CFLAGS += $(if $(findstring clang,$(notdir $(CC))),$(CLANG_SPECIFIC_STRICT_FLAGS)) debug-threaded: CFLAGS += $(if $(findstring gcc,$(notdir $(CC))),$(GCC_SPECIFIC_STRICT_FLAGS) $(ANALYZER_FLAGS_GCC)) debug-threaded: LDFLAGS += $(SANITIZER_TSAN_FLAGS) debug-threaded: LDFLAGS += -flto=auto debug-threaded: $(TARGET) -include $(DEPS) $(MAIN_SRC:.c=.o): $(MAIN_SRC) @echo " CC (Strict) $<" $(CC) $(DEPFLAGS) $(CFLAGS) -c $< -o $@ src/%.o: src/%.c @echo " CC (Strict) $<" $(CC) $(DEPFLAGS) $(CFLAGS) -c $< -o $@ lib/%.o: lib/%.c @echo " CC (Lax) $<" $(CC) $(DEPFLAGS) $(filter-out $(ALL_STRICT_FLAGS),$(CFLAGS)) -c $< -o $@ IWYU := $(shell command -v include-what-you-use 2>/dev/null) $(TARGET): $(OBJS) @echo " CCLD $@" $(CC) $(OBJS) -o $@ $(LDFLAGS) @echo "Build complete. Executable '$(TARGET)' created." check: debug tidy iwyu format-check clean: @echo "Cleaning up..." rm -f $(TARGET) $(OBJS) $(DEPS) @echo "Clean complete." install: all @echo "Installing $(TARGET) to $(INSTALL_PATH)..." install -Dm755 "$(TARGET)" "$(INSTALL_PATH)/$(TARGET)" @echo "Installation complete." uninstall: @echo "Uninstalling $(TARGET)..." rm -f "$(INSTALL_PATH)/$(TARGET)" $(MAKE) clean @echo "Uninstall complete." tidy: @echo " TIDY Running clang-tidy..." clang-tidy $(MAIN_SRC) $(APP_SRCS) -- $(CORE_CFLAGS) $(STRICT_CFLAGS) $(CLANG_SPECIFIC_STRICT_FLAGS) iwyu: @if [ -z "$(IWYU)" ]; then \ echo " SKIP include-what-you-use not found on this system."; \ else \ for file in $(MAIN_SRC) $(APP_SRCS); do \ echo " IWYU $$file"; \ $(IWYU) -Xiwyu --error \ -Xiwyu --check_also="src/*.h" \ $(CORE_CFLAGS) $(STRICT_CFLAGS) $$file || exit 1; \ done; \ fi format: @echo " FORMAT Applying source code formatting..." clang-format -i $(PROJECT_SRCS) format-check: @echo " FORMAT Checking source code formatting..." clang-format --dry-run -Werror $(PROJECT_SRCS)