This is the current Makefile that I use with my C projects. Here is what I would like to be reviewed:

  1. Reusability - is this Makefile easy to use for multiple separate projects with minimal modification?

  2. Organization - is this Makefile organized in a logical and readable way?

  3. Dynamics - are there Make features (or compiler options/warnings) that I am not taking advantage of that could make my Makefile more powerful?

  4. Miscellaneous - what other things could I improve?

CXX = g++-4.9
CC = gcc-4.9
DOXYGEN = doxygen
CFLAGS = -fdiagnostics-color=always -std=gnu11 -s -c -g3 -O3 -time
WARNINGS = -Werror -Wall -Wextra -pedantic-errors -Wformat=2 -Wno-import -Wimplicit -Wmain -Wchar-subscripts -Wsequence-point -Wmissing-braces -Wparentheses -Winit-self -Wswitch-enum -Wstrict-aliasing=2 -Wundef -Wshadow -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wdisabled-optimization -Wunused-macros -Wno-unused
LIBRARIES = -lcurl
SOURCES = main.c test.c


    $(CC) $(LDFLAGS) $(OBJECTS) -o $@ $(LIBRARIES)

debug: CFLAGS += -DDEBUG -g

    $(CC) $< -o $@ $(CFLAGS) $(WARNINGS)

.PHONY: doc clean       
    $(DOXYGEN) doxygen.config    
    rm -rf $(EXECUTABLE) $(OBJECTS)
  • \$\begingroup\$ Question is why would you use and (more importantly) create by hand Makefiles? For any project that exceeds few files (and spans over more than one directory) Makefiles become very cumbersome and it seems to manage them sanely you need some other software (to i.e. generate them from some more sane description). I can really recommend scons.org, way more flexible than any other build system I have ever had a chance to use. And should work on any platform that Python works on. \$\endgroup\$ – elmo Apr 15 '14 at 8:36
  • 1
    \$\begingroup\$ Writing good Makefiles by hand is really not a simple task, especially when you are aiming for Reusability and Portability. I know that, when you are at the point you are at the moment, you don't want to hear about "meta-generators" like the one elmo suggested, but they really are a big help. While elmo pointed to SCONS, I familiarized myself with CMake, and did put together some boilerplate of my own, named JAWS. Check it out, it does what you want (including the Doxygen part), and much more... \$\endgroup\$ – DevSolar Apr 15 '14 at 9:51
  • \$\begingroup\$ @DevSolar If you expanded on that a bit in an answer, that would be something that I would give an upvote, and maybe even a reward bounty (but that would have to give an in-depth explanation of some stuff :))! \$\endgroup\$ – syb0rg Apr 15 '14 at 13:24
  • \$\begingroup\$ @syb0rg: I'd rather work on some polish for JAWS if you don't mind. ;-) Anything specific you think is missing? \$\endgroup\$ – DevSolar Apr 15 '14 at 13:57
  • \$\begingroup\$ @DevSolar I'm still going through it, I'm somewhat new to the world of the GNU build system. If you would join me in our chat room to talk about some stuff, that would be awesome! \$\endgroup\$ – syb0rg Apr 15 '14 at 14:07

I would make source file discovery dynamic:

 SOURCES   = $(wildcard *.c)

In addition to all I usually add debug and release versions.

CFLAGS = -fdiagnostics-color=always -std=gnu11 -s -c -time
all:     CFLAGS += -DTYPE=ALL
debug:   CFLAGS += -DTYPE=DEBUG    -g3
release: CFLAGS += -DTYPE=RELEASE  -O3

I have a generic build file that I have all my rules built-into.


Note: It is not perfect or great (but does what I need).
But have a look and pull anything you need.

This allows my actual makefiles to be very simple:

# The Target I want to build
# My generic Makefile build apps and lib based
# on the extension extension of the target.
TARGET                  = myLib.slib

# Then include the Generic Makefile
# In uses THORSANVIL_ROOT as the root of where you are
THORSANVIL_ROOT         = $(realpath ../)
include ${THORSANVIL_ROOT}/build/tools/Makefile

Dependencies: right now your makefile will let changes in .h to remain unnoticed.

DEPS := $(SOURCES:.c=.d)

    $(CC) -o $< -MM $(CFLAGS)

-include $(DEPS)

PS: it is highly recommended to remove -c from CFLAGS and mention it explicitly in the .c.o rule.


The first rule should just be


In turn, $(EXECUTABLE) will require $(OBJECTS), and each object will require its corresponding .c file.

Also, all should be a .PHONY target, since you are not actually going to produce a file named all.

Both of the remarks above apply equally to the debug target as well.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.