From cbefafacf80ee9fa6d65107e690b1d15a8a56260 Mon Sep 17 00:00:00 2001 From: Quinn Date: Wed, 21 May 2025 16:49:52 +0200 Subject: [PATCH] rework makefile to be more os- and compiler-agnostic. alongside removing non-crucial complexity and attempting to simplify things as much as I can. --- makefile | 165 ++++++++++++++++++++++++++----------------------------- 1 file changed, 77 insertions(+), 88 deletions(-) diff --git a/makefile b/makefile index b112799..334228e 100644 --- a/makefile +++ b/makefile @@ -1,118 +1,112 @@ # dependencies: # - make -# - clang -# - glfw3 (install glfw3:x64-mingw-dynamic via vcpkg for win cross compilation) -# - vcpkg (win cross-compilation) -NAME := mcaselector-lite -DEBUG ?= 0 -ARCH ?= 0 +# - C compiler +# - glfw3 (install glfw3:x64-mingw-dynamic via vcpkg for cross compilation) +# - (windows) git bash (recommended) -# C compiler options -CC := clang -CSTD := c17 -CFLAGS := -Wall -Wextra -Wpedantic -Wno-pointer-arith -Ilib -LDFLAGS := +# build configuration, information about the current build process +NAME := mcaselector-lite +VERSION := 0.0.0 +DEBUG ?= 0 +CC ?= cc +CFLAGS += -c -std=c17 -Wall -Wextra -Wpedantic -Ilib -MMD -MP +LDFLAGS += +MARCH ?= $(shell uname -m) +KERNEL ?= $(shell uname -s | tr '[:upper:]' '[:lower:]') + +# check whether KERNEL is something nonsensical +ISWIN := $(if $(filter linux darwin freebsd netbsd openbsd,$(KERNEL)),0,1) # profiles -ifneq ($(DEBUG),0) -CFLAGS += -g -Og -fsanitize=address,undefined +ifeq ($(DEBUG),1) # check whether we're debugging +CFLAGS += -Og -g -fsanitize=address,undefined LDFLAGS += -fsanitize=address,undefined PROF := dbg -else -CFLAGS += -DNDEBUG -O2 -Werror +else ifeq ($(DEBUG),test) # check whether we're perhaps testing +CFLAGS += -O2 +PROF := test +else # otherwise, assume release +CFLAGS += -O2 -DNDEBUG PROF := rel endif -# targets -ifneq ($(MAKECMDGOALS),clean) -ifeq ($(ARCH),linux-x86_64) -CFLAGS += -target x86_64-pc-linux-gnu $(shell pkg-config --cflags glfw3) -LDFLAGS += -target x86_64-pc-linux-gnu $(shell pkg-config --libs glfw3) -else ifeq ($(ARCH),win-x86_64) -CFLAGS += -target x86_64-pc-windows-gnu -I$(VCPKG_ROOT)/installed/x64-mingw-dynamic/include -LDFLAGS += -target x86_64-pc-windows-gnu -L$(VCPKG_ROOT)/installed/x64-mingw-dynamic/lib -lglfw3dll -fuse-ld=lld -EXT := .exe +# setup the VCPKG_TRIPLET +# because microsoft thinks they should use a different method of classifying stuff than the standard +ifneq ($(VCPKG_ROOT),) +VCPKG_TRIPLET ?= $(strip \ + $(if $(filter x86_64,$(MARCH)),x64, \ +))-$(strip \ + $(if $(filter linux,$(KERNEL)),linux-dynamic, \ + $(if $(filter darwin,$(KERNEL)),osx-dynamic, \ + mingw-static)) \ +) + +# override the pkg config path, so it is used instead of system packages +export PKG_CONFIG_PATH := $(VCPKG_ROOT)/installed/$(VCPKG_TRIPLET)/lib/pkgconfig +else ifneq ($(shell which pkg_config),) +$(warning couldn't find VCPKG_ROOT, attempting to use system packages using pkg-config!) else -$(error you must set the ARCH environment variable to one of these: 'linux-x86_64' 'win-x86_64') +$(error neither VCPKG_ROOT nor pkg_config were available!) endif + +# use pkg-config to set the include and linker information +CFLAGS += $(shell pkg-config --cflags glfw3) +LDFLAGS += $(shell pkg-config --libs glfw3) + +# windows specific handling +ifeq ($(ISWIN),1) +NAME := $(NAME).exe +endif + +# build directory structure +DIR_BIN := bin/$(MARCH)-$(KERNEL)/$(VERSION)/$(PROF) +DIR_OBJ := obj/$(MARCH)-$(KERNEL)/$(VERSION)/$(PROF) + +# get source files +ifneq ($(DEBUG),test) +SRC := $(shell find src/ -name '*.c') +else +SRC := $(filter-out src/main.c, $(shell find test/ src/ -name '*.c')) +CFLAGS += -DGLFW_DLL endif # output files -ifneq ($(ARCH),0) -DIR_BIN := bin/$(ARCH)/$(PROF) -DIR_OBJ := obj/$(ARCH)/$(PROF) -BIN := $(DIR_BIN)/$(NAME)$(EXT) - -C_SRC := $(shell find src/ -name '*.c') -C_OBJ := $(patsubst src/%,$(DIR_OBJ)/%,$(C_SRC:.c=.o)) -C_DEP := $(C_OBJ:.o=.d) -C_TSRC := $(shell find test/src/ -name '*.c') -C_TOBJ := $(patsubst test/src/%,test/$(DIR_OBJ)/%,$(C_TSRC:.c=.o)) -C_TDEP := $(C_TOBJ:.o=.d) -C_TOBJ += $(filter-out $(DIR_OBJ)/main.o, $(C_OBJ)) +BIN := $(DIR_BIN)/$(NAME) +OBJ := $(SRC:%.c=$(DIR_OBJ)/%.o) +DEP := $(OBJ:.o=.d) COMPILE_COMMANDS := $(DIR_OBJ)/compile_commands.json -endif -define log_col - @printf "\033[%sm%s\033[0m\n" $(2) $(1) -endef -comp = $(call log_col,$(1),92) -mesg = $(call log_col,$(1),94) -warn = $(call log_col,$(1),93) -fail = $(call log_col,$(1),91) +.PHONY: run compile +run: compile_commands $(BIN); $(BIN) +compile: compile_commands $(BIN) # creates the binary (linking step) -define link_bin -$1: $2 - @$$(call mesg,"CC: '$$(CC)'") - @$$(call mesg,"CFLAGS: '$$(CFLAGS)'") - @$$(call mesg,"LDFLAGS: '$$(LDFLAGS)'") - @$$(call comp,"linking to: '$$@'") +$(BIN): $(OBJ) + @mkdir -p $(@D) + $(CC) -o $@ $^ $(LDFLAGS) - @mkdir -p $$(@D) - @$$(CC) $$(LDFLAGS) -o $$@ $$^ - @$$(call mesg,"current profile: '$$(PROF)'") +# compilation rule +$(DIR_OBJ)/%.o: %.c + @mkdir -p $(@D) + $(CC) $(CFLAGS) -o $@ $< -endef - -# creates .o and .d files -define compile_obj -$1/%.o: $2/%.c - @$$(call comp,"compiling $$@ from $$<") - @mkdir -p $$(@D) - @$$(CC) $$(CFLAGS) -c -MD -MP -std=$$(CSTD) -x c -o $$@ $$< -endef - -# compiles and executes the produced binary -run: compile; cd $(DIR_BIN) && ./$(NAME)$(EXT) -compile: compile_commands $(BIN) -run-test: compile-test; cd test/$(DIR_BIN) && ./test$(EXT) -compile-test: test/$(DIR_BIN)/test$(EXT) - -.NOTPARALLEL: +.PHONY .NOTPARALLEL: clean: - @$(call warn,"cleaning!") - rm -rf bin/ obj/ test/obj test/bin compile_commands.json - -# compilation macros -$(eval $(call link_bin,$(BIN),$(C_OBJ))) # link the binary -$(eval $(call compile_obj,$(DIR_OBJ),src)) # compile the objects for the binary -$(eval $(call link_bin,test/$(DIR_BIN)/test$(EXT),$(C_TOBJ))) # link the testing binary -$(eval $(call compile_obj,test/$(DIR_OBJ),test/src)) # compile the objects for the testing binary + rm -rf obj bin compile_commands.json # update compile commands if the makefile has been updated (for linting) compile_commands: # default, empty rule ifneq ($(shell which bear),) ifneq ($(COMPILE_COMMANDS),) ifeq ($(NOCMDS),) -.NOTPARALLEL .PHONY: +.PHONY .NOTPARALLEL: compile_commands: $(COMPILE_COMMANDS) - @[ "$(readlink compile_commands.json)" != "$<" ] && ln -sf $< compile_commands.json + ln -sf $< compile_commands.json .NOTPARALLEL: $(COMPILE_COMMANDS): makefile - @$(call warn,"regenerating compile_commands.json thus recompiling.") + @$(warning regenerating compile_commands.json thus recompiling.) @mkdir -p ${@D} # ensure the target directory exists @touch $@ # create the file so it isn't retriggered (will just change modification time if already exists) @bear --output $@ -- make -B compile NOCMDS=1 # rebuild the current target using bear, to create the compile commands @@ -120,9 +114,4 @@ endif endif endif -# disable implicit rules -.SUFFIXES: - -# include the dependencies --include $(C_DEP) --include $(C_TDEP) +-include $(DEP)