Skip to content

Instantly share code, notes, and snippets.

@a9QrX3Lu
Last active June 15, 2021 11:27
Show Gist options
  • Select an option

  • Save a9QrX3Lu/dff42af6fd4546469cc2bd06070cdd0b to your computer and use it in GitHub Desktop.

Select an option

Save a9QrX3Lu/dff42af6fd4546469cc2bd06070cdd0b to your computer and use it in GitHub Desktop.
Common makefile
#usage: include Makefile.common at the end of your Makefile
# no builtin rules/vars (CC, CXX, etc. are still defined but will be empty)
MAKEFLAGS += -r -R
HDR = $(addsuffix .h,$(MODULES) $(HEADERS))
SRC = $(addsuffix .c,$(MODULES) $(SOURCES))
ASM = $(addsuffix .S,$(ASSMBLY))
OBJ = $(addsuffix .o,$(MODULES) $(SOURCES) $(ASSEMBLY))
DEP = Makefile.common Makefile $(HDR) $(EXTERNDEP) $(EXTERNSRC)
BIN = $(addsuffix .out,$(TARGETS))
DIS = $(addsuffix .dis,$(TARGETS))
# clang:
# EXTRA="-Rpass=loop-vectorize" # IDs loops that were successfully V-ed
# EXTRA="-Rpass-missed=loop-vectorize" # IDs loops that failed V
# EXTRA="-Rpass-analysis=loop-vectorize" # IDs the statements that caused V to fail
# EXTRA="-Rpass=\ *" # remarks for all passes
# other passes: https://llvm.org/docs/Passes.html
O ?= rg
# predefined OPT: make O={rg,r,0g,3g,p,0s,3s,cov,mc,hc,wn,stk}
ifeq ($O,rg) # make O=rg
OPT ?= -DNDEBUG -g3 -O3 -flto -fno-stack-protector
else ifeq ($O,r) # make O=r (for release)
OPT ?= -DNDEBUG -O3 -flto -fno-stack-protector
else ifeq ($O,ns) # make O=ns (no signal handlers)
OPT ?= -DNDEBUG -O3 -flto -fno-stack-protector -DNOSIGNAL
else ifeq ($O,0g) # make O=0g
OPT ?= -g3 -O0 -fno-inline
else ifeq ($O,2g) # make O=2g
OPT ?= -g3 -O2
else ifeq ($O,3g) # make O=3g
OPT ?= -g3 -O3 -flto -fno-inline
else ifeq ($O,p) # make O=p (profiling: rg+noinline)
OPT ?= -DNDEBUG -g3 -O3 -flto -fno-stack-protector -fno-inline
else ifeq ($O,0s) # make O=0s (address sanitizer)
OPT ?= -g3 -O0 -fno-inline -fsanitize=address -fno-omit-frame-pointer -DHEAPCHECKING
else ifeq ($O,3s) # make O=3s (address sanitizer)
OPT ?= -g3 -O3 -fno-inline -fsanitize=address -fno-omit-frame-pointer -DHEAPCHECKING
else ifeq ($O,t) # make O=0t (thread sanitizer)
OPT ?= -g3 -O1 -fno-inline -fsanitize=thread -fno-stack-protector
else ifeq ($O,cov) # make O=cov (for gcov)
OPT ?= -g3 -DNDEBUG -O0 --coverage
CCC = gcc
else ifeq ($O,mc) # make O=mc (for valgrind memcheck)
OPT ?= -g3 -O1 -fno-inline -DHEAPCHECKING
ARCH ?= broadwell
else ifeq ($O,hc) # make O=hc (for gperftools heapcheck)
OPT ?= -g3 -O1 -fno-inline
LIB += tcmalloc
else ifeq ($O,wn) # more warning
OPT ?= -g3 -O3 -Wvla -Wformat=2 -Wconversion -Wstrict-prototypes -Wmissing-prototypes
else ifeq ($O,stk) # check stack usage with gcc
OPT ?= -g3 -O3 -DNDEBUG -fstack-usage
CCC = gcc
endif
# malloc: g:glibc, t:tcmalloc, j:jemalloc
M ?= g
ifeq ($M,t)
LIB += tcmalloc
FLG += -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free
else ifeq ($M,j)
LIB += jemalloc
endif
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
CHECK_S := -D__linux__
LIB += rt
else ifeq ($(UNAME_S),FreeBSD)
CHECK_S := -D__FreeBSD__
FLG += -I/usr/local/include -L/usr/local/lib
LIB += rt
LIB += execinfo
TPUT := /usr/local/bin/tput
else ifeq ($(UNAME_S),Darwin)
CHECK_S := -D__APPLE__ -D__MACH__
# do nothing
else
$(error "Supported Platforms: Linux, FreeBSD, Darwin")
endif
TPUT ?= tput
CCC ?= clang
CSTD = -std=gnu18
XCC ?= clang++
XSTD = -std=gnu++17
UNAME_M := $(shell uname -m)
ifeq ($(UNAME_M),aarch64) # "native" does not work for clang@aarch64
CHECK_M := -D__aarch64__
ARCH ?= armv8-a+crc
else ifeq ($(UNAME_M),arm64) # "native" does not work for clang@aarch64
CHECK_M := -D__aarch64__
ARCH ?= armv8-a+crc
else ifeq ($(UNAME_M),x86_64)
CHECK_M := -D__x86_64__
ARCH ?= native
else ifeq ($(UNAME_M),amd64) # freebsd
CHECK_M := -D__x86_64__
ARCH ?= native
else
$(error "Supported Platforms: aarch64, x86_64")
endif
TUNE ?= native
NBI += memcpy memmove memcmp
# minimal requirement on x86_64: -march=nehalem
# minimal requirement on aarch64: -march=armv8-a+crc
FLG += -march=$(ARCH) -mtune=$(TUNE)
FLG += -pthread -Wall -Wextra -Wshadow #-Weverything
FLG += $(addprefix -fno-builtin-,$(NBI))
FLG += $(OPT)
ifneq ($(shell $(CCC) --version 2>/dev/null | grep clang),)
FLG += -ferror-limit=3
CCCTYPE := clang
else ifneq ($(shell $(CCC) --version 2>/dev/null | grep gcc),)
FLG += -fmax-errors=3
FLG += -Wno-unknown-pragmas
CCCTYPE := gcc
else
$(error "Supported Compilers: clang, gcc")
endif
ifeq ($(CCCTYPE),clang)
CCINST = /usr/lib/clang/$(shell $(CCC) --version 2>/dev/null | awk '/^clang/ { print $$3 }')
CCINC = $(CCINST)/include
else ifeq ($(CCCTYPE),gcc)
CCINST = /usr/lib/gcc/$(shell $(CCC) -dumpmachine)/$(shell $(CCC) -dumpversion)
CCINC = $(CCINST)/include $(CCINST)/include-fixed
endif
CCINC = /usr/include /usr/local/include
ifneq ($(shell find $(CCINC) -name backtrace-supported.h 2>/dev/null),)
LIB += backtrace
FLG += -DBACKTRACE
endif
ifneq ($(shell find $(CCINC) -name liburing.h 2>/dev/null),)
LIB += uring
FLG += -DLIBURING
endif
uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))
magentatxt := $(shell $(TPUT) setaf 5)
greentxt := $(shell $(TPUT) setaf 2)
bluetxt := $(shell $(TPUT) setaf 4)
normaltxt := $(shell $(TPUT) sgr0)
.PHONY : bin dis clean cleanx check tags
bin : $(BIN)
dis : $(DIS) bin
.DEFAULT_GOAL = bin
.SECONDEXPANSION:
ifeq ($(J),o)
# DANGER. Don't use unless it works!
# build from .o files but target-specific flags are missing in %.o : %.x
%.out : %.o $(OBJ) $$(addsuffix .o,$$(SRC-$$@) $$(MOD-$$@) $$(ASM-$$@))
$(eval ALLFLG := $(CSTD) $(EXTRA) $(FLG) $(FLG-$*) $(FLG-$*.o) $(FLG-$@) -rdynamic)
$(eval ALLLIB := $(addprefix -l,$(LIB) $(LIB-$@)))
$(CCC) $(ALLFLG) -o $@ $^ $(ALLLIB)
#
else # default: all-in-one command
%.out : %.c $(SRC) $(ASM) $(DEP) $$(DEP-$$@) $$(addsuffix .c,$$(SRC-$$@) $$(MOD-$$@)) $$(addsuffix .h,$$(HDR-$$@) $$(MOD-$$@)) $$(addsuffix .S,$$(ASM-$$@))
$(eval ALLSRC := $(SRC) $(addsuffix .c,$(SRC-$@) $(MOD-$@)) $(ASM) $(addsuffix .S,$(ASM-$@)))
$(eval UNIQSRC := $(call uniq,$(ALLSRC)))
$(eval ALLFLG := $(CSTD) $(EXTRA) $(FLG) $(FLG-$@) -rdynamic)
$(eval ALLLIB := $(addprefix -l,$(LIB) $(LIB-$@)))
@printf '$(bluetxt)$@$(magentatxt) <= $(greentxt)$< $(UNIQSRC)$(normaltxt)\n'
$(CCC) $(ALLFLG) -o $@ $< $(UNIQSRC) $(ALLLIB)
#
endif
%.dis : %.out
objdump -SlwtC $< 1>$@ 2>/dev/null
%.o : %.cc $(DEP) $$(DEP-$$@) $$(addsuffix .h,$$(HDR-$$@) $$(MOD-$$@))
$(XCC) $(XSTD) $(EXTRA) $(FLG) $(FLG-$*) $(FLG-$@) -o $@ -c $<
%.o : %.c $(DEP) $$(DEP-$$@) $$(addsuffix .h,$$(HDR-$$@) $$(MOD-$$@))
$(CCC) $(CSTD) $(EXTRA) $(FLG) $(FLG-$*) $(FLG-$@) -o $@ -c $<
%.o : %.S $(DEP) $$(DEP-$$@) $$(addsuffix .h,$$(HDR-$$@) $$(MOD-$$@))
$(CCC) $(CSTD) $(EXTRA) $(FLG) $(FLG-$*) $(FLG-$@) -o $@ -c $<
%.s : %.c $(DEP) $$(DEP-$$@) $$(addsuffix .h,$$(HDR-$$@) $$(MOD-$$@))
$(CCC) $(CSTD) $(EXTRA) $(FLG) $(FLG-$*) $(FLG-$*.o) -S -o $@ -c $<
clean :
rm -rf *.out *.dis *.o *.so *.gcda *.gcno *.gcov *.dSYM
cleanx : clean
rm -rf $(EXTERNDEP) $(EXTERNSRC)
check :
cppcheck $(addprefix -I ,$(CCINC)) \
-q $(CHECK_M) $(CHECK_S) -DNDEBUG -U__cplusplus \
--std=c11 --language=c --platform=unix64 \
--enable=warning,style,performance,portability,information --inline-suppr .
tags :
ctags -R . /usr/include /usr/local/include $(CCINC)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment