From 8e7fb0433b7497bd7f8a6ddb5f33d2a86f8e7482 Mon Sep 17 00:00:00 2001 From: rexy712 Date: Fri, 20 Mar 2020 12:52:41 -0700 Subject: [PATCH] Change basic makefiles to not use recursive invocations of make. This does potentially break some build behaviors (without tampering with some internals). So I'm keeping the recursive versions as new files --- makefile.basic | 85 ++++++++------- makefile.library | 156 +++++++++++++-------------- makefile.reclib | 264 +++++++++++++++++++++++++++++++++++++++++++++ makefile.recursive | 206 +++++++++++++++++++++++++++++++++++ 4 files changed, 587 insertions(+), 124 deletions(-) create mode 100644 makefile.reclib create mode 100644 makefile.recursive diff --git a/makefile.basic b/makefile.basic index bf81725..9caa392 100644 --- a/makefile.basic +++ b/makefile.basic @@ -23,19 +23,16 @@ SOURCE_DIRS::=src SOURCES::= OBJDIR::=obj DEPDIR::=$(OBJDIR)/dep -LIBDIRS::=lib +LIBDIRS::= INCLUDE_DIRS::=include CFLAGS::=-std=c18 -Wall -pedantic -Wextra CXXFLAGS::=-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 +SAVEFLAGS?=1 ifneq ($(WINDOWS),1) #*nix settings @@ -59,23 +56,29 @@ else #windows RANLIB::=$(MINGW_PREFIX)ranlib AR::=$(MINGW_PREFIX)ar AS::=$(MINGW_PREFIX)as + MAIN_EXECUTABLE::=$(MAIN_EXECUTABLE).exe endif #windows -#Put your custom targets for PRE_TARGETS, POST_TARGETS, and CLEAN_TARGETS here: +#main targets +.PHONY: all +#prerun targets +all:: +#main target +all:: | flags-update $(MAIN_EXECUTABLE) +#postrun targets +all:: + +#custom clean targets +clean:: ########################################################################################################### #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 +#set the default 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 @@ -102,10 +105,11 @@ else ifeq ($(LANG),c) 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 +#a lot of false strict aliasing warnings from gcc 9 +COMPILER_FLAGS+=-O2 -Wno-strict-aliasing + else ifeq ($(MEMCHK),1) #use asan to check memory leaks/invalid accesses LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls @@ -115,22 +119,22 @@ else COMPILER_FLAGS+=-O0 -g3 -ggdb endif -ifeq ($(SAVECFLAGS),1) +ifeq ($(SAVEFLAGS),1) CFLAGS_TMPFILE::=.cflags.tmp + LDFLAGS_TMPFILE::=.ldflags.tmp OLD_COMPILEFLAGS::=$(file <$(CFLAGS_TMPFILE)) + OLD_LINKFLAGS::=$(file <$(LDFLAGS_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,$@))" INTERNAL_LINKFLAGS=$(foreach dir,$(LIBDIRS),-L"$(dir)") -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) ALL_LINKFLAGS=$(INTERNAL_LINKFLAGS) $(LDFLAGS) -#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 @@ -139,40 +143,39 @@ endef .PHONY: cflags-update cflags-update: -ifeq ($(SAVECFLAGS),1) +ifeq ($(SAVEFLAGS),1) ifneq ($(subst -MF"$(DEPDIR)/",-MF"$(DEPDIR)/cflags-update",$(ALL_COMPILEFLAGS)),$(OLD_COMPILEFLAGS)) $(file >$(CFLAGS_TMPFILE),$(ALL_COMPILEFLAGS)) endif +$(CFLAGS_TMPFILE): cflags-update +endif +.PHONY: ldflags-update +ldflags-update: +ifeq ($(SAVEFLAGS),1) +ifneq ($(ALL_LINKFLAGS),$(OLD_LINKFLAGS)) + $(file >$(LDFLAGS_TMPFILE),$(ALL_LINKFLAGS)) +endif +$(LDFLAGS_TMPFILE): ldflags-update endif -#default target: run targets in PRE_TARGETS, then the main executable, then POST_TARGETS -.PHONY: all -all: cflags-update - $(foreach target,$(PRE_TARGETS),@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(target)"$(\n)) - @$(MAKE) $(SUBMAKE_ARGUMENTS) "$(MAIN_EXECUTABLE)" - $(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)" +.PHONY: flags-update +flags-update: cflags-update ldflags-update #Link executable -$(MAIN_EXECUTABLE): $(OBJECTS) - $(COMPILER) $^ -o "$(basename $@)" $(ALL_LINKFLAGS) $(LDLIBS) +$(MAIN_EXECUTABLE): $(OBJECTS) $(LDFLAGS_TMPFILE) + $(COMPILER) $(OBJECTS) -o "$(basename $@)" $(ALL_LINKFLAGS) $(LDLIBS) +ifeq ($(RELEASE),1) + $(STRIP) --strip-all "$(MAIN_EXECUTABLE)" +endif #Object target recipe -define GENERATE_OBJECTS -$$(OBJDIR)/$(subst \,.,$(subst /,.,$(1))).%.o: $(1)/% $(CFLAGS_TMPFILE) - $$(COMPILER) $$(ALL_COMPILEFLAGS) "$$<" -o "$$@" -endef define GENERATE_INDIVIDUAL_OBJECTS $$(OBJDIR)/$(subst \,.,$(subst /,.,$(1))).o: $(1) $(CFLAGS_TMPFILE) $$(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)))) +$(foreach src,$(INTERNAL_SOURCES),$(eval $(call GENERATE_INDIVIDUAL_OBJECTS,$(src)))) $(OBJECTS): | $(OBJDIR) $(DEPDIR) #Output directory creation @@ -182,14 +185,14 @@ $(DEPDIR): $(call mkdir,"$@") .PHONY: clean -clean: - $(foreach target,$(CLEAN_TARGETS),@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(target)"$(\n)) +clean:: $(call rmdir,"$(DEPDIR)") $(call rmdir,"$(OBJDIR)") $(call rm,"$(MAIN_EXECUTABLE)") $(call rm,"$(MAIN_EXECUTABLE).exe") -ifeq ($(SAVECFLAGS),1) +ifeq ($(SAVEFLAGS),1) $(call rm,"$(CFLAGS_TMPFILE)") + $(call rm,"$(LDFLAGS_TMPFILE)") endif #header file dep tracking diff --git a/makefile.library b/makefile.library index 3ef1ed2..53a6a3f 100644 --- a/makefile.library +++ b/makefile.library @@ -30,14 +30,11 @@ CXXFLAGS::=-std=c++17 -Wall -pedantic -Wextra EXT::=cpp LANG::=$(EXT) MAIN_LIBRARY::=tester -PRE_TARGETS::= -POST_TARGETS::= -CLEAN_TARGETS::= SHARED?=1 STATIC?=0 RELEASE?=0 MEMCHK?=0 -SAVECFLAGS?=1 +SAVEFLAGS?=1 ifneq ($(WINDOWS),1) #*nix settings @@ -49,6 +46,9 @@ ifneq ($(WINDOWS),1) RANLIB::=ranlib AR::=ar AS::=as + ifeq ($(SHARED),1) + INTERNAL_SHARED_LIBRARY::=lib$(MAIN_LIBRARY).so + endif else #windows #windows settings #windows is a fuckwit @@ -61,11 +61,29 @@ else #windows RANLIB::=$(MINGW_PREFIX)ranlib AR::=$(MINGW_PREFIX)ar AS::=$(MINGW_PREFIX)as + ifeq ($(SHARED),1) + INTERNAL_SHARED_LIBRARY::=$(MAIN_LIBRARY).dll + endif endif #windows +ifeq ($(STATIC),1) + INTERNAL_STATIC_LIBRARY::=lib$(MAIN_LIBRARY).a +endif #Put your custom targets for PRE_TARGETS and POST_TARGETS here: +#default target +.PHONY: all +#pre targets +all:: + +all:: flags-update $(INTERNAL_STATIC_LIBRARY) $(INTERNAL_SHARED_LIBRARY) + +#post targets +all:: + +#custom clean targets +clean:: ########################################################################################################### #Everything past this point is internal BS, probably best not to touch it unless you know what you're doing @@ -74,16 +92,6 @@ endif #windows .DEFAULT_GOAL::=all #setup the actual output library name depending on shared/static and windows/anything else -ifeq ($(WINDOWS),1) - INTERNAL_SHARED_LIBRARY::=lib$(MAIN_LIBRARY).a -else - INTERNAL_SHARED_LIBRARY::=lib$(MAIN_LIBRARY).so -endif -SHARED_LIBRARY_FLAGS=-fPIC -DLLOUT::=$(MAIN_LIBRARY).dll -INTERNAL_STATIC_LIBRARY::=lib$(MAIN_LIBRARY).a - - #system dependant bullshit ifeq ($(OS),Windows_NT) #windows' cmd commands @@ -113,7 +121,6 @@ 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 @@ -123,118 +130,101 @@ else COMPILER_FLAGS+=-O0 -g3 -ggdb endif -ifeq ($(SAVECFLAGS),1) +ifeq ($(SAVEFLAGS),1) CFLAGS_TMPFILE::=.cflags.tmp + LDFLAGS_TMPFILE::=.ldflags.tmp OLD_COMPILEFLAGS::=$(file <$(CFLAGS_TMPFILE)) + OLD_LINKFLAGS::=$(file <$(LDFLAGS_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,$@))" +ifeq ($(WINDOWS),1) +INTERNAL_LINKFLAGS=-Wl,--out-implib,"lib$(MAIN_LIBRARY).a" $(foreach dir,$(LIBDIRS),-L"$(dir)") +else INTERNAL_LINKFLAGS=$(foreach dir,$(LIBDIRS),-L"$(dir)") -ifeq ($(SHARED),1) - INTERNAL_COMPILERFLAGS+=$(SHARED_LIBRARY_FLAGS) endif -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))))) +STATIC_OBJECTS::=$(addprefix $(OBJDIR)/static/,$(subst \,.,$(subst /,.,$(addsuffix .o,$(INTERNAL_SOURCES))))) +SHARED_OBJECTS::=$(addprefix $(OBJDIR)/shared/,$(subst \,.,$(subst /,.,$(addsuffix .o,$(INTERNAL_SOURCES))))) ALL_COMPILEFLAGS=$(COMPILER_FLAGS) $(INTERNAL_COMPILERFLAGS) ALL_LINKFLAGS=$(INTERNAL_LINKFLAGS) $(LDFLAGS) -#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) +ifeq ($(SAVEFLAGS),1) ifneq ($(subst -MF"$(DEPDIR)/",-MF"$(DEPDIR)/cflags-update",$(ALL_COMPILEFLAGS)),$(OLD_COMPILEFLAGS)) $(file >$(CFLAGS_TMPFILE),$(ALL_COMPILEFLAGS)) endif +$(CFLAGS_TMPFILE): cflags-update endif -#default target: run targets in PRE_TARGETS, then build the main library, then POST_TARGETS -.PHONY: all -all: cflags-update - $(foreach target,$(PRE_TARGETS),@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(target)"$(\n)) -ifeq ($(SHARED),1) -ifeq ($(WINDOWS),1) - @$(MAKE) $(SUBMAKE_ARGUMENTS) "$(DLLOUT)" -else #windows - @$(MAKE) $(SUBMAKE_ARGUMENTS) "$(INTERNAL_SHARED_LIBRARY)" -endif #windows -endif #shared -ifeq ($(STATIC),1) -ifeq ($(SHARED),1) - @$(MAKE) $(SUBMAKE_ARGUMENTS) "object_clean" -endif #shared - @$(MAKE) $(SUBMAKE_ARGUMENTS) "$(INTERNAL_STATIC_LIBRARY)" SHARED=0 -endif #static - $(foreach target,$(POST_TARGETS),@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(target)"$(\n)) +.PHONY: ldflags-update +ldflags-update: +ifeq ($(SAVEFLAGS),1) +ifneq ($(ALL_LINKFLAGS),$(OLD_LINKFLAGS)) + $(file >$(LDFLAGS_TMPFILE),$(ALL_LINKFLAGS)) +endif +$(LDFLAGS_TMPFILE): ldflags-update +endif +.PHONY: flags-update +flags-update: cflags-update ldflags-update -ifeq ($(WINDOWS),1) -#target for windows shared library -$(DLLOUT): $(OBJECTS) - $(COMPILER) -shared -o "$(DLLOUT)" $^ -Wl,--out-implib,"lib$(MAIN_LIBRARY).a" $(SHARED_LIBRARY_FLAGS) $(ALL_LINKFLAGS) $(LDLIBS) -else #windows -#target for *nix shared library -$(INTERNAL_SHARED_LIBRARY): $(OBJECTS) - $(COMPILER) -shared -o "$@" $^ $(COMPILER_FLAGS) $(SHARED_LIBRARY_FLAGS) $(ALL_LINKFLAGS) $(LDLIBS) -endif #windows +#target for shared library +$(INTERNAL_SHARED_LIBRARY): $(SHARED_OBJECTS) $(LDFLAGS_TMPFILE) + $(COMPILER) -shared -o "$@" $(SHARED_OBJECTS) -fPIC $(ALL_LINKFLAGS) $(LDLIBS) +ifeq ($(RELEASE),1) + $(STRIP) --strip-debug "$@" +endif #target for static library -$(INTERNAL_STATIC_LIBRARY): $(OBJECTS) +$(INTERNAL_STATIC_LIBRARY): $(STATIC_OBJECTS) $(AR) rcs "$@" $^ $(RANLIB) "$@" -#Called in POST_TARGETS when RELEASE=1 -.PHONY: do_strip -do_strip: -ifeq ($(SHARED),1) - $(STRIP) --strip-debug "$(INTERNAL_SHARED_LIBRARY)" -endif -ifeq ($(STATIC),1) - $(STRIP) --strip-debug "$(INTERNAL_STATIC_LIBRARY)" -endif - #Object target recipe -define GENERATE_OBJECTS -$$(OBJDIR)/$(subst \,.,$(subst /,.,$(1))).%.o: $(1)/% $(CFLAGS_TMPFILE) - $$(COMPILER) $$(ALL_COMPILEFLAGS) "$$<" -o "$$@" +define GENERATE_SHARED_OBJECTS +$$(OBJDIR)/shared/$(subst \,.,$(subst /,.,$(1))).o: $(1) $(CFLAGS_TMPFILE) + $$(COMPILER) $$(ALL_COMPILEFLAGS) -fPIC "$$<" -o "$$@" endef -define GENERATE_INDIVIDUAL_OBJECTS -$$(OBJDIR)/$(subst \,.,$(subst /,.,$(1))).o: $(1) $(CFLAGS_TMPFILE) +#Object target recipe +define GENERATE_STATIC_OBJECTS +$$(OBJDIR)/static/$(subst \,.,$(subst /,.,$(1))).o: $(1) $(CFLAGS_TMPFILE) $$(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) +ifeq ($(SHARED),1) +$(foreach src,$(INTERNAL_SOURCES),$(eval $(call GENERATE_SHARED_OBJECTS,$(src)))) +endif +ifeq ($(STATIC),1) +$(foreach src,$(INTERNAL_SOURCES),$(eval $(call GENERATE_STATIC_OBJECTS,$(src)))) +endif + +$(STATIC_OBJECTS): | $(OBJDIR)/static $(DEPDIR) +$(SHARED_OBJECTS): | $(OBJDIR)/shared $(DEPDIR) $(OBJDIR): $(call mkdir,"$@") +$(OBJDIR)/static: $(OBJDIR) + $(call mkdir,"$@") +$(OBJDIR)/shared: $(OBJDIR) + $(call mkdir,"$@") $(DEPDIR): $(call mkdir,"$@") -.PHONY: object_clean -object_clean: - $(call rmdir,"$(OBJDIR)") - .PHONY: clean -clean: object_clean - $(foreach target,$(CLEAN_TARGETS),@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(target)"$(\n)) +clean:: + $(call rmdir,"$(OBJDIR)") $(call rmdir,"$(DEPDIR)") $(call rm,"lib$(MAIN_LIBRARY).so") $(call rm,"lib$(MAIN_LIBRARY).a") - $(call rm,"$(DLLOUT)") -ifeq ($(SAVECFLAGS),1) + $(call rm,"$(MAIN_LIBRARY).dll") +ifeq ($(SAVEFLAGS),1) $(call rm,"$(CFLAGS_TMPFILE)") + $(call rm,"$(LDFLAGS_TMPFILE)") endif #header file dep tracking diff --git a/makefile.reclib b/makefile.reclib new file mode 100644 index 0000000..76fc10e --- /dev/null +++ b/makefile.reclib @@ -0,0 +1,264 @@ +#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 2018-2020 rexy712 + +#Makefile to generate a single static or shared library from all the sources in SOURCE_DIRS ending in EXT + +ifeq ($(OS),Windows_NT) + WINDOWS::=1 +endif + +SOURCE_DIRS::=src +SOURCES::= +OBJDIR::=obj +DEPDIR::=$(OBJDIR)/dep +LIBDIRS::=lib +INCLUDE_DIRS::=include +CFLAGS::=-std=c18 -Wall -pedantic -Wextra +CXXFLAGS::=-std=c++17 -Wall -pedantic -Wextra +EXT::=cpp +LANG::=$(EXT) +MAIN_LIBRARY::=tester +PRE_TARGETS::= +POST_TARGETS::= +CLEAN_TARGETS::= +SHARED?=1 +STATIC?=0 +RELEASE?=0 +MEMCHK?=0 +SAVEFLAGS?=1 + +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::=-static-libgcc -static-libstdc++ + 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 and POST_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 + +#setup the actual output library name depending on shared/static and windows/anything else +ifeq ($(WINDOWS),1) + INTERNAL_SHARED_LIBRARY::=lib$(MAIN_LIBRARY).a +else + INTERNAL_SHARED_LIBRARY::=lib$(MAIN_LIBRARY).so +endif +SHARED_LIBRARY_FLAGS=-fPIC +DLLOUT::=$(MAIN_LIBRARY).dll +INTERNAL_STATIC_LIBRARY::=lib$(MAIN_LIBRARY).a + + +#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 ($(SAVEFLAGS),1) + CFLAGS_TMPFILE::=.cflags.tmp + OLD_COMPILEFLAGS::=$(file <$(CFLAGS_TMPFILE)) + LDFLAGS_TMPFILE::=.ldflags.tmp + OLD_LINKFLAGS::=$(file <$(LDFLAGS_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,$@))" +INTERNAL_LINKFLAGS=$(foreach dir,$(LIBDIRS),-L"$(dir)") +ifeq ($(SHARED),1) + INTERNAL_COMPILERFLAGS+=$(SHARED_LIBRARY_FLAGS) +endif +THIS_MAKEFILE_NAME::=$(lastword $(MAKEFILE_LIST)) +INTERNAL_SOURCES::=$(SOURCES) $(foreach source,$(SOURCE_DIRS),$(foreach ext,$(EXT),$(wildcard $(source)/*.$(ext)))) +ifeq ($(STATIC),1) +STATIC_OBJECTS::=$(addprefix $(OBJDIR)/static/,$(subst \,.,$(subst /,.,$(addsuffix .o,$(INTERNAL_SOURCES))))) +endif +ifeq ($(SHARED),1) +SHARED_OBJECTS::=$(addprefix $(OBJDIR)/shared/,$(subst \,.,$(subst /,.,$(addsuffix .o,$(INTERNAL_SOURCES))))) +endif +ALL_COMPILEFLAGS=$(COMPILER_FLAGS) $(INTERNAL_COMPILERFLAGS) +ALL_LINKFLAGS=$(INTERNAL_LINKFLAGS) $(LDFLAGS) + +#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 ($(SAVEFLAGS),1) +ifneq ($(subst -MF"$(DEPDIR)/",-MF"$(DEPDIR)/cflags-update",$(ALL_COMPILEFLAGS)),$(OLD_COMPILEFLAGS)) + $(file >$(CFLAGS_TMPFILE),$(ALL_COMPILEFLAGS)) +endif +endif +.PHONY: ldflags-update +ldflags-update: +ifeq ($(SAVEFLAGS),1) +ifneq ($(ALL_LINKFLAGS),$(OLD_LINKFLAGS)) + $(file >$(LDFLAGS_TMPFILE),$(ALL_LINKFLAGS)) +endif +endif +.PHONY: flags-update +flags-update: cflags-update ldflags-update + +#default target: run targets in PRE_TARGETS, then build the main library, then POST_TARGETS +.PHONY: all +all: flags-update + $(foreach target,$(PRE_TARGETS),@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(target)"$(\n)) +ifeq ($(SHARED),1) +ifeq ($(WINDOWS),1) + @$(MAKE) $(SUBMAKE_ARGUMENTS) "$(DLLOUT)" STATIC=0 +else #windows + @$(MAKE) $(SUBMAKE_ARGUMENTS) "$(INTERNAL_SHARED_LIBRARY)" STATIC=0 +endif #windows +endif #shared +ifeq ($(STATIC),1) + @$(MAKE) $(SUBMAKE_ARGUMENTS) "$(INTERNAL_STATIC_LIBRARY)" SHARED=0 +endif #static + $(foreach target,$(POST_TARGETS),@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(target)"$(\n)) + +ifeq ($(WINDOWS),1) +#target for windows shared library +$(DLLOUT): $(SHARED_OBJECTS) $(LDFLAGS_TMPFILE) + $(COMPILER) -shared -o "$(DLLOUT)" $(SHARED_OBJECTS) -Wl,--out-implib,"lib$(MAIN_LIBRARY).a" $(SHARED_LIBRARY_FLAGS) $(ALL_LINKFLAGS) $(LDLIBS) +else #windows + +#target for *nix shared library +$(INTERNAL_SHARED_LIBRARY): $(SHARED_OBJECTS) $(LDFLAGS_TMPFILE) + $(COMPILER) -shared -o "$@" $(SHARED_OBJECTS) $(SHARED_LIBRARY_FLAGS) $(ALL_LINKFLAGS) $(LDLIBS) +endif #windows + +#target for static library +$(INTERNAL_STATIC_LIBRARY): $(STATIC_OBJECTS) + $(AR) rcs "$@" $^ + $(RANLIB) "$@" + + +#Called in POST_TARGETS when RELEASE=1 +.PHONY: do_strip +do_strip: +ifeq ($(SHARED),1) + $(STRIP) --strip-debug "$(INTERNAL_SHARED_LIBRARY)" +endif +ifeq ($(STATIC),1) + $(STRIP) --strip-debug "$(INTERNAL_STATIC_LIBRARY)" +endif + +#Object target recipe +define GENERATE_STATIC_OBJECTS +$$(OBJDIR)/static/$(subst \,.,$(subst /,.,$(1))).o: $(1) $(CFLAGS_TMPFILE) + $$(COMPILER) $$(ALL_COMPILEFLAGS) "$$<" -o "$$@" +endef +define GENERATE_SHARED_OBJECTS +$$(OBJDIR)/shared/$(subst \,.,$(subst /,.,$(1))).o: $(1) $(CFLAGS_TMPFILE) + $$(COMPILER) $$(ALL_COMPILEFLAGS) "$$<" -o "$$@" +endef + + +#Create targets for object files +ifeq ($(STATIC),1) +$(foreach src,$(INTERNAL_SOURCES),$(eval $(call GENERATE_STATIC_OBJECTS,$(src)))) +endif +ifeq ($(SHARED),1) +$(foreach src,$(INTERNAL_SOURCES),$(eval $(call GENERATE_SHARED_OBJECTS,$(src)))) +endif +$(SHARED_OBJECTS): | $(OBJDIR)/shared $(DEPDIR) +$(STATIC_OBJECTS): | $(OBJDIR)/static $(DEPDIR) + +$(OBJDIR): + $(call mkdir,"$@") +$(DEPDIR): + $(call mkdir,"$@") +$(OBJDIR)/static: $(OBJDIR) + $(call mkdir,"$@") +$(OBJDIR)/shared: $(OBJDIR) + $(call mkdir,"$@") + + +.PHONY: clean +clean: + $(foreach target,$(CLEAN_TARGETS),@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(target)"$(\n)) + $(call rmdir,"$(OBJDIR)") + $(call rmdir,"$(DEPDIR)") + $(call rm,"lib$(MAIN_LIBRARY).so") + $(call rm,"lib$(MAIN_LIBRARY).a") + $(call rm,"$(DLLOUT)") +ifeq ($(SAVEFLAGS),1) + $(call rm,"$(CFLAGS_TMPFILE)") + $(call rm,"$(LDFLAGS_TMPFILE)") +endif + +#header file dep tracking +-include $(wildcard $(DEPDIR)/*.d) + diff --git a/makefile.recursive b/makefile.recursive new file mode 100644 index 0000000..b0e47b7 --- /dev/null +++ b/makefile.recursive @@ -0,0 +1,206 @@ +#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 2018-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 +LIBDIRS::=lib +INCLUDE_DIRS::=include +CFLAGS::=-std=c18 -Wall -pedantic -Wextra +CXXFLAGS::=-std=c++17 -Wall -pedantic -Wextra +EXT::=cpp +LANG::=$(EXT) +MAIN_EXECUTABLE::=tester +PRE_TARGETS::= +POST_TARGETS::= +CLEAN_TARGETS::= +RELEASE?=0 +MEMCHK?=0 +SAVEFLAGS?=1 + +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 +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 ($(SAVEFLAGS),1) + CFLAGS_TMPFILE::=.cflags.tmp + OLD_COMPILEFLAGS::=$(file <$(CFLAGS_TMPFILE)) + LDFLAGS_TMPFILE::=.ldflags.tmp + OLD_LINKFLAGS::=$(file <$(LDFLAGS_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,$@))" +INTERNAL_LINKFLAGS=$(foreach dir,$(LIBDIRS),-L"$(dir)") +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) +ALL_LINKFLAGS=$(INTERNAL_LINKFLAGS) $(LDFLAGS) + +#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 ($(SAVEFLAGS),1) +ifneq ($(subst -MF"$(DEPDIR)/",-MF"$(DEPDIR)/cflags-update",$(ALL_COMPILEFLAGS)),$(OLD_COMPILEFLAGS)) + $(file >$(CFLAGS_TMPFILE),$(ALL_COMPILEFLAGS)) +endif +endif +.PHONY: ldflags-update +ldflags-update: +ifeq ($(SAVEFLAGS),1) +ifneq ($(ALL_LINKFLAGS),$(OLD_LINKFLAGS)) + $(file >$(LDFLAGS_TMPFILE),$(ALL_LINKFLAGS)) +endif +endif +.PHONY: flags-update +flags-update: cflags-update ldflags-update + +#default target: run targets in PRE_TARGETS, then the main executable, then POST_TARGETS +.PHONY: all +all: flags-update + $(foreach target,$(PRE_TARGETS),@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(target)"$(\n)) + @$(MAKE) $(SUBMAKE_ARGUMENTS) "$(MAIN_EXECUTABLE)" + $(foreach target,$(POST_TARGETS),@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(target)"$(\n)) + +#Link executable +$(MAIN_EXECUTABLE): $(OBJECTS) $(LDFLAGS_TMPFILE) + $(COMPILER) $(OBJECTS) -o "$(basename $@)" $(ALL_LINKFLAGS) $(LDLIBS) +ifeq ($(RELEASE),1) + $(STRIP) --strip-all "$@" +endif + +#Object target recipe +define GENERATE_OBJECTS +$$(OBJDIR)/$(subst \,.,$(subst /,.,$(1))).%.o: $(1)/% $(CFLAGS_TMPFILE) + $$(COMPILER) $$(ALL_COMPILEFLAGS) "$$<" -o "$$@" +endef +define GENERATE_INDIVIDUAL_OBJECTS +$$(OBJDIR)/$(subst \,.,$(subst /,.,$(1))).o: $(1) $(CFLAGS_TMPFILE) + $$(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 ($(SAVEFLAGS),1) + $(call rm,"$(CFLAGS_TMPFILE)") + $(call rm,"$(LDFLAGS_TMPFILE)") +endif + +#header file dep tracking +-include $(wildcard $(DEPDIR)/*.d)