mirror of
https://github.com/oxen-io/lokinet.git
synced 2024-11-03 23:15:52 +00:00
423 lines
13 KiB
PHP
423 lines
13 KiB
PHP
# This Makefile is intended to be included by another Makefile. It contains a
|
|
# number of common functions, variables, recipes. Ideally the calling Makefile
|
|
# will only need to define targets for that project.
|
|
#
|
|
# Features:
|
|
# - Shadow building
|
|
# - Auto dependency generation
|
|
# - debug target uses address sanitizer when available (GCC >= 4.8.0),
|
|
# and undefined behavior sanitizer (GCC >=4.9.0)
|
|
# - coloured error messages when available (GCC >=4.9.0)
|
|
# - pre-configured targets for cleaning .o files, insure leftovers
|
|
# - targets for callgrind, memcheck, insure, profiling and code coverage
|
|
#
|
|
# Organization
|
|
# - Supporting functions
|
|
# - Definitions of the variables used by this makefile (ex., CXX, WARNINGS)
|
|
# - Predefined configurations of variables (ex., DEBUG)
|
|
# - File type targets (ex., .o)
|
|
# - Named targets (ex., profile)
|
|
# - Inclusion of auto-dependencies
|
|
#
|
|
# TODO Profile guided optimization
|
|
# TODO Precompiled headers
|
|
# TODO Static analysis
|
|
# TODO Clang support
|
|
# TODO -fsanitize=integer for clang
|
|
# TODO -fsanitize=thread
|
|
# TODO ubsan prints messages to the stderr; does not terminate
|
|
# TODO dynamic/static libs
|
|
# TODO _GLIBCXX_DEBUG and _GLIBCXX_DEBUG_PEDANTIC
|
|
# TODO split up makefile into common functions, variables, configurations, recipes
|
|
# TODO -B option for TOOLCHAIN
|
|
# TODO CONFIG=RELEASE (strip, for example)
|
|
# TODO Different debug levels
|
|
# TODO CONFIG=HARDENED including some of the following options
|
|
# TODO -fstack-protector-strong?
|
|
# TODO -Wformat-security
|
|
# TODO -pie -fPIE
|
|
# TODO full relro -Wl,-z,relro,-z,now
|
|
# TODO -pipe
|
|
# TODO -flto
|
|
|
|
# Shadow building ==============================================================
|
|
# This gets the directory of the calling Makefile (and, presumably, where the
|
|
# source code resides
|
|
|
|
# Functions ====================================================================
|
|
gccversion = $(shell $(CXX) -dumpversion | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/')
|
|
gcc48 = $(shell expr $(gccversion) \>= 40800)
|
|
gcc49 = $(shell expr $(gccversion) \>= 40900)
|
|
gcc51 = $(shell expr $(gccversion) \>= 50100)
|
|
|
|
# Convert a word to lowercase
|
|
lower = $(shell echo $(1) | tr '[:upper:]' '[:lower:]')
|
|
|
|
# Convert a word to uppercase
|
|
upper = $(shell echo $(1) | tr '[:lower:]' '[:upper:]')
|
|
|
|
# Variables ====================================================================
|
|
#
|
|
# The basic variables that this makefile uses
|
|
|
|
# Toolchain --------------------------------------------------------------------
|
|
# Which programs to use during compilation
|
|
|
|
# Path to a different toolchain (ex., ~/bin/gcc-4.9.0)
|
|
TOOLCHAIN =
|
|
|
|
ifndef TOOLCHAIN
|
|
# C++ compiler
|
|
CXX = g++
|
|
|
|
# Archive (.a) program
|
|
AR = ar
|
|
|
|
# Linker
|
|
LD = $(CXX)
|
|
|
|
PROFILER = gprof
|
|
else
|
|
# Use a particular set of tools
|
|
CXX = $(TOOLCHAIN)/bin/g++ -B$(TOOLCHAIN)/bin/
|
|
AR = $(TOOLCHAIN)/bin/ar
|
|
LD = $(CXX)
|
|
PROFILER = $(TOOLCHAIN)/bin/gprof
|
|
endif
|
|
|
|
# Misc
|
|
VALGRIND = valgrind
|
|
|
|
# Compiler flags ---------------------------------------------------------------
|
|
# Arguments to the toolchain programs
|
|
|
|
# Which version of C++ to compile for
|
|
STANDARD = -ansi -pedantic
|
|
|
|
# Optimization flags
|
|
OPTIMIZATION = -O2
|
|
|
|
# Architecture flags
|
|
TARGET_ARCH =
|
|
|
|
# Warnings
|
|
WARNINGS = -Wall -Wsign-compare -Wconversion -Wpointer-arith \
|
|
-Winit-self -Wcast-qual -Wredundant-decls -Wcast-align -Wwrite-strings \
|
|
-Wno-long-long -Woverloaded-virtual -Wformat -Wno-unknown-pragmas \
|
|
-Wnon-virtual-dtor -Wno-c++0x-compat
|
|
# -Wold-style-cast
|
|
|
|
ifeq "$(gcc51)" "1"
|
|
#WARNINGS += -Wsuggest-attribute=const -Wsuggest-attribute=pure
|
|
endif
|
|
|
|
# Level of debugging information to provide
|
|
DEBUGGING = -g
|
|
|
|
# Machine independent options
|
|
#-fno-nonansi-builtins
|
|
OPTIONS = -fuse-cxa-atexit -ffor-scope
|
|
|
|
ifeq "$(gcc49)" "1"
|
|
OPTIONS += -fdiagnostics-color
|
|
endif
|
|
|
|
# Flags to use when compiling C++ source into object files
|
|
CXXFLAGS = $(STANDARD) $(DEBUGGING) $(OPTIMIZATION) $(WARNINGS) $(OPTIONS) $(TARGET_ARCH)
|
|
|
|
# Directories to search for includes
|
|
INCLUDE =
|
|
|
|
# Any macros that can be defined on the command line
|
|
DEFINES = -D_FORTIFY_SOURCE=1
|
|
|
|
# Preprocessor flags
|
|
CPPFLAGS = $(INCLUDE) $(DEFINES)
|
|
|
|
# How to build an archive
|
|
ARFLAGS = crs
|
|
|
|
# Linker flags
|
|
LDFLAGS =
|
|
LDLIBS =
|
|
|
|
ifdef TOOLCHAIN
|
|
# Statically link the GCC and
|
|
LDFLAGS += -static-libgcc -static-libstdc++
|
|
|
|
# Dynamic linking
|
|
#LDFLAGS += -Wl,-rpath -Wl,$(TOOLCHAIN)/lib
|
|
#LDLIBS = -L$(TOOLCHAIN)/lib
|
|
endif
|
|
|
|
# Printing =====================================================================
|
|
# If this is not empty, print messages
|
|
VERBOSE =
|
|
|
|
# Predefined configurations ====================================================
|
|
# Combinations of the OPTIMIZATION, etc.
|
|
ifdef CONFIG
|
|
UCONFIG := $(call upper,$(CONFIG))
|
|
|
|
# Fast -------------------------------------------------------------------------
|
|
# A faster build, primarily for testing
|
|
ifeq "$(UCONFIG)" "FAST"
|
|
OPTIMIZATION = -O0
|
|
endif
|
|
|
|
# Tune -------------------------------------------------------------------------
|
|
# Heavily optimized for a fast application
|
|
ifeq "$(UCONFIG)" "TUNE"
|
|
ifeq "$(gcc48)" "1"
|
|
TARGET_ARCH = -march=native
|
|
endif
|
|
OPTIMIZATION = -O3 -mtune=native
|
|
endif
|
|
|
|
# Debug ------------------------------------------------------------------------
|
|
# Programmer is tracking a bug
|
|
ifeq "$(UCONFIG)" "DEBUG"
|
|
|
|
# Set additional warnings and flags
|
|
WARNINGS += -Wshadow -Wfloat-equal
|
|
ifeq "$(gcc51)" "1"
|
|
WARNINGS += -Wstrict-overflow=5
|
|
endif
|
|
|
|
DEBUGGING = -ggdb3 -fno-omit-frame-pointer -fno-default-inline -fno-inline -fno-merge-constants -ffloat-store
|
|
# -fno-elide-constructors
|
|
|
|
# Set the optimization level
|
|
ifeq "$(gcc48)" "1"
|
|
OPTIMIZATION = -Og
|
|
else
|
|
OPTIMIZATION = -O0
|
|
endif
|
|
|
|
# Turn on address sanitizer
|
|
ifeq "$(gcc48)" "1"
|
|
DEBUGGING += -fsanitize=address
|
|
LDFLAGS += -fsanitize=address -static-libasan
|
|
endif
|
|
|
|
# Turn on undefined behavior sanitizer and leak sanitizer
|
|
ifeq "$(gcc49)" "1"
|
|
DEBUGGING += -fsanitize=undefined -fsanitize=leak
|
|
LDFLAGS += -fsanitize=undefined -fsanitize=leak -static-libubsan -static-liblsan
|
|
endif
|
|
endif
|
|
|
|
# Profile ----------------------------------------------------------------------
|
|
# Programmer wants profile information
|
|
ifeq "$(UCONFIG)" "PROFILE"
|
|
OPTIMIZATION = -O2 -pg
|
|
LDFLAGS += -pg
|
|
endif
|
|
|
|
# Coverage ---------------------------------------------------------------------
|
|
# Programmer wants code coverage information
|
|
ifeq "$(UCONFIG)" "COVERAGE"
|
|
DEBUGGING += --coverage -fno-elide-constructors
|
|
LDFLAGS += --coverage
|
|
OPTIMIZATION = -O0
|
|
endif
|
|
|
|
# Insure -----------------------------------------------------------------------
|
|
# Programmer wants to run insure
|
|
ifeq "$(UCONFIG)" "INSURE"
|
|
CXX = insure
|
|
LDLIBS += -lstdc++
|
|
OPTIMIZATION = -O0
|
|
endif
|
|
endif
|
|
|
|
# Targets ======================================================================
|
|
.PHONY: no_default_goal depend clean_insure clean_objects clean_profile clean_depend distclean coverage profile memcheck callgrind cachegrind help help_common examples
|
|
|
|
no_default_goal:
|
|
$(error "The including Makefile hasn't specified a default goal. It should.")
|
|
|
|
# Dependency generation --------------------------------------------------------
|
|
DEPDIR := .deps
|
|
|
|
# Build object files with automatic dependency generation
|
|
# TODO maybe use LINK.cpp from 'make -p'
|
|
%.o: %.cpp
|
|
@mkdir -p $(@D)/$(DEPDIR)
|
|
ifeq ($(VERBOSE),)
|
|
@echo [CXX] $@
|
|
@$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -MMD -MP -MF $(@D)/$(DEPDIR)/$(*F).d -o $@ $<
|
|
else
|
|
$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -MMD -MP -MF $(@D)/$(DEPDIR)/$(*F).d -o $@ $<
|
|
endif
|
|
|
|
%.a:
|
|
ifeq ($(VERBOSE),)
|
|
@echo [AR] $@
|
|
@$(AR) $(ARFLAGS) $@ $^ > /dev/null
|
|
else
|
|
$(AR) $(ARFLAGS) $@ $^ > /dev/null
|
|
endif
|
|
|
|
# A script for combining .a's. Dependency list for the mri should be
|
|
# subdirectories containing static libs. Name of the output library
|
|
# is inferred from the mri name (abc.mri produces libabc.a)
|
|
%.mri:
|
|
@echo 'CREATE $(patsubst %.mri,lib%.a,$@)' > $@
|
|
@for dir in $^; do echo ADDLIB $$dir >> $@; done
|
|
@echo 'SAVE' >> $@
|
|
|
|
|
|
# TODO dynamic libs
|
|
# %.so: CXXFLAGS += -fPIC
|
|
# %.so: LDFLAGS := -shared
|
|
# %.so:
|
|
# $(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@
|
|
# optionally add -Wl,-soname,$(SONAME)
|
|
|
|
# TODO java classes
|
|
# %.class: %.java
|
|
# $(JC) -cp . $<
|
|
|
|
# Code coverage ----------------------------------------------------------------
|
|
coverage:
|
|
ifdef COVERAGE_OUT
|
|
@TMPFILE=`mktemp`; lcov --capture --directory . --output-file $$TMPFILE; genhtml $$TMPFILE --output-directory $(COVERAGE_OUT); $(RM) $$TMPFILE
|
|
else
|
|
$(error You have not set COVERAGE_OUT)
|
|
endif
|
|
|
|
# Profiling --------------------------------------------------------------------
|
|
profile:
|
|
ifdef PROFILE_TARGET
|
|
$(PROFILE_TARGET) $(PROFILE_TARGET_ARGS)
|
|
ifdef PROFILE_OUT
|
|
@$(PROFILER) -c $(PROFILE_TARGET) > $(PROFILE_OUT)
|
|
else
|
|
$(error You have not specified PROFILE_OUT)
|
|
endif
|
|
else
|
|
$(error You have not specified PROFILE_TARGET)
|
|
endif
|
|
|
|
# Memcheck ---------------------------------------------------------------------
|
|
# User should set MEMCHECK_TARGET, MEMCHECK_TARGET_ARGS, and a recipe like:
|
|
# memcheck: $(MEMCHECK_TARGET)
|
|
memcheck:
|
|
$(VALGRIND) --tool=memcheck -v --read-var-info=yes --track-origins=yes --show-reachable=yes --leak-check=full --read-inline-info=yes --keep-stacktraces=alloc-and-free $(VALGRIND_TARGET) $(VALGRIND_TARGET_ARGS) 2> $(MEMCHECK_OUT)
|
|
|
|
# Callgrind --------------------------------------------------------------------
|
|
# User should set CALLGRIND_TARGET, CALLGRIND_TARGET_ARGS, and a recipe like:
|
|
# callgrind: $(CALLGRIND_TARGET)
|
|
callgrind:
|
|
$(VALGRIND) --tool=callgrind $(VALGRIND_TARGET) $(VALGRIND_TARGET_ARGS)
|
|
|
|
cachegrind:
|
|
$(VALGRIND) --tool=cachegrind --branch-sim=yes $(VALGRIND_TARGET) $(VALGRIND_TARGET_ARGS)
|
|
|
|
# Clean targets ----------------------------------------------------------------
|
|
# remove all .o files
|
|
clean_objects:
|
|
ifeq ($(VERBOSE),)
|
|
@find -name '*.o' -exec $(RM) '{}' \;
|
|
else
|
|
find -name '*.o' -exec $(RM) '{}' \;
|
|
endif
|
|
|
|
# remove all files left by insure
|
|
clean_insure:
|
|
ifeq ($(VERBOSE),)
|
|
@find -name '*.tcl' -exec $(RM) '{}' \;
|
|
@$(RM) tca.map tca.log
|
|
else
|
|
find -name '*.tcl' -exec $(RM) '{}' \;
|
|
$(RM) tca.map tca.log
|
|
endif
|
|
|
|
# remove all files left by gprof
|
|
clean_profile:
|
|
ifeq ($(VERBOSE),)
|
|
@$(RM) profile
|
|
@find \( -name '*.gcda' -o -name '*.gcno' \) -exec $(RM) '{}' \;
|
|
else
|
|
$(RM) profile
|
|
find \( -name '*.gcda' -o -name '*.gcno' \) -exec $(RM) '{}' \;
|
|
endif
|
|
|
|
clean_depend:
|
|
ifeq ($(VERBOSE),)
|
|
@find -depth -name $(DEPDIR) -type d -exec $(RM) -r '{}' \;
|
|
else
|
|
find -depth -name $(DEPDIR) -type d -exec $(RM) -r '{}' \;
|
|
endif
|
|
|
|
depend: clean clean_depend
|
|
|
|
distclean: depend
|
|
|
|
# Documentation ----------------------------------------------------------------
|
|
help_common:
|
|
@echo "==================================================================="
|
|
@echo "Here are some standard Makefile variables and their defaults:"
|
|
@echo " CXX ($(CXX))"
|
|
@echo " CPPFLAGS ($(CPPFLAGS))"
|
|
@echo " LDFLAGS ($(LDFLAGS))"
|
|
@echo " LDLIBS ($(LDLIBS))"
|
|
@echo " AR ($(AR))"
|
|
@echo " ARFLAGS ($(ARFLAGS))"
|
|
@echo
|
|
@echo "You can set the TOOLCHAIN variable to use a different compiler,"
|
|
@echo "linker, profiler. Ex., (~/bin/gcc-4.9.0)"
|
|
@echo
|
|
@echo "The CXXFLAGS variable is comprised of a number of other variables:"
|
|
@echo " STANDARD ($(STANDARD))"
|
|
@echo " DEBUGGING ($(DEBUGGING))"
|
|
@echo " OPTIMIZATION ($(OPTIMIZATION))"
|
|
@echo " WARNINGS ($(WARNINGS))"
|
|
@echo " TARGET_ARCH ($(TARGET_ARCH))"
|
|
@echo
|
|
@echo "For convenience, several preconfigured options are available by"
|
|
@echo "setting the CONFIG variale:"
|
|
@echo " DEBUG - Turns on debugging info; turns down optimization; enables"
|
|
@echo " address sanitizer, etc. if available"
|
|
@echo " PROFILE - Keeps optimization for release build; adds debugging"
|
|
@echo " and gprof flags"
|
|
@echo " COVERAGE - Don't inline functions"
|
|
@echo " INSURE - Build the target with the insure compiler"
|
|
@echo " TUNE - High optimization level; CPU-specific instructions"
|
|
@echo " FAST - A fast compilation with low optimization level"
|
|
@echo
|
|
@echo "==================================================================="
|
|
@echo "Here are some special targets and variables that affect them"
|
|
@echo
|
|
@echo " profile - First build a target with CONFIG=PROFILE and run it."
|
|
@echo " PROFILE_TARGET the name of the program to profile"
|
|
@echo " (default: $(PROFILE_TARGET))"
|
|
@echo " PROFILE_TARGET_ARGS arguments to the program to profile"
|
|
@echo " (default: $(PROFILE_TARGET_ARGS))"
|
|
@echo " PROFILE_OUT the file to place the profile data in"
|
|
@echo " (default: $(PROFILE_OUT))"
|
|
@echo " PROFILER Path to profiler"
|
|
@echo " (default: $(PROFILER))"
|
|
@echo " coverage - First build a target with CONFIG=COVERAGE and run it."
|
|
@echo " COVERAGE_OUT specifies where to put the resulting web pages"
|
|
@echo " (default: $(COVERAGE_OUT))"
|
|
@echo
|
|
@echo " memcheck - Run memcheck for VALGRIND_TARGET, testing memory access"
|
|
@echo " callgrind - Run callgrind for VALGRIND_TARGET, testing performance"
|
|
@echo " cachegrind - Run cachegrind for VALGRIND_TARGET, testing cache"
|
|
@echo " VALGRIND_TARGET The program to check"
|
|
@echo " (default: $(VALGRIND_TARGET))"
|
|
@echo " VALGRIND_TARGET_ARGS The arguments to VALGRIND_TARGET"
|
|
@echo " (default: $(VALGRIND_TARGET_ARGS))"
|
|
@echo " MEMCHECK_OUT Where to put the memcheck results"
|
|
@echo " (default: $(MEMCHECK_OUT))"
|
|
@echo "==================================================================="
|
|
|
|
help: help_common
|
|
|
|
# ==============================================================================
|
|
# Include dependencies which are stored as .d files in the $(DEPDIR) directories
|
|
# TODO prefer -wholename to -path, but old version of find doesn't have wholename
|
|
-include $(shell find -path '*/$(DEPDIR)/*.d')
|