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

This commit is contained in:
rexy712 2020-03-20 12:52:41 -07:00
parent 9f03069ebe
commit 8e7fb0433b
4 changed files with 587 additions and 124 deletions

View File

@ -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

View File

@ -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

264
makefile.reclib Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
#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)

206
makefile.recursive Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
#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)