https://xkcd.com/303/
https://xkcd.com/303/

Building Executables

How are executables built?

In short, human-readable code is translated into machine code that your computer can execute. This breaks down into two steps*:

  1. Compiling - translating human-readable code to binary objects
  2. Linking - gluing binary objects together into a runnable

How are executables built?

https://goo.gl/g0bMH2
https://goo.gl/g0bMH2

So what?

If you don't change a file's source code, its object file won't change either.

For huge projects with hundreds of source files, it saves a ton of time to keep object files and only re-compile the source that changes.

This is impractical to do by hand. That's what make is for!

make

What is make?

  • make is a program that is used to create files (such as executables).

  • It can detect what has changed between builds and only rebuild what is necessary.

  • Makefiles are very common in large C and C++ projects.

  • They can also be used to store project-related commands.

Your First Makefile

# Makefile 1
program:
        g++ *.cpp -o program

Dependencies

# Makefile 2
program: main.cpp funcs.h funcs.cpp
        g++ *.cpp -o program

Multiple Targets

# Makefile 3
program: main.o funcs.o
        g++ main.o funcs.o -o program

main.o: main.cpp funcs.h
        g++ -c main.cpp

funcs.o: funcs.cpp funcs.h
        g++ -c funcs.cpp

Phony Targets

# Makefile 4
.PHONY: clean

program: main.o funcs.o
        g++ main.o funcs.o -o program

# %< --- SNIP --- >%

# - means "ignore errors from"
# @ means "don't print command"
clean:
        -@rm -f program
        -@rm -f *.o

Variables

Variables

  • var=value sets values.

  • ${var} uses the value of the variable.

  • var=$(wildcard *.cpp) stores the name of every file ending in .cpp in var.

  • foo=$(var:%.cpp=%.o) substitutes .o for .cpp in all the files in var.

  • target: var=thing assigns thing to var when building target and its dependencies.

CFLAGS = -Wall --pedantic-errors -O2

program: main.o funcs.o
        g++ ${CFLAGS} main.o funcs.o -o program

.PHONY:debug
debug: CFLAGS = -g -Wall --pedantic-errors
debug: program

main.o: main.cpp funcs.h
        g++ ${CFLAGS} -c main.cpp

funcs.o: funcs.cpp funcs.h
        g++ ${CFLAGS} -c funcs.cpp

Patterns

Patterns

  • You can make pattern targets that describe how to build more than one file.

  • As with substitution, you use % for the variable part of the target name.

  • For example: %.o: %.cpp describes how to build any .o file from its matching .cpp file.

  • $@ holds the name of the target.

  • $< holds the name of the first dependency.

  • $^ holds the names of all the dependencies.

  • Automatic Variables

SOURCES = $(wildcard *.cpp)
HEADERS = $(wildcard *.h)
OBJECTS = $(SOURCES:%.cpp=%.o)

CPP = g++
CFLAGS = -Wall --pedantic-errors -O2

program: ${OBJECTS}
        ${CPP} ${CFLAGS} ${OBJECTS} -o program

%.o: %.cpp ${HEADERS}
        ${CPP} ${CFLAGS} -c $<

.PHONY: clean
clean:
        -@rm -f program
        -@rm -f ${OBJECTS}

Miscellany

Miscellany

Command-Line Options:

  • make -j3 runs up to 3 jobs in parallel

  • make -B makes targets even if they seem up-to-date.

Related programs:

  • makedepend is a command for auto-generating dependencies in C and C++ projects.

  • CMake can generate Makefiles and various IDE configurations for projects.