Makefiles¶
Makefile Rules¶
A makefile takes a set of rules in the following format:
target ... : prerequisites ...
(tab space) recipe
(tab space) ...
- A target usually refers to a file name that is generated by executing your program. This is your outcome from running your code.
- A prerequisite is a file that is required as input in order to generate the target, which often depends on several files.
- A recipe is an action that takes place when
make
carries out. One very important thing is to put a tab space in front of each recipe.
Makeifle examples¶
The directory $lecture_note/chapters/chapt02/codes/multifile
contains a Fortran code
fullcode.f90 that consists of a main program and two subroutines:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ! /codes/multifile/fullcode.f90
program demo
print *, "In main program"
call sub1()
call sub2()
end program demo
subroutine sub1()
print *, "In sub1"
end subroutine sub1
subroutine sub2()
print *, "In sub2"
end subroutine sub2
|
To illustrate the construction of a Makefile, we first break this up into three separate files:
1 2 3 4 5 6 7 | ! /codes/multifile/demo.f90
program demo
print *, "In main program"
call sub1()
call sub2()
end program demo
|
1 2 3 4 5 | ! /codes/multifile/sub1.f90
subroutine sub1()
print *, "In sub1"
end subroutine sub1
|
1 2 3 4 5 | ! /codes/multifile/sub2.f90
subroutine sub2()
print *, "In sub2"
end subroutine sub2
|
The directory $lecture_note/chapters/chapt02/codes/multifile
contains several Makefiles
that get successively more sophisticated to compile the codes in this
directory.
In the first version we write out explicitly what to do for each
file. In order to run this Makefile
, just type make
as long as your makefile has
a default name Makefile
or makefile
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # /codes/multifile/Makefile
output.txt: main.exe
./main.exe > output.txt
main.exe: main.o sub1.o sub2.o
gfortran main.o sub1.o sub2.o -o main.exe
main.o: main.f90
gfortran -c main.f90
sub1.o: sub1.f90
gfortran -c sub1.f90
sub2.o: sub2.f90
gfortran -c sub2.f90
|
In the second version there is a general rule for creating .o files from
.f90 files, called inference rules (see more article-inference),
or pattern rules (see more
article-pattern).
There is an old style rule called suffix rules which we will not use in our course.
See article-suffix
for more details. The last line (i.e., recipe) has the special macro
$<
which implies the filename of the prerequisite (i.e., *.f90
files). There are seven frequently used core
macro variables.
In order to run this non-default Makefile2
, you need
to type in make -f Makefile2
:
1 2 3 4 5 6 7 8 9 10 | # /codes/multifile/Makefile2
output.txt: main.exe
./main.exe > output.txt
main.exe: main.o sub1.o sub2.o
gfortran main.o sub1.o sub2.o -o main.exe
%.o : %.f90
gfortran -c $<
|
In the third version we define a macro OBJECTS so we only have to write out this list once, which minimizes the chance of introducing errors:
1 2 3 4 5 6 7 8 9 10 11 12 | # /codes/multifile/Makefile3
OBJECTS = main.o sub1.o sub2.o
output.txt: main.exe
./main.exe > output.txt
main.exe: $(OBJECTS)
gfortran $(OBJECTS) -o main.exe
%.o : %.f90
gfortran -c $<
|
In the fourth version, we add a Fortran compile flag (for level 3 optimization) and an linker flag (blank in this example):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # /codes/multifile/Makefile4
FC = gfortran
FFLAGS = -O3
DFLAGS = -g3
LFLAGS =
OBJECTS = main.o sub1.o sub2.o
output.txt: main.exe
./main.exe > output.txt
main.exe: $(OBJECTS)
$(FC) $(LFLAGS) $(OBJECTS) -o main.exe
%.o : %.f90
gfortran -c $(DFLAGS) $<
|
Next we add a phony
target clean
that removes the files created when compiling
the code in order to facilitate cleanup. It is phony because it does not
create a file named clean
, rather clean
is an action.
To run clean
, type make -f Makefile5 clean
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # /codes/multifile/Makefile5
OBJECTS = main.o sub1.o sub2.o
.PHONY: clean
output.txt: main.exe
./main.exe > output.txt
main.exe: $(OBJECTS)
gfortran $(OBJECTS) -o main.exe
%.o : %.f90
gfortran -c $<
clean:
rm -f $(OBJECTS) main.exe
|
Finally we add a help message so that make help says something
useful (you need to type make -f Makefile6 help
for this example):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # /codes/multifile/Makefile6
OBJECTS = main.o sub1.o sub2.o
.PHONY: clean help
output.txt: main.exe
./main.exe > output.txt
main.exe: $(OBJECTS)
gfortran $(OBJECTS) -o main.exe
%.o : %.f90
gfortran -c $<
clean:
rm -f $(OBJECTS) main.exe
help:
@echo "Valid targets:"
@echo " main.exe"
@echo " main.o"
@echo " sub1.o"
@echo " sub2.o"
@echo " clean: removes .o and .exe files"
|
Fancier things are also possible, for example automatically detecting all the .f90 files in the directory to construct the list of SOURCES and OBJECTS:
1 2 3 4 5 6 7 8 9 10 | # /codes/multifile/Makefile7
SOURCES = $(wildcard *.f90)
OBJECTS = $(subst .f90,.o,$(SOURCES))
.PHONY: test
test:
@echo "Sources are: " $(SOURCES)
@echo "Objects are: " $(OBJECTS)
|
Further reading¶
- http://software-carpentry.org/4_0/make/
- http://www.gnu.org/software/make/manual/make.html
- http://mrbook.org/tutorials/make/
- http://en.wikipedia.org/wiki/Make_%28software%29
- remake, a make debugger
- https://stackoverflow.com/questions/5950395/makefile-to-compile-multiple-c-programs, a makefile to produce multiple executables