C++ project makefile

Version 2:

################################################################################
#
# Author: Tancredi-Paul Grozav <paul@grozav.info>
#
# Makefile for a C++ project. Run "make addsubdir DIR=src" to add a source folder named src
# Please keep this header if you copy this file 🙂
#
################################################################################

# ========================- SETTINGS -========================
# Please give your build a name:
BUILD_NAME := tst1

# Comment or uncomment an option for BUILD_TYPE, OPTIMIZATION_TYPE, LINKING_TYPE:
#BUILD_TYPE := library# Uncomment this if you want to build a library out of your sources
BUILD_TYPE := executable# Uncomment this if you want to build an executable out of your sources

#OPTIMIZATION_TYPE := release# Uncomment this if you want to build a release vesion ( -O3 )
OPTIMIZATION_TYPE := debug# Uncomment this if you want to build a debug version ( -O0 -ggdb -g3 )

#LINKING_TYPE := static# Uncomment this if you want your build to have static linkage (built in dependencies)
LINKING_TYPE := dynamic# Uncomment this if you want your build to have dynamic linkage (load dependencies at runtime from LD_LIBRARY_PATH)

# Please specify the libraries and paths:
GLOBAL_INCLUDE_PATHS := # Where should the compiler search for source files (#include's)
LIBRARY_PATHS := # Where should the linker search for libraries
LIBS := # What libraries should be linked with this build

# Type here any arguments that you want to pass to your executable when running it
RUN_ARGUMENTS :=# Arguments passed to the executable when running: make run
# ======================- END SETTINGS -======================

#SOURCE_FILES_REGEX := .*.(cpp|CPP)# Accepted extensions for source files
all: $(BUILD_NAME)
#       @echo 'Building objects:$(OBJS)'


# Create the list of objects that need to be compiled
#$(eval OBJECTS += $(shell find .. -type f -regex "$(SOURCE_FILES_REGEX)" | awk '{print substr($$0,1,length($$0)-3)"o"}'))
#$(eval OBJECTS += $(shell find .. -type f -name "*.cpp" | awk '{print substr($$0,1,length($$0)-3)"o"}'))
$(eval OBJECTS += $(shell find .. -type f -name "*.cpp" | awk '{print substr($$0,2,length($$0)-3-1)"o"}'))

# create the dependency list - helps to recompile only what changed from last compile
$(eval -include $(shell find .. -type f -name "*.cpp" | awk '{print substr($$0,2,length($$0)-3-1)"d"}'))

# Link all objects into the final binary
$(BUILD_NAME): $(OBJECTS)
        @echo "Linking objects into $(BUILD_NAME) ..."
ifeq ($(BUILD_TYPE),executable)
ifeq ($(LINKING_TYPE),static) # Executable static
#       @g++ -o $(BUILD_NAME) $(OBJECTS) -Wl,-Bstatic $(LIBS) $(LIBRARY_PATHS)
        g++ -static -o $(BUILD_NAME) $(OBJECTS) $(LIBS) $(LIBRARY_PATHS)
else
ifeq ($(LINKING_TYPE),dynamic) # Executable dynamic
        @g++ -o $(BUILD_NAME) $(OBJECTS) -Wl,-Bdynamic $(LIBS) $(LIBRARY_PATHS)
else
        @echo "How do I link the objects using LINKING_TYPE=$(LINKING_TYPE) ?"
endif
endif
else
ifeq ($(BUILD_TYPE),library)
ifeq ($(LINKING_TYPE),static) # Library static
#       g++ -o $(BUILD_NAME) $(OBJECTS) -Wl,-Bstatic $(LIBS) $(LIBRARY_PATHS)
        ar -r $(BUILD_NAME) $(OBJECTS) $(LIBS)
else
ifeq ($(LINKING_TYPE),dynamic) # Library dynamic
        g++ -shared -o $(BUILD_NAME) $(OBJECTS) $(LIBS) $(LIBRARY_PATHS)
else
        @echo "How do I link the objects using LINKING_TYPE=$(LINKING_TYPE) ?"
endif
endif
else
        @echo "How do I link the objects as BUILD_TYPE=$(BUILD_TYPE) ?"
endif
endif

# Compile each source file
%.o:
        @echo "Compiling $@ ..."
        @if [ ! -d $$(dirname $@) ]; then mkdir -p $$(dirname $@); fi
