Created
March 25, 2013 04:00
-
-
Save spott/5234842 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
##### | |
# | |
# Dynamic Makefile for C++11 Projects. | |
# Recursively builds all files in a project and its test suite. | |
# | |
# Standard build targets are: | |
# - (none): all | |
# - all: testing | |
# - primary: build primary targets | |
# - testing: build testing targets | |
# - run: build and link primary targets, execute primary binary | |
# - test: build and link testing targets, execute testing binary | |
# - clean: remove objects created from primary and testing builds | |
# - remove remove main objects and executables from primary and testing links | |
# and perform a clean | |
# | |
# Build modes can be speficified on the command-line (mode=XXXX): | |
# - debug: debug symbols, minor optimizations, defines DEBUG | |
# - release: massive optimizations, defines NDEBUG | |
# - profile: debug and profiling symbols, safe optimizations, defines NDEBUG | |
# - default: set to value of DEFAULT_BUILD_MODE | |
# | |
# Variables expected to be edited (and their default values): | |
# - LIBRARIES | |
# - INCLUDES | |
# - DEFINES | |
# - WARNINGS (all extra) | |
# - CXXFLAGS (--std=c++11 -pipe) | |
# - LXXFLAGS | |
# | |
# Oher variables that can be changed (and their default values): | |
# - SOURCE_DIR (src) | |
# - OBJECT_DIR (obj) | |
# - PRIMARY_DIR (project) | |
# - TESTING_DIR (testing) | |
# - DEFAULT_BUILD_MODE (debug) | |
# | |
# Requires separate project and testing directories and mains: | |
# |- ./ | |
# |- Makefile | |
# |- project/ | |
# |- main.cpp | |
# |- src/ | |
# |- ... project files and directories | |
# |- testing/ | |
# |- main.cpp | |
# |- src/ | |
# |- ... testing files and directories | |
# | |
##### | |
.PHONY: all run test primary testing \ | |
prepare prepare_primary prepare_testing \ | |
build build_primary build_testing \ | |
link link_primary link_testing \ | |
clean clean_primary clean_testing \ | |
remove remove_primary remove_testing | |
.DEFAULT_GOAL: all | |
### | |
# TARGETS | |
### | |
all: testing | |
primary: build_primary | |
testing: build_testing | |
### | |
# PATHS | |
### | |
# Common | |
SOURCE_DIR = src | |
OBJECT_DIR = obj | |
# Primary | |
PRIMARY_DIR = project | |
PRIMARY_SOURCE_DIR = $(PRIMARY_DIR)/$(SOURCE_DIR) | |
PRIMARY_OBJECT_DIR = $(PRIMARY_DIR)/$(OBJECT_DIR) | |
PRIMARY_SOURCE_SUB_DIRS = $(shell find $(PRIMARY_SOURCE_DIR) -type d) | |
PRIMARY_OBJECT_SUB_DIRS = \ | |
$(patsubst $(PRIMARY_SOURCE_DIR)%,$(PRIMARY_OBJECT_DIR)%,$(PRIMARY_SOURCE_SUB_DIRS)) | |
# Testing | |
TESTING_DIR = testing | |
TESTING_SOURCE_DIR = $(TESTING_DIR)/$(SOURCE_DIR) | |
TESTING_OBJECT_DIR = $(TESTING_DIR)/$(OBJECT_DIR) | |
TESTING_SOURCE_SUB_DIRS = $(shell find $(TESTING_SOURCE_DIR) -type d) | |
TESTING_OBJECT_SUB_DIRS = \ | |
$(patsubst $(TESTING_SOURCE_DIR)%,$(TESTING_OBJECT_DIR)%,$(TESTING_SOURCE_SUB_DIRS)) | |
### | |
# FILES | |
### | |
# Primary | |
PRIMARY_SOURCE_FILES = $(shell find $(PRIMARY_SOURCE_DIR) -name "*.cpp") | |
PRIMARY_HEADER_FILES = $(shell find $(PRIMARY_SOURCE_DIR) -name "*.hpp") | |
PRIMARY_OBJECT_FILES = \ | |
$(patsubst $(PRIMARY_SOURCE_DIR)/%.o,$(PRIMARY_OBJECT_DIR)/%.o,$(PRIMARY_SOURCE_FILES:.cpp=.o)) | |
PRIMARY_SOURCE_MAIN = $(PRIMARY_DIR)/main.cpp | |
PRIMARY_OBJECT_MAIN = $(OBJECT_DIR)/$(patsubst %.cpp,%.o,$(PRIMARY_SOURCE_MAIN)) | |
PRIMARY_EXEC = $(shell basename `pwd`) | |
# Testing | |
TESTING_SOURCE_FILES = $(shell find $(TESTING_SOURCE_DIR) -name "*.cpp") | |
TESTING_HEADER_FILES = $(shell find $(TESTING_SOURCE_DIR) -name "*.hpp") | |
TESTING_OBJECT_FILES = \ | |
$(patsubst $(TESTING_SOURCE_DIR)/%.o,$(TESTING_OBJECT_DIR)/%.o,$(TESTING_SOURCE_FILES:.cpp=.o)) | |
TESTING_SOURCE_MAIN = $(TESTING_DIR)/main.cpp | |
TESTING_OBJECT_MAIN = $(OBJECT_DIR)/$(patsubst %.cpp,%.o,$(TESTING_SOURCE_MAIN)) | |
TESTING_EXEC = $(PRIMARY_EXEC)_test | |
### | |
# VARIABLES | |
### | |
# Common | |
LIBRARIES = | |
INCLUDES = | |
DEFINES = | |
WARNINGS = all extra | |
CXX = g++ | |
CXXFLAGS = --std=c++11 -pipe | |
LXX = g++ | |
LXXFLAGS = | |
# Target-specific | |
MODE ?= default | |
BUILD_MODE = $(shell echo $(MODE) | tr '[:upper:]' '[:lower:]') | |
DEFAULT_BUILD_MODE = debug | |
ifeq ($(BUILD_MODE),default) | |
BUILD_MODE = $(DEFAULT_BUILD_MODE) | |
endif | |
ifeq ($(BUILD_MODE),debug) | |
CXXFLAGS += -g -O | |
DEFINES += DEBUG | |
else | |
ifeq ($(BUILD_MODE),release) | |
CXXFLAGS += -Ofast | |
DEFINES += NDEBUG | |
else | |
ifeq ($(BUILD_MODE),profile) | |
CXXFLAGS += -g -pg -Og | |
LXXFLAGS += -pg | |
DEFINES += NDEBUG | |
else | |
$(warning Unrecognized build mode: $(BUILD_MODE)) | |
endif | |
endif | |
endif | |
# Primary | |
PRIMARY_LIBRARIES = $(LIBRARIES) | |
PRIMARY_INCLUDES = $(INCLUDES) | |
PRIMARY_DEFINES = $(DEFINES) | |
PRIMARY_WARNINGS = $(WARNINGS) | |
PRIMARY_CXXFLAGS = $(CXXFLAGS) $(foreach d,$(PRIMARY_DEFINES),-D$d) \ | |
$(foreach d,$(PRIMARY_WARNINGS),-W$d) $(foreach d,$(PRIMARY_INCLUDES),-I$d) | |
PRIMARY_LXXFLAGS = | |
# Testing | |
TESTING_LIBRARIES = $(LIBRARIES) | |
TESTING_INCLUDES = $(INCLUDES) | |
TESTING_DEFINES = $(DEFINES) | |
TESTING_WARNINGS = $(WARNINGS) | |
TESTING_CXXFLAGS = $(CXXFLAGS) $(foreach d,$(TESTING_DEFINES),-D$d) \ | |
$(foreach d,$(TESTING_WARNINGS),-W$d) $(foreach d,$(TESTING_INCLUDES),-I$d) | |
TESTING_LXXFLAGS = | |
### | |
# TARGETS | |
### | |
# Common | |
build: build_primary build_testing | |
link: link_primary link_testing | |
clean: clean_primary clean_test | |
remove: remove_primary remove_test | |
rm -rf $(OBJECT_DIR) | |
# Primary | |
$(PRIMARY_OBJECT_DIR)/%.o: $(PRIMARY_SOURCE_DIR)/%.cpp | |
$(CXX) $(PRIMARY_CXXFLAGS) -c -o $@ $< | |
$(PRIMARY_OBJECT_MAIN): $(PRIMARY_SOURCE_MAIN) | |
$(CXX) $(PRIMARY_CXXFLAGS) -c -o $@ $< | |
prepare_primary: | |
@echo " --------" | |
@echo "| creating primary build directories..." | |
@echo " --------" | |
mkdir -p $(PRIMARY_OBJECT_SUB_DIRS) $(OBJECT_DIR)/$(PRIMARY_DIR) | |
declare_primary_build: | |
@echo " --------" | |
@echo "| building primary object files..." | |
@echo " --------" | |
build_primary: prepare_primary declare_primary_build $(PRIMARY_OBJECT_FILES) | |
link_primary: $(PRIMARY_EXEC) | |
$(PRIMARY_EXEC): build_primary $(PRIMARY_OBJECT_MAIN) | |
@echo " --------" | |
@echo "| linking primary executable..." | |
@echo " --------" | |
$(LXX) $(LXXFLAGS) -o $@ $(PRIMARY_OBJECT_FILES) $(PRIMARY_OBJECT_MAIN) \ | |
$(foreach l,$(PRIMARY_LIBRARIES),-l$l) | |
run: link_primary | |
@echo " --------" | |
@echo "| running primary executable..." | |
@echo " --------" | |
./$(PRIMARY_EXEC) | |
clean_primary: | |
@echo " --------" | |
@echo "| cleaning primary build..." | |
@echo " --------" | |
rm -f $(PRIMARY_OBJECTS) | |
rm -rf $(PRIMARY_OBJECT_SUB_DIRS) | |
remove_primary: clean_primary | |
@echo " --------" | |
@echo "| removing primary executable..." | |
@echo " --------" | |
rm -f $(PRIMARY_OBJECT_MAIN) $(PRIMARY_EXEC) | |
rm -rf $(OBJECT_DIR)/$(PRIMARY_DIR) | |
# Testing | |
$(TESTING_OBJECT_DIR)/%.o: $(TESTING_SOURCE_DIR)/%.cpp | |
$(CXX) $(TESTING_CXXFLAGS) -c -o $@ $< | |
$(TESTING_OBJECT_MAIN): $(TESTING_SOURCE_MAIN) | |
$(CXX) $(TESTING_CXXFLAGS) -c -o $@ $< | |
prepare_testing: | |
@echo " --------" | |
@echo "| creating testing build directories..." | |
@echo " --------" | |
mkdir -p $(TESTING_OBJECT_SUB_DIRS) $(OBJECT_DIR)/$(TESTING_DIR) | |
declare_testing_build: | |
@echo " --------" | |
@echo "| building testing object files..." | |
@echo " --------" | |
build_testing: build_primary prepare_testing declare_testing_build $(TESTING_OBJECT_FILES) | |
link_testing: $(TESTING_EXEC) | |
$(TESTING_EXEC): build_testing $(TESTING_OBJECT_MAIN) | |
@echo " --------" | |
@echo "| linking testing executable..." | |
@echo " --------" | |
$(LXX) $(LXXFLAGS) -o $@ $(PRIMARY_OBJECT_FILES) $(TESTING_OBJECT_FILES) \ | |
$(TESTING_OBJECT_MAIN) $(foreach l,$(TESTING_LIBRARIES),-l$l) | |
test: link_testing | |
@echo " --------" | |
@echo "| running testing executable..." | |
@echo " --------" | |
./$(TESTING_EXEC) | |
clean_test: | |
@echo " --------" | |
@echo "| cleaning testing build..." | |
@echo " --------" | |
rm -f $(TESTING_OBJECTS) $(TESTING_OBJECT_MAIN) | |
rm -rf $(TESTING_OBJECT_SUB_DIRS) | |
remove_test: clean_test | |
@echo " --------" | |
@echo "| removing testing executable..." | |
@echo " --------" | |
rm -f $(TESTING_OBJECT_MAIN) $(TESTING_EXEC) | |
rm -rf $(OBJECT_DIR)/$(TESTING_DIR) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment