Generic Makefile

Posted on

Problem

I decided to setup a generic makefile to compile SFML programs, as I’m going to be making a bunch of small apps over the next few weeks playing around with it. I’m still new to writing makefiles (still weaning off of using IDEs), but I’m pretty happy with how it turned out.

################################################################
##                         Variables                          ##
################################################################

# Default variables
# CC - The compiler
# INC - The include directories
# CFLAGS - Compiler flags to use
# LDFLAGS - Linker flags to use
# TITLE - Output file name
CC   := g++
INC  := -I./include
CFLAGS   := $(INC) -std=c++0x
LDFLAGS  := -lsfml-audio -lsfml-network -lsfml-graphics -lsfml-window -lsfml-system
TITLE    ?= App


# Build specific variables, if need be define these when running make
# BUILD - Either Debug or Release, defaults to Release
# ARCH - Either 32 or 64, defaults to OS type
BUILD ?= RELEASE

ifeq ($(shell uname -p),x86_64)
    ARCH    ?= 64
    CFLAGS  := $(CFLAGS) -fPIC
else
    ARCH    ?= 32
endif

ifeq ($(BUILD),DEBUG)
    CFLAGS  := $(CFLAGS) -m$(ARCH) -g -pg -Og
    LDFLAGS := $(LDFLAGS) -m$(ARCH)
endif

ifeq ($(BUILD),RELEASE)
    CFLAGS  := $(CFLAGS) -m$(ARCH) -s -O3
    LDFLAGS := $(LDFLAGS) -m$(ARCH)
endif


# Directory variables, no need to change these
# SRCPATH - The directory for source files
# OBJDIR - Directory path for .o files
# BINPATH - Where to put the built library
SRCPATH := ./src/
OBJDIR  := ./obj/$(BUILD)/$(ARCH)-bit
BINPATH := ./bin/$(BUILD)/$(ARCH)-bit


# File variables, should only need to change when adding source files
# SOURCES - Path to all source files
# OBJECTS - Path to output individual object files
# DIRECTORIES - List of directories to mirror source code directory structure
SOURCES     := $(shell find ./src -type f -regex '.*.cpp' | tr 'n' ' ')
OBJECTS     := $(addprefix $(OBJDIR)/,$(SOURCES:.cpp=.o))
DIRECTORIES := $(BINPATH) $(addprefix $(OBJDIR)/,$(shell find ./src -type d | tr 'n' ' '))


################################################################
##                     Build Targets                          ##
################################################################

# Default build target
all: BINARY

# Builds the final game binary
BINARY: $(SOURCES)
    $(CC) $(LDFLAGS) $(OBJECTS) -o $(BINPATH)/$(TITLE)

# Compiles individual source files into object files
$(SOURCES): $(DIRECTORIES)
    $(CC) $(CFLAGS) -c $@ -o $(patsubst %.cpp,%.o,$(OBJDIR)/$@)

# Ensures the existance of the directory structure
$(DIRECTORIES):
    mkdir -p $@

# Deletes object files
clean:
    rm -rf ./obj
    rm -rf ./bin
    find -regex '.*~' -exec rm {} ;

Solution

  • CFLAGS traditionally refer to compiling .c files. The c++ compiler is traditionally invoked with CXXFLAGS.

  • I must advise against automatic collection of SOURCES (line 54). Usually you need to build more than one target from the same tree (a unit test version, for example). It is better to be explicit telling which sources contribute to which target.

  • Line 67. BINARY does not depend on the sources. It depends on $(OBJECTS). Think of modification made to some .h file: the source would remain unchanged, yet the object – and hence a target – must be rebuilt.

  • However each object does depend on the corresponding source, as well as on all of the files the source includes. These dependencies must be accounted for. Spelling them out manually is too tedious and too error prone. With GCC (and all other compilers except MS) you may rely on the -M family of options to generate the necessary dependencies.

A standard approach is to declare a DEP set of targets, pretty much the same way as OBJECTS is defined:

DEPS := $(addprefix $(DEPDIR)/,$(SOURCES:.cpp=.d))

define the stem rule to generate a .d file as

$(DEPDIR)/%.d: %.cpp
    $(CC) _MM $(CXXFLAGS) -o $@ $<

and take the resulting makefile fragments into account:

-include $(DEPS)
  • I’d recommend to provide ARCH from the command line to enable cross-arch builds.

Leave a Reply

Your email address will not be published. Required fields are marked *