ifeq ($(OPTIMIZATION_TYPE),debug)
        @g++ $(GLOBAL_INCLUDE_PATHS) -O0 -g3 -ggdb -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"$(shell echo "$@" | awk '{print substr($$0,1,length($$0)-1)"d"}')" -MT"$(shell echo "$@" | awk '{print substr($$0,1,length($$0)-1)"d"}')" -o "$@" "$(shell echo "$@" | awk '{print "../"substr($$0,1,length($$0)-1)"cpp"}')"
else
ifeq ($(OPTIMIZATION_TYPE),release)
        @g++ $(GLOBAL_INCLUDE_PATHS) -O3 -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"$(shell echo "$@" | awk '{print substr($$0,1,length($$0)-1)"d"}')" -MT"$(shell echo "$@" | awk '{print substr($$0,1,length($$0)-1)"d"}')" -o "$@" "$(shell echo "$@" | awk '{print "../"substr($$0,1,length($$0)-1)"cpp"}')"
else
        @echo "How do I compile in $(OPTIMIZATION_TYPE) mode?"
endif
endif

# Clean project target
clean:
        @echo "Cleaning project ..."
        @rm -Rf $(shell ls -l | grep -vw "makefile" | awk '{printf $$9" "}')

# Run executable target
run:
ifeq ($(BUILD_TYPE),executable)
        @echo "Running program ..."
        ./$(BUILD_NAME) $(RUN_ARGUMENTS)
else
        @echo "No need to run library $(BUILD_NAME)"
endif

.PHONY: clean all run

 

Version 1:

################################################################################
#
# Author: Tancredi-Paul Grozav <paul@grozav.info>
#
# Makefile for a C++ project. Run "make addsubdir DIR=src" to add a source folder named src
#
################################################################################

BUILD_NAME := some_decoder_dbg
#BUILD_TYPE := library# Uncomment this if you want to build a library out of your sources
BUILD_TYPE := executable# Uncomment this if you want to build an executable out of your sources

#OPTIMIZATION_TYPE := release# Uncomment this if you want to build a release vesion ( -O3 )
OPTIMIZATION_TYPE := debug# Uncomment this if you want to build a debug version ( -O0 -ggdb -g3 )

LINKING_TYPE := static# Uncomment this if you want your build to have static linkage (built in dependencies)
#LINKING_TYPE := dynamic# Uncomment this if you want your build to have dynamic linkage (load dependencies at runtime from LD_LIBRARY_PATH)

GLOBAL_INCLUDE_PATHS := -I/home/pgrozav/git/someLib# Where should the compiler search for source files (#include's)
LIBRARY_PATHS := -L/home/pgrozav/git/someLib/lib/DebugStatic# Where should the linker search for libraries
LIBS := -lliba_dbg -llibb_dbg# What libraries should be linked with this build

RUN_ARGS := -f file1.log -template template.xml# Arguments passed to the executable when running: make run

# OTHER variables
#ER_OBJS :=
#O_SRCS :=
CPP_SRCS :=
#C_UPPER_SRCS :=
#C_SRCS :=
#S_UPPER_SRCS :=
#OBJ_SRCS :=
#ASM_SRCS :=
#CXX_SRCS :=
#C++_SRCS :=
#CC_SRCS :=
OBJS :=
#C++_DEPS :=
#C_DEPS :=
#CC_DEPS :=
CPP_DEPS :=
#EXECUTABLES :=
#CXX_DEPS :=
#C_UPPER_DEPS :=

# All Target
ifdef BUILD_TYPE
all: $(BUILD_NAME)
#       @echo 'Building objects:$(OBJS)'
else
all:
        @echo 'Please specify one BUILD_TYPE'
endif

# Every subdirectory with source files must be described here
SUBDIRS :=
src

# All of the sources participating in the build are defined here. Please add a subdir.mk to each source folder describing it's content.
#-include subdir.mk
-include src/subdir.mk

ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(C++_DEPS)),)
-include $(C++_DEPS)
endif
ifneq ($(strip $(C_DEPS)),)
-include $(C_DEPS)
endif
ifneq ($(strip $(CC_DEPS)),)
-include $(CC_DEPS)
endif
ifneq ($(strip $(CPP_DEPS)),)
-include $(CPP_DEPS)
endif
ifneq ($(strip $(CXX_DEPS)),)
-include $(CXX_DEPS)
endif
ifneq ($(strip $(C_UPPER_DEPS)),)
-include $(C_UPPER_DEPS)
endif
endif

