Back to index.html.
make command is a traditional Unix tool to build an executable. It understands the dependency among files and figures out the order of files to be compiled by reading a configuration file (makefile). If your program consists of more than 2 files,
make helps you to compile the files.
A simple makefile
Dependency graph and makefile
Assume we have a module (
mymod.f90) and the main program (
main.f90) and each program unit is stored in a separate file. The module should be compiled first. The main program has to link the module object. The dependency is represented as the following figure.
This dependency graph shows that the main program requires the module. Although the main program requires depends on two files (
mymod.o), these two files are generated at the same time, so we would say that
main.f90 depends on the presence of one of these 2 files. With a separate compilation, you have to run the compiler 3 times.
gfortran -c mymod.f90 gfortran -c main.f90 gfortran main.o myprod.o
A makefile represents the graph in a special syntax. Although the name of the makefile is arbitrary, we usually use
makefile because the
make command looks for such files by default. Here is a simple makefile to describe the above dependency.
a.out: myprod.o main.o gfortran main.o mymod.o main.o: main.f90 gfortran -c main.f90 mymod.o: mymod.f90 gfortran -c mymod.f90
Save this content as a file,
Makefile, and simply type
make in your terminal. The command reads the makefile and compiles the files in the requested order.
Structure of makefile
A makefile consists of repeated rules of a target (product) file, dependent files, and the command to generate the target.
target : dependency files (ingridients) command to generate the target
The target file is a single file. The order of files in the dependency list is arbitrary. The target and the dependency files are separated by
: (colon). In the command line, you must insert a tab character at the top of the command. The tab is a marker to start the command in a makefile, so it can not be replaced with spaces. You can put 2 or more command lines; each command should be in a separate line (with a tab character).
You should repeat this block as many as you need. In the above example, you have to run a command (compiler) 3 times, so you need at least 3 blocks to describe the dependency graph.
By default, the first rule is for the final target. The order of remaining rule is arbitrary. In the above case, the final target is
make creates a dependency graph. You can place the final target at any place in a makefile, using some techniques explained later.
In the makefile, characters followed by
# will be ignored as a comment. It is similar to a shell script and some scripting languages.
How it works
make command creates the dependency graph. It means that this command knows which file is need to generate the final target. For example, in the above case, when
main.f90 is updated but
mymod.f90 is unchanged, you just need to re-compile
main.f90 only, and link the new
main.o and the existing
make command will do it.
The command checks the timestamp of the target file and the dependency files. If the target is older than the ingredients (or the target does not exist), the program runs the specified commands. This smart compilation saves much time when there are many files in your project.
makecommand creates a dependency graph of files involved in a compilation process.
- The graph is described in a makefile. The default name is
- A makefile has several rules. Each rule consists of the target name, its dependency files, and the commands to generate the target.
- The first rule describes the final target.
- The command line must starts with a tab character.
makecommand compares the timestamp between the target and each one of the ingredients. If the target is old (or not found),
makeinvokes the commands.
- The character
#leads a comment line.
- Change the order of rules in the makefile shown above. Make sure the changed file does not work.
- Remove a tab character from the makefile shown above, and make sure it does not work.
Useful features for makefile
A makefile can have a macro, which is used as a variable. The above make file can be generalized using some macros.
FC = gfortran a.out: myprod.o main.o $(FC) main.o mymod.o main.o: main.f90 $(FC) -c main.f90 mymod.o: mymod.f90 $(FC) -c mymod.f90
The macro is defined as
macro_name = value, usually placed at the top of the makefile. The macro name separates upper and lower cases. To expand the macro (i.e., to get the value), use
$(macro_name). Note that
$ is required when referring to the macro. In the above case, a macro
FC (for Fortran compiler) defines a compiler so that you can just modify the macro to change the compiler.
There are many features in macros. Please search the possible usage of macros by yourself.
The makefile has several pre-defined targets, and
.PHONY: is one of them. It defines a dummy target that is not a file name. Typical usage of
.PHONY is to define a more meaningful target-name than a file name.
Assume your makefile has the final target
a.out, but it is not at the top. You may come up with the following makefile to specify the final target.
FC = gfortran all: a.out main.o: main.f90 $(FC) -c main.f90 mymod.o: mymod.f90 $(FC) -c mymod.f90 a.out: myprod.o main.o $(FC) main.o mymod.o
The first target is
all, which is not a file, but it just indicates the final product. Although it works, it becomes clumsy if you have many such dummies and real files in a makefile. The
.PHONY target clarify which targets are dummy. The dummy target
all is often used to refer to the final target.
FC = gfortran .PHONY: all all: a.out main.o: main.f90 $(FC) -c main.f90 mymod.o: mymod.f90 $(FC) -c mymod.f90 a.out: myprod.o main.o $(FC) main.o mymod.o
Another typical usage of dummy targets is to remove all existing files. A dummy target,
clean, is used in practice for this purpose.
FC = gfortran .PHONY: all clean all: a.out main.o: main.f90 $(FC) -c main.f90 mymod.o: mymod.f90 $(FC) -c mymod.f90 a.out: myprod.o main.o $(FC) main.o mymod.o clean: rm -f a.out *.o *.mod
Options of the make command
If you obtain a target described in the 2nd or later rules rather than the final target, you can specify the target as an option of
make in the terminal. For example, in the above case, the following command tries to generate
main.o instead of
Arbitrary name of the makefile
If the name of a makefile is not
makefile, you can specify the name in the terminal. For example, when the makefile is
makefile.txt, type the following command in terminal.
make -f makefile.txt
Some files may be independent, and these files can be compiled at the same time. The
make command finds independent files and runs the commands in parallel with an option.
make -j 4
It can use at most 4 threads if possible. The option
-j, meaning jobs, specifies the number of threads to generate the target. This option is not useful in a small project, but it becomes very efficient with many files. Note that, if the dependency graph is broken or incomplete, the compilation may fail with this option.
Back to index.html.