Make, again

It's been a very long time since I've written my first post about the way I use make. Now that I'm reading it again, I realize I don't even use Makefiles anymore. Since few years now, I use Tox, too much Python development I guess.

I started (again) learning C programming, I had to write a simple Makefile for being able to easily and quickly build, install, remove executable. The following is what I have, heavily commented for future self:

# shell to use
SHELL := /bin/sh

# name of the executable file
EXECUTABLE := prog

# absolute path to a bin directory (assuming is is on the PATH)
# we want to launch the new command easily
BIN_DIR = $(shell echo $${HOME})/bin

# build & source directories
BUILD_DIR ?= build
SRC_DIRS ?= src

# source files are all c files inside the source directory
SRCS := $(shell find $(SRC_DIRS) -name *.c)

# for each '.c' file, there will be an '.o' file located inside the build directory
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)

# we find the dependency files by finding all the object files
# and replacing '.o' extension by '.d' extension
DEPS := $(OBJS:.o=.d)

# all the directories inside source directory
INC_DIRS := $(shell find $(SRC_DIRS) -type d)

# include them all during the compilation process
INC_FLAGS := $(addprefix -I,$(INC_DIRS))

# flag to use when compiling
# -g
# -Wall
# -Wfatal-errors
# -pedantic
# -Wextra
# -std=c99
# -MMD -MP

CFLAGS ?= $(INC_FLAGS) -g -Wall -Wfatal-errors -pedantic -Wextra -std=c99 -MMD -MP

# to install, we need the executable
# installing is equal to move the executable inside a folder that is in the PATH
install: $(BUILD_DIR)/$(EXECUTABLE)
	@echo "installing..."
	$(CP) $(BUILD_DIR)/$(EXECUTABLE) $(BIN_DIR)

# to build the executable, we need the object file
$(BUILD_DIR)/$(EXECUTABLE): $(OBJS)
	@echo "building executable file..."
	$(CC) $(OBJS) -o $@ $(LDFLAGS)

# to build the object file we need source file
# also, clean all the previously built files
$(BUILD_DIR)/%.c.o: %.c clean
	@echo "building object files..."
	@$(MKDIR_P) $(dir $@)
	$(CC) $(CFLAGS) -c $< -o $@

clean:
	@echo "deleting old build..."
	@$(RM) -r $(BUILD_DIR)

# suspend reading the current makefile 
# and read one or more other makefiles before continuing
-include $(DEPS)

# aliasing shell commands
MKDIR_P ?= mkdir -p
CP ?= cp -r

# A phony target is one that is not really the name of a file
# it is just a name for a recipe to be executed
.PHONY: clean install

After all those years reading and writing tox.ini files, I won't deny, reading and writing makefiles feels like... esoterism? At least, I'm ready to compile my first C program.

It's been a long time.