Skip to content

Build a Simple Makefile

December 20th, 2015 - Software(1 min)

TL;DR: If you don’t have anything better to do, create Makefiles by hand :) Gist here.

The other day I went back to origins with building a small C++ project. With modern tools, all went OK. However, deployment was a bit of a problem, in the sense the host had an obsolete toolchain:

Me: GCC 5.2.x, CMAKE 3.3 ...

Host: GCC 4.7.x, no CMAKE :(

So, I had to build a makefile by hand!

Following some best practices, I’ve devised a simple Makefile with following sections:

  1. A declaration section, where all parameters are specified
  2. A targets section, where different targets are specified (e.g. compilation, linking…)

The declaration section

Here I’m basically making the script flexible. I’m declaring:

  • The compiler
  • The compiler flags
  • The INCLUDES
  • The sources and objects
  • The project (binary) name

The section looks like this:

# The compiler
CXX = /usr/bin/g++
CXXFALGS = -std=c++11 -ggdb3 -Wpedantic -Wall -Wextra \
    -Wconversion -Wstrict-null-sentinel -Wold-style-cast \
    -Wnoexcept -Wctor-dtor-privacy -Woverloaded-virtual \
    -Wsign-promo -Wzero-as-null-pointer-constant

# Commented out (not supported by gcc<5):
# Wsuggest-final-types -Wsuggest-final-methods -Wsuggest-override

# The executable sources and target
#
INCLUDES = -I.
SRCS = main.cpp \
    tests/common/checks.cpp \
    tests/polynomial/test_polynomial_modulo.cpp

OBJS = $(SRCS:.cpp=.o)

MAIN = polymorph

The targets

The targets sections is as simple as possible:

  • an “all” target to build the MAIN
  • The compilation target (from C++ to .o)
  • The linking target
  • A cleanup target (if you get to copy files around like me)

It looks like this:

.PHONY: depend clean

all: $(MAIN)
      @echo  Polymorph binary has been compiled

$(MAIN): $(OBJS)
        $(CXX) $(CXXFALGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS)

# this is a suffix replacement rule for building .o's from .c's
# it uses automatic variables $<: the name of the prerequisite of
# the rule(a .c file) and [email protected]: the name of the target of the rule (a .o file)
# (see the gnu make manual section about automatic variables)
.cpp.o:
        $(CXX) $(CXXFALGS) $(INCLUDES) -c $<  -o [email protected]

clean:
        $(RM) *.o *~ $(MAIN)

depend: $(SRCS)
        makedepend $(INCLUDES) $^

Please not that make is picky and you need tab indenting for targets.

Conclusion

This is a simple Makefile to build an executable. Generally, you’ll need to edit the CXX , CXXFLAGS , INCLUDE , SRC and MAIN. Alternatively you can use a modern tool like CMAKE, which will create an OS-dependent makefile.

Best part is the CMAKE equivalent is much simpler:

cmake_minimum_required(VERSION 3.3)
project(polymorph)
# -Weffc++

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -std=c++14 -ggdb3 -Wpedantic -Wall -Wextra -Wconversion -Wstrict-null-sentinel -Wold-style-cast -Wnoexcept -Wctor-dtor-privacy -Woverloaded-virtual -Wsign-promo -Wzero-as-null-pointer-constant -Wsuggest-final-types -Wsuggest-final-methods -Wsuggest-override")

set(SOURCE_FILES main.cpp structures/vector.h structures/polynomial_mod.h tests/polynomial/test_polynomial_modulo.cpp tests/polynomial/test_polynomial_modulo.h tests/common/checks.cpp tests/common/checks.h)

add_executable(polymorph ${SOURCE_FILES})

HTH,

Share on
Reddit
Linked in
Whatsapp

A little experiment: