#
# Generic Makefile rules that can be included in any Makefile
# Written by John Ryland
# (C) Copyright 2015
#
# Example usage:
#
# # Example Makefile
# TARGET = app_name
# SOURCES = main.cpp \
# tests.cpp \
# file.c
#
# # Some optional values that can be omitted
# CONFIG = [release|profile|debug] [application|library] [dynamic|static] [qt]
# CFLAGS = -Os
# DEFINES = DEBUG OS_LINUX
# INCLUDE_PATHS = ./include
# LIBRARY_PATHS = ./lib
# LIBRARIES = utils
# OBJECTS_DIR = .obj
# TARGET_DIR = ./bin
# VERSION_MAJOR = 1
# VERSION_MINOR = 0
#
# # The important part, including the generic set of Makefile rules
# include ../Makefile.inc
#
#
# Linking config options
#
LINKING += $(findstring dynamic,$(CONFIG))
LINKING += $(findstring static,$(CONFIG))
LINKING := $(LINKING: =)
#
# Optimization config options
#
OPTIMIZATION += $(findstring release,$(CONFIG))
OPTIMIZATION += $(findstring profile,$(CONFIG))
OPTIMIZATION += $(findstring debug,$(CONFIG))
OPTIMIZATION := $(OPTIMIZATION: =)
#
# Template config options
#
TEMPLATE += $(findstring application,$(CONFIG))
TEMPLATE += $(findstring library,$(CONFIG))
TEMPLATE := $(TEMPLATE: =)
#
# Framework config options (currently only Qt)
#
FRAMEWORK += $(findstring qt,$(CONFIG))
FRAMEWORK := $(FRAMEWORK: =)
#
# Setup defaults
#
ifeq ($(TARGET_DIR: =),)
TARGET_DIR=.
endif
ifeq ($(OBJECTS_DIR: =),)
OBJECTS_DIR=.obj
endif
ifeq ($(LINKING: =),)
LINKING=dynamic
endif
ifeq ($(OPTIMIZATION: =),)
OPTIMIZATION=debug
endif
ifeq ($(TEMPLATE: =), )
TEMPLATE=application
endif
TARGET_SUFFIX=
ifeq ($(OPTIMIZATION: =),profile)
TARGET_SUFFIX=_p
endif
ifeq ($(OPTIMIZATION: =),debug)
TARGET_SUFFIX=_d
endif
ifeq ($(VERSION_MAJOR: =),)
VERSION_MAJOR=1
endif
ifeq ($(VERSION_MINOR: =),)
VERSION_MINOR=0
endif
#
# Framework settings
#
ifeq ($(FRAMEWORK),qt)
DEFINES += QT_WEBKITWIDGETS_LIB QT_QUICK_LIB QT_OPENGL_LIB QT_PRINTSUPPORT_LIB \
QT_WEBKIT_LIB QT_QML_LIB QT_LOCATION_LIB QT_WIDGETS_LIB QT_NETWORK_LIB \
QT_POSITIONING_LIB QT_SENSORS_LIB QT_GUI_LIB QT_CORE_LIB QT_QML_DEBUG \
QT_DECLARATIVE_DEBUG _REENTRANT
QTDIR = /usr/include/qt5
QMAKEDIR = /usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++-64
INCLUDE_PATHS += $(QMAKEDIR) $(QTDIR) $(QTDIR)/QtWebKitWidgets \
$(QTDIR)/QtQuick $(QTDIR)/QtOpenGL $(QTDIR)/QtPrintSupport \
$(QTDIR)/QtWebKit $(QTDIR)/QtQml $(QTDIR)/QtLocation \
$(QTDIR)/QtWidgets $(QTDIR)/QtNetwork $(QTDIR)/QtPositioning \
$(QTDIR)/QtSensors $(QTDIR)/QtGui $(QTDIR)/QtCore
# LIBRARY_PATHS += /usr/lib/x86_64-linux-gnu
LIBRARIES += png z Qt5WebKitWidgets Qt5Quick Qt5OpenGL Qt5PrintSupport Qt5WebKit \
Qt5Qml Qt5Location Qt5Widgets Qt5Network Qt5Positioning Qt5Sensors \
Qt5Gui Qt5Core GL pthread
# Add the files we generate using moc to the sources
OBJECTS_PATH = $(OBJECTS_DIR)/$(OPTIMIZATION)/$(LINKING)
SOURCES += $(patsubst %.h,$(OBJECTS_PATH)/moc/%.cpp,$(HEADERS))
# SOURCES += $(foreach HEADER,$(HEADERS), $(OBJECTS_PATH)/$(dir $(HEADER))/moc_$(basename $(notdir $(HEADER))).cpp )
# SOURCES += $(foreach HEADER,$(HEADERS), $(OBJECTS_PATH)/moc/moc_$(basename $(notdir $(HEADER))).cpp )
# SOURCES += $(patsubst %.ui,$(OBJECTS_PATH)/ui/%.cpp,$(FORMS))
# SOURCES += $(patsubst %.qrc,$(OBJECTS_PATH)/rc/%.cpp,$(RESOURCES))
endif
#
# Flags
#
CFLAGS_debug := -DDEBUG -g -O0 $(CFLAGS_debug)
CFLAGS_profile := -DNDEBUG -pg -O5 $(CFLAGS_profile)
CFLAGS_release := -DNDEBUG -O5 $(CFLAGS_release)
CFLAGS_static := -DSTATIC -static $(CFLAGS_static)
CFLAGS_dynamic := -DDYNAMIC -fPIC $(CFLAGS_dynamic)
override CFLAGS := $(patsubst %,-I%,$(INCLUDE_PATHS)) $(patsubst %,-D%,$(DEFINES)) $(CFLAGS_$(OPTIMIZATION)) $(CFLAGS_$(LINKING)) $(CFLAGS)
override CXXFLAGS := $(CFLAGS) -std=c++11 $(CXXFLAGS)
LFLAGS_dynamic := $(LFLAGS_dynamic)
LFLAGS_static := -static $(LFLAGS_static)
override LFLAGS := $(patsubst %,-L%,$(LIBRARY_PATHS)) $(patsubst %,-l%,$(LIBRARIES)) $(LFLAGS)
#
# Commands
#
CC = $(TOOLCHAIN_PREFIX)gcc
CXX = $(TOOLCHAIN_PREFIX)g++
LINK = $(TOOLCHAIN_PREFIX)g++
MKDIR = mkdir -p
RM = rm -f
MOC = moc
UIC = uic
RCC = rcc
#
# Targets
#
OBJECTS_PATH = $(OBJECTS_DIR)/$(OPTIMIZATION)/$(LINKING)
COMPILED_OBJS = $(patsubst %.c,$(OBJECTS_PATH)/%.o,$(filter %.c,$(SOURCES)))
COMPILED_OBJS += $(patsubst %.cpp,$(OBJECTS_PATH)/%.o,$(filter %.cpp,$(SOURCES)))
OBJECTS += $(COMPILED_OBJS)
DEPENDS = $(OBJECTS_PATH)/.depend
LIBRARY = $(TARGET_DIR)/lib$(TARGET)$(TARGET_SUFFIX)
LIBRARY_static = $(LIBRARY).a
LIBRARY_dynamic = $(LIBRARY).so
TARGET_library = $(LIBRARY_$(LINKING))
TARGET_application = $(TARGET_DIR)/$(TARGET)$(TARGET_SUFFIX)
TARGET_BINARY = $(TARGET_$(TEMPLATE))
#
# Rules
#
all: $(TARGET_BINARY)
$(TARGET_application): $(OBJECTS)
@$(MKDIR) $(dir $@)
$(LINK) $(LFLAGS_$(LINKING)) -o $@ $^ $(CXXFLAGS) $(LFLAGS)
$(LIBRARY_static): $(OBJECTS)
@$(MKDIR) $(dir $@)
ar rcs $@ $^ $(LFLAGS)
$(LIBRARY_dynamic): $(OBJECTS)
@$(MKDIR) $(dir $@)
$(LINK) $(LFLAGS_$(LINKING)) -shared -Wl,-soname,$(@).$(VERSION_MAJOR) -o $@.$(VERSION_MAJOR).$(VERSION_MINOR) $^ $(CXXFLAGS) $(LFLAGS)
ln -s $@.$(VERSION_MAJOR).$(VERSION_MINOR) $@.$(VERSION_MAJOR)
ln -s $@.$(VERSION_MAJOR) $@
# To work out dependancies, a simple non-gcc specific way is just depend on everything in the include dir:
# DEPENDS = $(patsubst %,$(INCLUDE_PATH)/%,$(HEADERS))
# But not every source depends on everything in the include dir, and it may not properly capture other dependancies.
# This solution is better, but GCC specific
$(DEPENDS): $(SOURCES)
@$(MKDIR) $(dir $@)
@$(CXX) $(CXXFLAGS) -MM $(SOURCES) | sed 's,^\(.*\.o\),$(OBJECTS_PATH)\/\1,' > $@
# $(foreach RES,$(RESOURCES),{ echo -n "$(patsubst %.qrc,$(OBJECTS_PATH)/rc/%.cpp,$(RES)): " ; $(RCC) --list $(RES) | tr '\n' ' ' ; } ' >> $@)
$(foreach HEADER,$(HEADERS), $(shell echo $(OBJECTS_PATH)/moc/moc_$(basename $(notdir $(HEADER))).cpp: $(HEADER) >> $@))
debug:
$(MAKE) OPTIMIZATION=debug
release:
$(MAKE) OPTIMIZATION=release
profile:
$(MAKE) OPTIMIZATION=profile
$(OBJECTS_PATH)/%.o: %.c $(DEPENDS)
@$(MKDIR) $(dir $@)
$(CC) -c -o $@ $< $(CFLAGS)
$(OBJECTS_PATH)/%.o: %.cpp $(DEPENDS)
@$(MKDIR) $(dir $@)
$(CXX) -c -o $@ $< $(CXXFLAGS)
# Qt rules
$(OBJECTS_PATH)/moc/%.cpp: %.h
@$(MKDIR) $(dir $@)
$(MOC) $(patsubst %,-D%,$(DEFINES)) $(patsubst %,-I%,$(INCLUDE_PATHS)) $< -o $@
$(OBJECTS_PATH)/ui/%.cpp: %.ui
@$(MKDIR) $(dir $@)
$(UIC) $(patsubst %,-D%,$(DEFINES)) $(patsubst %,-I%,$(INCLUDE_PATHS)) $< -o $@
$(OBJECTS_PATH)/rc/%.cpp: %.qrc
@$(MKDIR) $(dir $@)
$(RCC) -name $< $< -o $@
FAKE_TARGETS = debug release profile clean verify help all info null
MAKE_TARGETS = $(MAKE) -rpn null | sed -n -e '/^$$/ { n ; /^[^ .\#][^ ]*:/ { s/:.*$$// ; p ; } ; }'
REAL_TARGETS = $(MAKE_TARGETS) | sort | uniq | grep -E -v $(shell echo $(FAKE_TARGETS) | sed 's/ /\\|/g')
null:
verify: test-report.txt
@echo ""
@echo " Test Results:"
@echo " PASS count: "`grep -c "PASS" test-report.txt`
@echo " FAIL count: "`grep -c "FAIL" test-report.txt`
@echo ""
help:
@echo ""
@echo " Usage:"
@echo " $(MAKE) [target]"
@echo ""
@echo " Targets:"
@echo " "`$(MAKE_TARGETS)`
@echo ""
info:
@echo ""
@echo " Info:"
@echo " $(LINKING) linking"
@echo " $(OPTIMIZATION) optimization"
@echo " $(TEMPLATE) template"
@echo " $(FRAMEWORK) framework"
@echo " target: $(TARGET_BINARY)"
@echo ""
@echo " Make targets:"
@echo " "`$(MAKE_TARGETS)`
@echo " Real targets:"
@echo " "`$(REAL_TARGETS)`
@echo " Fake targets:"
@echo " $(FAKE_TARGETS)"
@echo ""
clean:
@echo $(RM) `$(REAL_TARGETS)` $(DEPENDS) $(COMPILED_OBJS) core
@$(RM) `$(REAL_TARGETS)` $(DEPENDS) $(COMPILED_OBJS) core
.PHONY: $(FAKE_TARGETS)
#
# Dependancies
#
-include $(DEPENDS)