# All Target
#ifdef BUILD_TYPE
#all: $(BUILD_NAME)
#       @echo 'Building objects:$(OBJS)'
#else
#all:
#       @echo 'Please specify one BUILD_TYPE'
#endif

## Tool invocations
$(BUILD_NAME): $(OBJS) $(USER_OBJS)
        @echo 'Building target: $@ as $(BUILD_TYPE)'
ifeq ($(BUILD_TYPE),library)
# Build as Library
ifeq ($(LINKING_TYPE),static)
# Static
#       @echo 'Invoking: GCC Archiver'
        ar -r $(BUILD_NAME) $(OBJS) $(USER_OBJS) $(LIBS)
else
ifeq ($(LINKING_TYPE),dynamic)
# Dynamic
#       @echo 'Invoking: GCC C++ Linker'
        g++ -o $(BUILD_NAME) $(OBJS) $(USER_OBJS) $(LIBS) $(LIBRARY_PATHS)
else
        @echo 'Invalid linking type: $(LINKING_TYPE)'
endif
endif
else
ifeq ($(BUILD_TYPE),executable)
# Build as executable
#       @echo 'Invoking: GCC C++ Linker'
        g++ $(LIBRAY_PATHS) -o $(BUILD_NAME) $(OBJS) $(USER_OBJS) $(LIBS) $(LIBRARY_PATHS)
else
        @echo "Invalid build type: I don't know how to build: $(BUILD_TYPE)"
endif
endif
        @echo -e 'e[5me[92mFinished building target: $@e[39me[25m'





# clean target
clean:
        rm -Rf $(OBJS)$(C++_DEPS)$(C_DEPS)$(CC_DEPS)$(CPP_DEPS)$(EXECUTABLES)$(CXX_DEPS)$(C_UPPER_DEPS) $(BUILD_NAME)


# run target
run:
        @./$(BUILD_NAME) $(RUN_ARGS)



# Add all .cpp files to subdir.mk
addsubdir:
ifdef DIR
        @if [ ! -d $(DIR) ]; then mkdir $(DIR); fi
        @if [ -f ./$(DIR)/subdir.mk ]; then mv ./$(DIR)/subdir.mk ./$(DIR)/subdir.mk.bakup; fi
        @ls -la ../$(DIR)/*.cpp | awk 'BEGIN{ nrFiles=0; }function printFiles(variable){ print variable" += "; for(i=0;i<nrFiles;i++){ fileName=files[i]; if( variable == "OBJS" || variable == "CPP_DEPS" ) fileName=substr(fileName,2,length(fileName)-1) ; exten="cpp"; if(variable == "OBJS") exten="o"; if(variable == "CPP_DEPS") exten="d"; fileName=substr(fileName,1,length(fileName)-3)exten; printf fileName; if(i<nrFiles-1) print " "; else print ""; }}{ files[nrFiles++]=$$9; }END{ printFiles("CPP_SRCS"); print ""; printFiles("OBJS"); print ""; printFiles("CPP_DEPS"); print ""; }' > ./$(DIR)/subdir.mk
# Append compilation rules to the subdir.mk file
        @echo -ne "src/%.o: ../src/%.cppn
t@echo 'Building file: $$<'n
t@echo 'Invoking: GCC C++ Compiler'n
ifeq ($$(OPTIMIZATION_TYPE),debug)n
tg++ $$(GLOBAL_INCLUDE_PATHS) -O0 -g3 -ggdb -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"$$(@:%.o=%.d)" -MT"$$(@:%.o=%.d)" -o "$$@" "$$<"n
elsen
ifeq ($$(OPTIMIZATION_TYPE),release)n
tg++ $$(GLOBAL_INCLUDE_PATHS) -O3 -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"$$(@:%.o=%.d)" -MT"$$(@:%.o=%.d)" -o "$$@" "$$<"n
elsen
t@echo 'Invalid optimization type: '$$(OPTIMIZATION_TYPE)n
endifn
endifn
t@echo 'Finished building: $$<'n
t@echo ''
" >> ./$(DIR)/subdir.mk
        @echo 'Please add the folder $(DIR) to SUBDIRS := and -include $(DIR)/subdir.mk to makefile !'
else
        @echo "Please specify a DIR=src or something"
endif


.PHONY: all clean dependents
.SECONDARY: