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 my executables. The following is a Bash script I've created to bootstrap small C projects:
#!/bin/bash
GIT=`which git`
MSG="initial commit from $USER on $(date)"
CURRENT_DIRECTORY=`pwd`
PROJECT_NAME=$1
EXECUTABLE_NAME="${2:-kli}"
if [[ -z "${PROJECT_NAME}" ]]; then
echo "Please add the name of the project"
exit
fi
if [[ -d "${CURRENT_DIRECTORY}/${PROJECT_NAME}" ]]; then
echo "The folder exists. Choose another name"
exit
fi
# project tree
mkdir -p "${CURRENT_DIRECTORY}/${PROJECT_NAME}"/{build,src,docs,include,lib,tests,data}
# clang format config ???
clang-format --style=llvm -dump-config > "${CURRENT_DIRECTORY}/${PROJECT_NAME}"/.clang-format
# Makefile header
cat <<EOF >> "${CURRENT_DIRECTORY}/${PROJECT_NAME}"/Makefile
SHELL := /bin/sh
EXECUTABLE := $EXECUTABLE_NAME
EOF
# Makefile body
cat <<"EOF" >> "${CURRENT_DIRECTORY}/${PROJECT_NAME}"/Makefile
# https://matt.sh/howto-c
# where all bin will be moved for easy trying
BIN_DIR := $(shell echo $${HOME})/bin
# set build and source directories
BUILD_DIR := build
SRC_DIRS := src
LIBS := -lm -lpthread
# all source files are .c files under source directory
SRCS := $(shell find $(SRC_DIRS) -name *.c)
# all objects files are obtained from all the .c files in src directory
# and placed under build directory with the o extension
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
# deps are .d files, obtained from all the .o files in the build directory
DEPS := $(OBJS:.o=.d)
# directories to include are all the directories under src directory
INC_DIRS := $(shell find $(SRC_DIRS) -type d)
# add -I in front of each subdirectory under src directory
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
#
CFLAGS ?= $(INC_FLAGS) -g -Wall -Wfatal-errors -Wpedantic -Wextra -Werror -Wshadow -std=c11 -MMD -MP -march=native
install: $(BUILD_DIR)/$(EXECUTABLE) ## install prog
@echo "installing..."
$(CP) $(BUILD_DIR)/$(EXECUTABLE) $(BIN_DIR)
$(BUILD_DIR)/$(EXECUTABLE): $(OBJS) ## build executable
@echo "building executable file..."
$(CC) $(OBJS) -o $@ $(LDFLAGS) $(LIBS) # CC and LDFLAGS are predefined see make -p -f /dev/null
$(BUILD_DIR)/%.o: %.c clean ## build object files
@echo "building object files..."
@$(MKDIR_P) $(dir $@)
# $< evaluates to the first "prerequisite", $@ evaluates to the "target"
$(CC) $(CFLAGS) -c $< -o $@
format:
@echo "reformatting..."
find . -iname *.h -o -iname *.c | xargs clang-format -style=file -i -fallback-style=none
clean: ## delete build files
@echo "deleting old build..."
@$(RM) -r $(BUILD_DIR)
@$(RM) -r $(BIN_DIR)/$(EXECUTABLE)
# acts like include except that there is no error (not even a warning) if DEPS does not exists, sinclude is another name
-include $(DEPS)
# Meh :\
MKDIR_P ?= mkdir -p
CP ?= cp -r
.PHONY: clean install help format
EOF
# main source file
cat <<EOF > "${CURRENT_DIRECTORY}/${PROJECT_NAME}"/src/main.c
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
int main (int argc, char **argv) {
printf("Hello World.\n");
exit(EXIT_SUCCESS);
}
EOF
# git it
cd ${PROJECT_NAME}
${GIT} init -q .
${GIT} add --all .
${GIT} commit -m "$MSG"