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)