Makefile
Overview
make is a build tool that automatically performs a sequence of steps, such as compilation and linking, to produce an executable from source code. It has long been used as a standard tool on UNIX-like operating systems such as Linux.
Developers describe the required procedures in a Makefile. When the make command reads the file, it executes the commands in sequence and completes the build.
What Is a Makefile?
A Makefile describes the compiler, source files, outputs, build order, and dependencies. Running make is enough to perform the build, and reading the file shows how the program is built. make also determines which files need to be updated, minimizing compilation work and shortening development time.
The GNU Make home page describes Make as follows.
- GNU Make is a tool which controls the generation of executables and other non-source files of a program from the program’s source files.
This provides the following benefits.
- End users can build and install a package without knowing the detailed procedure.
- make identifies files that need updates from the changed source files and automatically determines the correct order.
- Make supports compiled languages other than C.
Make - GNU Project - Free Software Foundation
Basic Makefile Syntax
make is useful when building C/C++ projects that use many libraries. To use make, prepare a Makefile.
The basic syntax consists of a Target: SourceFile line and a command line beginning with a tab. You can replace a line break with a semicolon to place the rule on one line. You can also define variables in the form name=value and use them for file names and other values.
Target : [Prerequisites]
Recipe
- Target: the name of a file generated by the program.
- Prerequisites: input files used to generate the target. You can specify multiple files or omit them.
- Recipe: an action executed by make. It may span multiple lines by using
\, and each line must begin with a tab.
Target: SourceFile
Command
For example:
hello: hello.c
gcc -o hello hello.c
You can also add commands to delete or copy generated files.
clean:
rm -f *~ hello
install: hello
install -s hello.exe Path
If you run make without arguments, the first target is executed. To run clean or install, specify it as an argument.
make clean
make install
To use a file other than Makefile, specify it with -f.
make -f sample.mk
You can also use variables.
CXX = g++
OPTIMIZE = -O3
CFLAGS = -IC:/Users/include \
-IC:/Python/include
DEST = C:/Users/Local
LDFLAGS = -LC:/Users/Local/libs
LIBS = -lpython
OBJS = hello
all: clean $(PROGRAM) install
$(PROGRAM): $(OBJS)
$(CXX) -o $(OBJS) $(OBJS).cpp $(CFLAGS) $(LDFLAGS) $(LIBS)
clean: rm -f *~ $(OBJS)
install: $(PROGRAM)
install -s $(OBJS).exe $(DEST)
Makefile Variables
Makefile variables include implicit variables and variables you define yourself. Implicit variables are predefined variables used by implicit rules.
What Are Implicit Rules?
Some rules and variables are predefined. For example, the recipe for compiling a C source file executes $(CC) -c $(CFLAGS) $(CPPFLAGS). The CC, CFLAGS, and CPPFLAGS variables are predefined, and you can override them to change the recipe.
Implicit Variable List
| Variable | Description | Default |
|---|---|---|
| AR | Archive-maintenance program | ar |
| AS | Assembly program | as |
| CC | C compiler | cc |
| CXX | C++ compiler | g++ |
| CO | RCS checkout program | co |
| CPP | C preprocessor | $(CC) -E |
| FC | Fortran and Ratfor compiler or preprocessor | f77 |
| GET | SCCS extraction program | get |
| LEX | Converts Lex grammar to C or Ratfor | lex |
| PC | Pascal compiler | pc |
| YACC | Converts Yacc grammar to C or Ratfor | yacc |
| YACCR | Converts Yacc grammar to Ratfor | yacc -r |
| MAKEINFO | Converts Texinfo source to Info | makeinfo |
| TEX | Creates TeX DVI from TeX source | tex |
| TEXI2DVI | Creates TeX DVI from Texinfo source | texi2dvi |
| WEAVE | Translates Web to TeX | weave |
| CWEAVE | Translates C Web to TeX | cweave |
| TANGLE | Translates Web to Pascal | tangle |
| CTANGLE | Translates C Web to C | ctangle |
| RM | File-removal command | rm -f |
| ARFLAGS | Flags for the archive-maintenance program | rv |
| ASFLAGS | Assembler flags | none |
| CFLAGS | C compiler flags | none |
| CXXFLAGS | C++ compiler flags | none |
| COFLAGS | RCS co flags | none |
| CPPFLAGS | C preprocessor and compiler flags | none |
| FFLAG | Fortran compiler flags | none |
| GFLAG | SCCS get flags | none |
| LDFLAGS | Compiler flags used when invoking the linker | none |
| LFLAGS | Lex flags | none |
| PFLAGS | Pascal compiler flags | none |
| RFLAGS | Fortran compiler flags for Ratfor | none |
| YFLAGS | Yacc flags | none |
https://www.gnu.org/software/make/manual/make.html#Implicit-Variables
Defining Variables
There are two ways to define variables.
| Symbol | Details |
|---|---|
= |
Recursively expanded variable |
:= |
Simply expanded variable |
foo = $(bar)
bar = $(ugh)
ugh = Huh?
all:
echo $(foo) # => Huh?
Referencing Variables
Use $(name) or ${name}.
objects = program.o foo.o utils.o
program : $(objects)
cc -o program $(objects)
$(objects) : defs.h
Automatic Variables Used in Rules
Automatic variables provide shorthand references to targets and prerequisites.
| Variable | Function |
|---|---|
$@ |
Target name |
$< |
First prerequisite name |
$^ |
All prerequisite names without duplicates |
$? |
Prerequisites newer than the target |
$+ |
All prerequisite names, including duplicates |
$* |
Part matched by the target pattern |
$@
$@ is the current target name. $(D) and $(F) suffixes select its directory and file name.
aaa/bbb/foo:
echo $@ # => aaa/bbb/foo
echo $(@D) # => aaa/bbb
echo $(@F) # => foo
$<
$< is the first prerequisite name.
output/foo: input/bar input/baz
echo $< # => input/bar
echo $(<D) # => input
echo $(<F) # => bar
$^
$^ contains all prerequisite names without duplicates.
output/foo: input/bar input/baz
echo $^ # => input/bar input/baz
echo $(^D) # => input input
echo $(^F) # => bar baz
$?
$? contains prerequisite names with timestamps newer than the target.
output/foo: input/bar input/baz
echo $? # => input/bar
echo $(?D) # => input
echo $(?F) # => bar
$+
$+ contains all prerequisite names, including duplicates. $^ is more commonly used.
output/foo: input/baz input/baz input/baz
echo $+ # => input/baz input/baz input/baz
echo $(+D) # => input input input
echo $(+F) # => baz baz baz
$*
$* is the part matched by the target pattern. This is useful when generating related files.
Makefile Functions
Make provides functions for string processing and conditional branching in Makefiles.
Text Transformation Functions
Call functions with $(function arguments) or ${function arguments}.
Reference: https://www.gnu.org/software/make/manual/make.html#Text-Functions
shell
Runs a shell command.
files := $(shell echo *.c)
INCLUDE := $(shell find $(INCDIRS) -type d)
SRCDIR = ./srcs
SRCS := $(shell find $(SRCDIR) -name *.c)
all:
echo $(files) # => hoge.c foo.c
echo $(INCLUDE) # => include
echo $(SRCDIR) # => ./srcs
echo $(SRCS) # => hoge.c foo.c
RESULT = $(shell seq 1 10)
all:
echo $(RESULT) # => 1 2 3 4 5 6 7 8 9 10
addprefix
Adds a prefix. This is useful for options such as -l.
FILES := foo bar
all:
echo $(addprefix src/,$(FILES)) # => src/foo src/bar
dir
Extracts directory parts from file names.
FILES := src/hoge.c src/hoge.h index.html
all:
echo $(dir $(FILES)) # => src/ src/ ./
notdir
Extracts file names.
FILES := ./dir/hoge.txt
all:
echo $(notdir $(FILES)) # => hoge.txt
Substitution References
Substitution references replace matching suffixes in variable values. They are shorthand for patsubst.
foo := a.o b.o c.o
bar := $(foo:%.o=%.c)
bar2 := $(patsubst %.o,%.c,$(foo))
realpath, suffix, and wildcard
"$(realpath ./dir/hoge.txt)"//C:users/hoge/bin/hoge.txt
"$(suffix ./dir/hoge.txt)"//.txt
"$(wildcard ./dir/*.txt)"//hoge.txt hogehoge.txt
Conditional Functions
"$(if $(VAR1),$(exist),$(none))"
ifeq ($(CC),gcc)
libs=$(libs_for_gcc)
else
libs=$(normal_libs)
endif
Debugging a Makefile
GNU Make’s -n option prints commands without executing them.
CC = gcc
OBJ = hoge.c
CFLAGS = -c $(OBJ)
$ make -n
gcc -c hoge.c -o hoge
The warning function prints content while make runs.
$(warning MAKE = $(MAKE))
$(warning CC = $(CC))
$(warning CFLAGS = $(CFLAGS))
Installing g++, make, and cmake
Installing on Windows
On Windows, use MinGW for g++/gcc, GnuWin for make, and the CMake installer for cmake.
To install from a command-line interface:
choco install mingw
choco install make
Configure the paths as environment variables.
C:\Program Files (x86)\MinGW\bin
C:\Program Files (x86)\GnuWin32\bin
Installing on Linux
Install all required packages together:
sudo apt install build-essential
Or install them individually:
sudo apt install g++
sudo apt install make
Summary
This article summarized how to write a Makefile. It will continue to be updated as a reference.