# Configuration (File extensions, tools to be used, etc) OPTLIBEXT=-O DEBUGLIBEXT=-g LIBEXTS=$(OPTLIBEXT) $(DEBUGLIBEXT) ifeq "$(MAKECMDGOALS)" "opt" LIBEXT=$(OPTLIBEXT) OPTFLAGS=$(OPTFLAGS_OPT) else LIBEXT=$(DEBUGLIBEXT) OPTFLAGS=$(OPTFLAGS_DEBUG) endif CXX=clang++ CC=clang LN=ln RM=rm MKDIR=mkdir TOUCH=touch DIRNAME=dirname OPTFLAGS_OPT=-O3 OPTFLAGS_DEBUG=-O0 -g # flags used for linking and compilation FLAGS=# # These flags are for compilation (not linking) only # -MMD auto-genenerates .d files in Make format when .o files are created COMPILE_FLAGS=-MMD -Werror -Wall -Wextra -pedantic -pipe $(OPTFLAGS) # Flags for linking only. LINK_FLAGS=-fuse-ld=gold # C / C++ specific compilation flags CXX_STD_FLAGS=-std=c++20 CXX_COMPILE_FLAGS=$(CXX_STD_FLAGS) C_STD_FLAGS=-std=c99 C_COMPILE_FLAGS=$(C_STD_FLAGS) CXX_SRC_EXTS=cpp C CPP C_SRC_EXTS=c SRC_EXTS=$(CXX_SRC_EXTS) $(C_SRC_EXTS) BUILDDIR=build DIRECTORIES=$(BUILDDIR) EXECUTABLE_REL=main LINK_NAME=$(BUILDDIR)/$(EXECUTABLE_REL) EXECUTABLE=$(LINK_NAME)$(LIBEXT) # Collect files to be compiled CXX_SRCS=$(foreach ext, $(CXX_SRC_EXTS), $(shell find src -name "*.$(ext)")) C_SRCS=$(foreach ext, $(C_SRC_EXTS), $(shell find src -name "*.$(ext)")) SRCS=$(CXX_SRCS) $(C_SRCS) OBJS=$(foreach ext, $(SRC_EXTS), $(patsubst %.$(ext), $(BUILDDIR)/%$(LIBEXT).o, $(filter %.$(ext), $(SRCS)))) # If there is at least one C++ source use the c++ compiler CXX to link. LINKER=$(CC) $(FLAGS) $(LINK_FLAGS) ifneq "$(strip $(CXX_SRCS))" "" LINKER=$(CXX) $(FLAGS) $(LINK_FLAGS) endif MAKECONFIG=Make.config # The set of Make-files influencing the build, hence everything depends on them MAKE_DEPENDENCIES=Makefile $(MAKECONFIG) DEFAULT_TARGET=debug # Include Make.config to modify variables above -include $(MAKECONFIG) # The supported meta targets, dependencies .PHONY: clean debug opt default check default: $(DEFAULT_TARGET) clean debug opt: check opt debug: $(EXECUTABLE) $(OBJS) : $(MAKE_DEPENDENCIES) | $(BUILDDIR) # include autogenerated .d files -include $(OBJS:.o=.d) # Rules define CXX_TO_OBJ $(CXX) $(FLAGS) $(CXX_COMPILE_FLAGS) $(COMPILE_FLAGS) $< -c -o $@ endef define C_TO_OBJ $(CC) $(FLAGS) $(C_COMPILE_FLAGS) $(COMPILE_FLAGS) $< -c -o $@ endef define MK_TARGETDIR @$(MKDIR) -p $$($(DIRNAME) $@) endef $(BUILDDIR)/%$(LIBEXT).o: %.cpp $(MK_TARGETDIR) $(CXX_TO_OBJ) $(BUILDDIR)/%$(LIBEXT).o: %.C $(MK_TARGETDIR) $(CXX_TO_OBJ) $(BUILDDIR)/%$(LIBEXT).o: %.CPP $(MK_TARGETDIR) $(CXX_TO_OBJ) $(BUILDDIR)/%$(LIBEXT).o: %.c $(MK_TARGETDIR) $(C_TO_OBJ) $(EXECUTABLE): $(OBJS) | $(BUILDDIR) $(LINKER) $(OBJS) -o $@ # Create link in opt/debug target opt debug: $(LN) -sf $(EXECUTABLE_REL)$(LIBEXT) $(LINK_NAME) check: $(BUILDDIR) @forbidden=$$(find $(BUILDDIR) -not -type d $(foreach filext, .o .d, -not -name "*$(filext)") $(foreach libext, $(LIBEXTS) "", -not -name "$(EXECUTABLE_REL)$(libext)")); \ if [ "$${forbidden}x" != "x" ]; then echo "Error: $(BUILDDIR) contains non-autogenerated files $${forbidden}"; exit 1; fi $(DIRECTORIES): @$(MKDIR) $@ $(MAKECONFIG): @$(TOUCH) $@ clean: @$(RM) -rf $(BUILDDIR)