Skip to content

Instantly share code, notes, and snippets.

@alekfrohlich
Last active January 15, 2020 02:35
Show Gist options
  • Save alekfrohlich/0a48d5f1a4f06646256e9829701a67da to your computer and use it in GitHub Desktop.
Save alekfrohlich/0a48d5f1a4f06646256e9829701a67da to your computer and use it in GitHub Desktop.
Example Makefile and Makedefs. Features automatic dependency generation and builds out-of-source. The Makefile was written to accommodate C++ source code but it should be easy to adapt it to other compiled languages.
# Application.
APP_NAME := main
# Directories.
ROOT := $(abspath $(dir $(filter %Makedefs, $(MAKEFILE_LIST))))
SRC := $(ROOT)/src
INCLUDE := $(ROOT)/include
BUILD := $(ROOT)/build
# C++ Compiler and Flags.
CXX := g++
CXXFLAGS := -std=c++17 -I $(INCLUDE)
# Every rule that is not debug shall be compiled with release flags.
ifeq (, $(filter debug, $(MAKECMDGOALS)))
APP := $(APP_NAME).release
BUILD := $(ROOT)/build/release
CXXFLAGS += -O2
else
APP := $(APP_NAME).debug
BUILD := $(ROOT)/build/debug
CXXFLAGS += -g
endif
# Source and Build Directory Trees.
SRC_DIR_TREE := $(shell find $(SRC) -type d)
BUILD_DIR_TREE := $(subst $(SRC),$(BUILD),$(SRC_DIR_TREE))
# VPATH is similar to bash's PATH in that it allows make to find files
# in other directories without having to change directory. GCC does not
# know that, so we include the VPATH'ed source files.
INCLUDES := $(foreach dir, $(SRC_DIR_TREE), $(addprefix -I, $(dir)))
VPATH := $(SRC_DIR_TREE)
# C++ Source Code.
CXX_SRC := $(foreach dir,$(SRC_DIR_TREE),$(wildcard $(dir)/*.cc))
# Object Files and Dependencies.
OBJS := $(subst $(SRC),$(BUILD),$(CXX_SRC:.cc=.o))
DEPS := $(OBJS:.o=.d)
# Rules That do Not Depend on Source Files.
OTHER_RULES := clean veryclean
# Example Makefile
SHELL := /bin/bash
include Makedefs.mk
.PHONY: release debug clean directories veryclean
# Build options: [release|debug]
__common:
$(MAKE) directories
$(MAKE) $(APP)
release: __common
debug: __common
$(APP): $(OBJS)
$(CXX) $< -o $@
directories:
mkdir -p $(BUILD_DIR_TREE)
# Function to generate Makefile rules for the given source code. Double dollar
# sign ($$) provides double expansion so that CXXFLAGS and INCLUDES are not
# evaluated when calling generate-rules. This allows variables to be evaluated
# only when the target's recipe is run.
define generate-rules
$(1)/%.o: %.cc
$(CXX) $$(CXXFLAGS) -c $$(INCLUDES) -o $$@ $$< -MMD
endef
# Generate rules for each build directory.
$(foreach targetdir, $(BUILD_DIR_TREE), \
$(eval $(call generate-rules, $(targetdir))))
# Avoid including dependencies when they're not needed.
ifeq (, $(filter $(OTHER_RULES),$(MAKECMDGOALS)))
-include $(DEPS)
endif
# Clean binary, object files and dependencies.
clean:
@find . -depth -type f \( -name "*.o" -o -name "*.d" \) -delete
@rm -f $(APP_NAME).release
# Also deletes build directory.
veryclean: clean
@rm -rf $(BUILD)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment