From 9a19e7fb7e8f74a991313c8dffb49da0d3283b22 Mon Sep 17 00:00:00 2001 From: rexy712 Date: Wed, 18 Mar 2020 13:15:47 -0700 Subject: [PATCH] Add makefile for single executable with progress indicator --- makefile.exe_progress | 220 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 makefile.exe_progress diff --git a/makefile.exe_progress b/makefile.exe_progress new file mode 100644 index 0000000..5ac1fc1 --- /dev/null +++ b/makefile.exe_progress @@ -0,0 +1,220 @@ +#This program is free software: you can redistribute it and/or modify +#it under the terms of the GNU General Public License as published by +#the Free Software Foundation, either version 3 of the License, or +#(at your option) any later version. + +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with this program. If not, see . + +#Copyright 2020 rexy712 + +#Makefile to generate a single executable from all sources in SOURCE_DIRS that end in EXT + +ifeq ($(OS),Windows_NT) + WINDOWS::=1 +endif + +SOURCE_DIRS::=src +SOURCES::= +OBJDIR::=obj +DEPDIR::=$(OBJDIR)/dep +LIBDIR::=lib +INCLUDE_DIRS::=include +CFLAGS::=-g -std=c18 -Wall -pedantic -Wextra +CXXFLAGS::=-g -std=c++17 -Wall -pedantic -Wextra +EXT::=cpp +LANG::=$(EXT) +MAIN_EXECUTABLE::=tester +PRE_TARGETS::= +POST_TARGETS::= +CLEAN_TARGETS::= +RELEASE?=0 +MEMCHK?=0 +SAVECFLAGS?=1 +VERBOSE=0 + +ifneq ($(WINDOWS),1) + #*nix settings + CC::=gcc + CXX::=g++ + LDLIBS::= + LDFLAGS::= + STRIP::=strip + RANLIB::=ranlib + AR::=ar + AS::=as +else #windows + #windows settings + #windows is a fuckwit + MINGW_PREFIX::=x86_64-w64-mingw32- + CC::=$(MINGW_PREFIX)gcc + CXX::=$(MINGW_PREFIX)g++ + LDLIBS::= + LDFLAGS::= + STRIP::=$(MINGW_PREFIX)strip + RANLIB::=$(MINGW_PREFIX)ranlib + AR::=$(MINGW_PREFIX)ar + AS::=$(MINGW_PREFIX)as +endif #windows + +#Put your custom targets for PRE_TARGETS, POST_TARGETS, and CLEAN_TARGETS here: + + +########################################################################################################### +#Everything past this point is internal BS, probably best not to touch it unless you know what you're doing + +#set the all target as the default target, otherwise the topmost target will run +.DEFAULT_GOAL::=all + +#set the main target to match the output of mingw +ifeq ($(WINDOWS),1) + MAIN_EXECUTABLE::=$(MAIN_EXECUTABLE).exe +endif + +#system dependant bullshit +ifeq ($(OS),Windows_NT) + #windows' cmd commands + mkdir=mkdir $(subst /,\,$(1)) > NUL 2>&1 + rm=del /F $(1) > NUL 2>&1 + rmdir=rd /S /Q $(1) > NUL 2>&1 + move=move /Y $(subst /,\,$(1)) $(subst /,\,$(2)) > NUL 2>&1 + copy=copy /Y /B $(subst /,\,$(1)) $(subst /,\,$(2)) > NUL 2>&1 +else + #*nix terminal commands + mkdir=mkdir -p $(1) + rm=rm -f $(1) + rmdir=rm -rf $(1) + move=mv $(1) $(2) + copy=cp $(1) $(2) +endif + +#setup compiler and flags based on language +ifeq ($(LANG),cpp) + COMPILER_FLAGS::=$(CXXFLAGS) + COMPILER::=$(CXX) +else ifeq ($(LANG),c) + COMPILER_FLAGS::=$(CFLAGS) + COMPILER::=$(CC) +endif + +ifeq ($(RELEASE),1) + #a lot of false strict aliasing warnings from gcc 9 + COMPILER_FLAGS+=-O2 -Wno-strict-aliasing + POST_TARGETS+= do_strip +else ifeq ($(MEMCHK),1) + #use asan to check memory leaks/invalid accesses + LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls + COMPILER_FLAGS+=-O0 -g3 -ggdb -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls +else + #default target + COMPILER_FLAGS+=-O0 -g3 -ggdb +endif + +ifeq ($(SAVECFLAGS),1) + CFLAGS_TMPFILE::=.cflags.tmp + OLD_COMPILEFLAGS::=$(file <$(CFLAGS_TMPFILE)) +endif + +#add dependency tracking and include directories +INTERNAL_COMPILERFLAGS=-c $(foreach dir,$(INCLUDE_DIRS),-I"$(dir)") -MMD -MP -MF"$(DEPDIR)/$(notdir $(patsubst %.o,%.d,$@))" +THIS_MAKEFILE_NAME::=$(lastword $(MAKEFILE_LIST)) +INTERNAL_SOURCES::=$(SOURCES) $(foreach source,$(SOURCE_DIRS),$(foreach ext,$(EXT),$(wildcard $(source)/*.$(ext)))) +OBJECTS::=$(addprefix $(OBJDIR)/,$(subst \,.,$(subst /,.,$(addsuffix .o,$(INTERNAL_SOURCES))))) +ALL_COMPILEFLAGS=$(COMPILER_FLAGS) $(INTERNAL_COMPILERFLAGS) +ifeq ($(VERBOSE),1) + SILENCER::= +else + SILENCER::=@ +endif + +#Arguments to make submake use this makefile without "Entering directory" stuff +SUBMAKE_ARGUMENTS::=--no-print-directory -e -f "$(THIS_MAKEFILE_NAME)" +#just a variable for a newline +define \n + + +endef + +.PHONY: cflags-update +cflags-update: +ifeq ($(SAVECFLAGS),1) +ifneq ($(subst -MF"$(DEPDIR)/",-MF"$(DEPDIR)/cflags-update",$(ALL_COMPILEFLAGS)),$(OLD_COMPILEFLAGS)) + $(file >$(CFLAGS_TMPFILE),$(ALL_COMPILEFLAGS)) +endif +endif + +ifndef PRINT_PERCENT +TOTAL_UNITS:=$(shell $(MAKE) -nrR --no-print-directory $(MAKECMDFLAGS) -f $(lastword $(MAKEFILE_LIST)) MEMCHK=$(MEMCHK) RELEASE=$(RELEASE) SAVECFLAGS=$(SAVECFLAGS) PRINT_PERCENT=PRINT_PERCENT | grep -c PRINT_PERCENT) +UNIT_COUNTER:=c +CURRENT_UNIT=$(words $(UNIT_COUNTER))$(eval UNIT_COUNTER:=c $(UNIT_COUNTER)) +GREEN::="\\e[32m" +CLEAR::="\\e[0m" +PRINT_PERCENT=@echo -e "$(GREEN)[$(CURRENT_UNIT)/$(TOTAL_UNITS)] $(1)$(CLEAR)" +else +unexport PRINT_PERCENT #unfortunately cannot work with submake without intermediate files +endif + +#default target: run targets in PRE_TARGETS, then the main executable, then POST_TARGETS +.PHONY: all +all: cflags-update +ifneq ($(PRE_TARGETS),) + @echo -e "$(GREEN)Running PRE_TARGETS$(CLEAR)" +endif + $(foreach target,$(PRE_TARGETS),@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(target)"$(\n)) + @$(MAKE) $(SUBMAKE_ARGUMENTS) "$(MAIN_EXECUTABLE)" +ifneq ($(POST_TARGETS),) + @echo -e "$(GREEN)Running POST_TARGETS$(CLEAR)" +endif + $(foreach target,$(POST_TARGETS),@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(target)"$(\n)) + +#Called in POST_TARGETS when RELEASE=1 +.PHONY: do_strip +do_strip: + $(STRIP) --strip-all "$(MAIN_EXECUTABLE)" + +#Link executable +$(MAIN_EXECUTABLE): $(OBJECTS) + @$(call PRINT_PERCENT,Linking $@) + $(SILENCER)$(COMPILER) $(LDFLAGS) $^ -o "$(basename $@)" $(LDLIBS) + +#Object target recipe +define GENERATE_OBJECTS +$$(OBJDIR)/$(subst \,.,$(subst /,.,$(1))).%.o: $(1)/% $(CFLAGS_TMPFILE) + @$$(call PRINT_PERCENT,Building $$<) + $(SILENCER)$$(COMPILER) $$(ALL_COMPILEFLAGS) "$$<" -o "$$@" +endef +define GENERATE_INDIVIDUAL_OBJECTS +$$(OBJDIR)/$(subst \,.,$(subst /,.,$(1))).o: $(1) $(CFLAGS_TMPFILE) + @$$(call PRINT_PERCENT,Building $$<) + $(SILENCER)$$(COMPILER) $$(ALL_COMPILEFLAGS) "$$<" -o "$$@" +endef + +#Create targets for object files +$(foreach dir,$(SOURCE_DIRS),$(eval $(call GENERATE_OBJECTS,$(dir)))) +$(foreach src,$(SOURCES),$(eval $(call GENERATE_INDIVIDUAL_OBJECTS,$(src)))) +$(OBJECTS): | $(OBJDIR) $(DEPDIR) + +#Output directory creation +$(OBJDIR): + $(call mkdir,"$@") +$(DEPDIR): + $(call mkdir,"$@") + +.PHONY: clean +clean: + $(foreach target,$(CLEAN_TARGETS),@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(target)"$(\n)) + $(call rmdir,"$(DEPDIR)") + $(call rmdir,"$(OBJDIR)") + $(call rm,"$(MAIN_EXECUTABLE)") + $(call rm,"$(MAIN_EXECUTABLE).exe") +ifeq ($(SAVECFLAGS),1) + $(call rm,"$(CFLAGS_TMPFILE)") +endif + +#header file dep tracking +-include $(wildcard $(DEPDIR)/*.d)