
Make
- 377 installs
- 155 repo stars
- Updated June 27, 2026
- mohitmishra786/low-level-dev-skills
make is a low-level-dev-skills agent skill that teaches GNU Makefile patterns for C/C++ projects with phony targets, pattern rules, -MMD dependency tracking, and cross-compilation-friendly build entrypoints.
About
make is a skill under mohitmishra786/low-level-dev-skills/skills/build-systems/make/ that guides agents writing and debugging GNU Makefiles for C and C++ codebases. It provides a minimal correct Makefile with wildcard sources, build/%.o pattern rules, and automatic variables $@, $<, $^, then adds -MMD -MP dependency generation so header edits trigger rebuilds. The skill documents debug versus release BUILD flags, make -j$(nproc) parallel builds, install targets with PREFIX, multi-directory include patterns via module.mk files, and a seven-row common-errors table covering missing separators, circular dependencies, and full rebuilds. Developers reach for make when converting ad-hoc gcc shell scripts into maintainable native build entrypoints or diagnosing why make rebuilds everything every time.
- Incremental dependency rules
- Cross-compile toolchains
- Generated header ordering
- Parallel make -j usage
- CI recipe standardization
Make by the numbers
- 377 all-time installs (skills.sh)
- +29 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #311 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill makeAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 377 |
|---|---|
| repo stars | ★ 155 |
| Last updated | June 27, 2026 |
| Repository | mohitmishra786/low-level-dev-skills ↗ |
How do you write a Makefile for C projects?
Author Makefiles for native projects with correct dependency rules, incremental rebuilds, cross-compilation targets, and CI-friendly deterministic build entrypoints.
Who is it for?
Systems and native C/C++ developers replacing shell compile scripts with incremental GNU Make builds.
Skip if: Skip make for CMake-, Bazel-, or Meson-first projects—use the matching build-systems skill in the same repo.
When should I use this skill?
User asks for a Makefile, pattern rules, automatic variables, incremental C builds, or why make rebuilds everything.
What you get
Makefiles with phony targets, .d dependency files, incremental object builds, and documented gcc compile recipes.
- Makefile
- .d dependency files
- build artifacts
By the numbers
- Documents 7 common Make errors with causes and fixes
- Shows 5 core automatic variables: $@, $<, $^, $*, $(@D)
- Related skills in repo: cmake, ninja, gcc under skills/build-systems/
Files
GNU Make
Purpose
Guide agents through idiomatic Makefile patterns for C/C++ projects: phony targets, pattern rules, automatic dependency generation, and common build idioms.
Triggers
- "How do I write a Makefile for my C project?"
- "My Makefile rebuilds everything every time"
- "How do I add dependency tracking to Make?"
- "What does
$@,$<,$^mean?" - "I'm getting 'make: Nothing to be done for all'"
- "How do I convert my shell compile script to a Makefile?"
Workflow
1. Minimal correct Makefile for C
CC := gcc
CFLAGS := -std=c11 -Wall -Wextra -g -O2
LDFLAGS :=
LDLIBS :=
SRCS := $(wildcard src/*.c)
OBJS := $(SRCS:src/%.c=build/%.o)
TARGET := build/prog
.PHONY: all clean
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
build/%.o: src/%.c | build
$(CC) $(CFLAGS) -c -o $@ $<
build:
mkdir -p build
clean:
rm -rf buildAutomatic variables:
$@— target name$<— first prerequisite$^— all prerequisites (deduplicated)$*— stem (the%part in a pattern rule)$(@D)— directory part of$@
2. Automatic dependency generation
Without this, changing a header doesn't trigger a rebuild of .c files that include it.
CC := gcc
CFLAGS := -std=c11 -Wall -Wextra -g -O2
DEPFLAGS = -MMD -MP # -MMD: generate .d file; -MP: phony targets for headers
SRCS := $(wildcard src/*.c)
OBJS := $(SRCS:src/%.c=build/%.o)
DEPS := $(OBJS:.o=.d)
TARGET := build/prog
.PHONY: all clean
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
build/%.o: src/%.c | build
$(CC) $(CFLAGS) $(DEPFLAGS) -MF $(@:.o=.d) -c -o $@ $<
-include $(DEPS) # '-' ignores errors on first build (no .d files yet)
build:
mkdir -p build
clean:
rm -rf build3. Pattern rules cheatsheet
# Compile C
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
# Compile C++
%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
# Generate assembly
%.s: %.c
$(CC) $(CFLAGS) -S -o $@ $<
# Run a tool on each file
build/%.processed: src/%.raw | build
mytool $< > $@4. Common Make patterns
Debug and release builds
BUILD ?= release
ifeq ($(BUILD),debug)
CFLAGS += -g -Og -DDEBUG
else
CFLAGS += -O2 -DNDEBUG
endifUsage: make BUILD=debug
Parallel builds
make -j$(nproc) # use all CPUs
make -j4 # exactly 4 jobsAdd -Otarget (or -O) for ordered output: make -j$(nproc) -O
Verbose output
# In Makefile: suppress with @
build/%.o: src/%.c | build
@echo " CC $<"
@$(CC) $(CFLAGS) -c -o $@ $<Override silence: make V=1 if you guard with $(V):
Q := $(if $(V),,@)
build/%.o: src/%.c
$(Q)$(CC) $(CFLAGS) -c -o $@ $<Installing
PREFIX ?= /usr/local
install: $(TARGET)
install -d $(DESTDIR)$(PREFIX)/bin
install -m 0755 $(TARGET) $(DESTDIR)$(PREFIX)/bin/5. Multi-directory projects
For medium projects, avoid recursive make (fragile, slow). Use a flat Makefile that includes sub-makefiles:
# project/Makefile
include lib/module.mk
include src/app.mk# lib/module.mk
LIB_SRCS := $(wildcard lib/*.c)
LIB_OBJS := $(LIB_SRCS:lib/%.c=build/lib_%.o)
OBJS += $(LIB_OBJS)
build/lib_%.o: lib/%.c
$(CC) $(CFLAGS) -c -o $@ $<6. Common errors
| Error | Cause | Fix |
|---|---|---|
No rule to make target 'foo.o' | Missing source or rule | Check source path and pattern rule |
Nothing to be done for 'all' | Targets up to date | Touch a source file or run make clean |
Circular dependency dropped | Target depends on itself | Check dependency chain |
missing separator | Tab vs spaces | Recipes must use a tab, not spaces |
*** multiple target patterns | Pattern rule syntax error | Check % placement |
| Rebuilds everything every time | Timestamps wrong, or PHONY missing | Check date; ensure all is .PHONY |
| Header change not detected | No dep tracking | Add -MMD -MP and -include $(DEPS) |
For a full variable and function reference, see references/cheatsheet.md.
Related skills
- Use
skills/build-systems/cmakefor CMake-based projects - Use
skills/build-systems/ninjafor Ninja as a make backend - Use
skills/compilers/gccfor CFLAGS details
GNU Make Cheatsheet
Source: <https://www.gnu.org/software/make/manual/make.html>
Automatic variables
| Variable | Meaning |
|---|---|
$@ | Target filename |
$< | First prerequisite |
$^ | All prerequisites (no duplicates) |
$+ | All prerequisites (with duplicates) |
$? | Prerequisites newer than target |
$* | Stem (matched % in pattern rule) |
$(@D) | Directory part of $@ |
$(@F) | File part of $@ |
$(<D) | Directory part of $< |
$(<F) | File part of $< |
---
Special targets
| Target | Effect |
|---|---|
.PHONY: all clean | Declare targets that are not files |
.DEFAULT_GOAL := all | Set default target |
.SUFFIXES: | Clear default suffix rules |
.SILENT: | Suppress command echoing globally |
.ONESHELL: | Run recipe lines in one shell |
.DELETE_ON_ERROR: | Remove target on recipe failure |
---
Functions
| Function | Effect |
|---|---|
$(wildcard *.c) | Expand glob |
$(patsubst %.c,%.o,files) | Replace pattern |
$(subst from,to,text) | Replace literal string |
$(strip text) | Remove whitespace |
$(notdir path) | Filename without directory |
$(dir path) | Directory component |
$(basename file) | Filename without extension |
$(suffix file) | Extension only |
$(addprefix pre,list) | Add prefix to each word |
$(addsuffix suf,list) | Add suffix to each word |
$(filter %.c,list) | Keep matching words |
$(filter-out %.c,list) | Remove matching words |
$(sort list) | Sort and deduplicate |
$(foreach var,list,expr) | Loop |
$(if cond,then,else) | Conditional |
$(shell cmd) | Run shell command |
$(call var,arg1,arg2) | Call a function-like variable |
$(origin var) | Where a variable came from |
$(value var) | Value without expansion |
$(info msg) | Print message during parse |
$(error msg) | Fatal error during parse |
$(warning msg) | Warning during parse |
---
Variable assignment
| Syntax | Type | When expanded |
|---|---|---|
VAR = value | Recursive | At use |
VAR := value | Simple | At definition |
VAR ::= value | POSIX simple | At definition |
VAR ?= value | Conditional | Only if unset |
VAR += value | Append | Depends on type |
---
Conditionals
ifeq ($(CC),gcc)
CFLAGS += -fanalyzer
endif
ifneq ($(BUILD),release)
CFLAGS += -g
endif
ifdef DEBUG
CFLAGS += -DDEBUG
endif---
Multi-line variables
define HELP_TEXT
Usage: make [target]
all - build everything
clean - remove build artifacts
endef
help:
@echo '$(HELP_TEXT)'---
Order-only prerequisites
# build/ must exist, but its timestamp doesn't trigger rebuild
build/%.o: src/%.c | build
$(CC) -c -o $@ $<---
Recursive make (use sparingly)
SUBDIRS := lib src
.PHONY: all $(SUBDIRS)
all: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@Prefer a flat include-based approach over recursive make for correctness.
---
Command line overrides
make CFLAGS="-O3 -march=native" # override variable
make CC=clang # change compiler
make -n # dry run (print commands)
make -B # force rebuild all
make -k # keep going on error
make -j$(nproc) # parallel
make -p # print database (all rules)
make --warn-undefined-variables # catch typosRelated skills
How it compares
Use make for hand-written GNU Makefiles; switch to skills/build-systems/cmake for CMake-native projects.
FAQ
How does make track C header dependencies?
make recommends DEPFLAGS=-MMD -MP on compile lines, writing .d files beside .o outputs, then -include $(DEPS) so changing a header rebuilds dependent .c files. Without this, make only compares .o versus .c timestamps and misses include changes.
What causes make missing separator errors?
make documents that recipe lines must start with a tab character, not spaces. The missing separator error is the most common Makefile mistake when agents indent compile recipes with spaces instead of tabs.
How should multi-directory C projects use make?
make advises against recursive make for medium projects. Instead, a top-level Makefile includes lib/module.mk and src/app.mk fragments that append OBJS and pattern rules, keeping one dependency graph instead of fragile sub-make calls.