Managing Projects with Make
make is a tool to manage builds, especially with multiple files.
It has a rigid and peculiar syntax.
It will look for a
makefile first, followed by
Makefile (on case-sensitive systems).
makefile defines one or more targets . The target is the product of one or more rules .
The target is defined with a colon following its name. If there are dependencies those follow the colon.
Dependencies are other files that are required to create the current target.
Targets and Rules
myexec:main.o module.o <tab>gfortran -o myexecmain.o module.o
The tab is required in the rule. Don’t ask why.
Macros (automatic targets) for rules:
$@ the file name of the current target $< the name of the first prerequisite
Variables and Comments
We can define variables in makefiles:
We then refer to them as
Common variables: F90, CC, CXX, FFLAGS, F90FLAGS, CFLAGS, CXXFLAGS, CPPFLAGS (for the preprocessor), LDFLAGS.
The continuation marker
\ (backslash) can be used across multiple lines. It must be the last character on the line; do not add spaces after it.
Comments are indicated by the hash mark
#. Anything beyond it will be ignored except for a continuation marker, which will extend the comment.
If all .f90 (or .cc or whatever) files are to be compiled the same way, we can write a suffix rule to handle them.
It uses a phony target called
.SUFFIXES: .f90 .o $(F90) -c $(F90FLAGS) –c $<
This is an extension by Gnu make (gmake), but nearly every
It is similar to suffix rules. Useful for Fortran 90+:
Pattern for creating the .o:
%.o: %.f90 $(F90) $(F90FLAGS) -c $<
PROG =bmidata SRCS = bmi_calculator.f90 bmi_data.f90 csv_file.f90 prec.f90 stats.f90 OBJS =bmi_calculator.obmi_data.ocsv_file.oprec.ostats.o LIBS = F90 =gfortran #F90FLAGS=-O F90FLAGS = -g -C LDFLAGS = all: $(PROG) $(PROG): $(OBJS) $(F90) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) .PHONY: clean clean: rm-f $(PROG) $(OBJS) *.mod .SUFFIXES: $(SUFFIXES) .f90 .F90 .f95 .f90.o .f95.o .F90.o: $(F90) $(F90FLAGS) -c $< stats.o:prec.o bmi_calculator.o:csv_file.o prec.o bmi_data.o:bmi_calculator.o csv_file.o prec.o stats.o
In this example, notice that the suffix rule applies the global compiler flags and explicitly includes the
-c option. If a particular file does not fit this pattern, a rule can be written for it and it will override the suffix rule. The link rule includes the loader flags and the
-o flag. The compilation suffix rule uses the special symbol for the prequisite; the link rule applies to the current target.
The example also demonstrates switching back and forth between “debug” and “optimized” versions. The “debug” version would be created this time. The
-g flag is required for debugging. The
-C flag is a very useful flag specific to Fortran that enables bounds checking for arrays. Both these flags, but especially
-C, will create a slower, sometimes much slower, executable, so when debugging is completed, always recompile with the optimization flag or flags enabled, of which
-O is the minimum and will activate the compiler’s default level. You must always
make clean anytime you change compiler options.
For further reading about
make, see the
Makemake is a Perl script first developed by Michael Wester soon after the introduction of Fortran 90, in order to construct correct makefiles for modern Fortran code. The version supplied here has been extended. It is freely licensed but if you use it, please do not remove the credits at the top.
This version works reasonably well for Fortran, C, and C++. It will generate stubs for all languages. You may remove any you are not using. Also note that the output is a skeleton
Makefile. You must at minimum name your executable, and you must fill in any other options and flags you wish to use. The
makemake script blindly adds any files ending in the specified suffixes it finds in the current working directory whether they are independently compilable or not, so keep your files organized, and be sure to edit your Makefile if you have files you need but cannot be compiled individually.
Several other build tools called
makemake are available, and not all handle Fortran. In addition, more tools have been created since the first
makemake. Several options are described at the
Fortran Wiki. The Python
makemake can search recursively through subfolders, which the original
Building with an IDE and a Makefile
Several IDEs will manage multiple files as a “project” and will generate a Makefile automatically. Unfortunately, that Makefile is frequently incorrect for Fortran codes that use modules, so you may have to write your own Makefiles. The
makemake script or one of the newer build tools described above can help.
We will use the NetCDF library as an example. Environmental sciences still use Fortran a great deal and this is a popular library for data files. The example code is taken from their standard examples, modified to place the subroutine into a separate file. The file is simple_xy_wr.f90.
On our test system, the library is installed in a standard location, but the netcdf module is not, so we need to use the
-I flag but not the
First we run makemake to obtain a skeleton Makefile.
PROG = SRCS = check.f90 simple_xy_wr.f90 OBJS = check.o simple_xy_wr.o LIBS = CC = cc CXX = c++ CFLAGS = -O CXXFLAGS = -O FC = f77 FFLAGS = -O F90 = f90 F90FLAGS = -O LDFLAGS = all: $(PROG) $(PROG): $(OBJS) $(F90) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) .PHONY: clean clean: rm -f $(PROG) $(OBJS) *.mod .SUFFIXES: $(SUFFIXES) .f .f90 .F90 .f95 .SUFFIXES: $(SUFFIXES) .c .cpp .cxx .f90.o .f95.o .F90.o: $(F90) $(F90FLAGS) -c $< .f.o: $(FC) $(FFLAGS) -c $< .c.o: $(CC) $(CFLAGS) -c $< .cpp.o .cxx.o: $(CXX) $(CXXFLAGS) -c $< check.o: simple_xy_wr.o:
We edit it to add the addition information required and to remove unneeded lines.
PROG = simple_xy_write SRCS = check.f90 simple_xy_wr.f90 OBJS = check.o simple_xy_wr.o LIBS = -lnetcdff -lnetcdf F90 = gfortran INCS = /usr/lib64/gfortran/modules F90FLAGS = -O -I$(INCS) LDFLAGS = all: $(PROG) $(PROG): $(OBJS) $(F90) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) .PHONY: clean clean: rm -f $(PROG) $(OBJS) *.mod .SUFFIXES: $(SUFFIXES) .f .f90 .F90 .f95 .f90.o .f95.o .F90.o: $(F90) $(F90FLAGS) -c $< check.o: simple_xy_wr.o:
If you have not already done so, download or copy the
example.f90 and its required
adder.f90. Place them into a separate folder. Run
makemake. Edit the Makefile appropriately. Build the project using Geany or your choice of IDE.
If you are working on a system with NetCDF available, download the two files and the completed Makefile into their own folder. Open Geany and browse to the location of the files. Open the two source files. Either select
Make from the
Build menu, or from the dropdown arrow next to the brick icon choose
Build the code using the Makefile. Execute the result.