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>g++ -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:
CC =gcc CXX=g++
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 .cxx (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: .cxx .o $(CXX) -c $(CXXFLAGS) –c $<
This is an extension by Gnu make (gmake), but nearly every
It is similar to suffix rules.
The pattern for creating the .o:
%.o: %.cxx $(CXX) $(CXXFLAGS) -c $<
PROG = bmi SRCS = bmi.cxx bmistats.cxx stats.cxx OBJS = bmi.o bmistats.o stats.o LIBS = CC = gcc CXX = g++ CFLAGS = -O #CXXFLAGS = -O -std=c++11 CXXFLAGS = -g -std=c++11 LDFLAGS = all: $(PROG) $(PROG): $(OBJS) $(CXX) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) .PHONY: clean clean: rm -f $(PROG) $(OBJS) *.mod .SUFFIXES: $(SUFFIXES) .c .cpp .cxx .c.o: $(CC) $(CFLAGS) -c $< .cpp.o .cxx.o: $(CXX) $(CXXFLAGS) -c $< bmi.o: bmi.cxx stats.h bmistats.h bmistats.o: bmistats.cxx stats.o: stats.cxx
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 to work for C and C++ codes as well. 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, some called
makemake, are available and may be newer and better supported. See
here for example. That script also produces files for
CMake, a popular build system, especially for Windows.
Building with an IDE and a Makefile
Several IDEs will manage multiple files as a “project” and will generate a Makefile automatically. They do not always pick up dependencies correctly, however, so the programmer may need to write a custom Makefile. A script like one of the
makemake examples can help.
We will use the NetCDF library as an example. This is a popular library for self-describing data files. The example code is taken from their standard examples. The file are simple_xy_wr.cpp.
On our test Linux system, the library is not installed in a standard location, so we must add flags for the headers and library paths. Our example assumes the programmer added the environment variable
$NETCDF_ROOT to the shell.
First we run makemake to obtain a skeleton Makefile.
PROG = SRCS = simple_xy_wr.cpp OBJS = 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) $(CXX) $(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 $< simple_xy_wr.o: simple_xy_wr.cpp
We edit it to add the addition information required and to remove unneeded lines.
PROG = simple_xy_wr SRCS = simple_xy_wr.cpp OBJS = simple_xy_wr.o LIBS = -lnetcdf_c++ CXX = c++ CXXFLAGS = -O LDFLAGS = all: $(PROG) $(PROG): $(OBJS) $(CXX) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) .PHONY: clean clean: rm -f $(PROG) $(OBJS) *.mod .SUFFIXES: $(SUFFIXES) .c .cpp .cxx .cpp.o .cxx.o: $(CXX) $(CXXFLAGS) -c $< simple_xy_wr.o: simple_xy_wr.cpp
Make with MinGW/MSYS2 on Windows
The MinGW64/MSYS2 system provides two versions of
make. In newer releases, on newer Windows, either should work. If you do not wish to add an additional path to your PATH
environment variable use
mingw32-make. You can change the Geany build commands through its
build tools menu. The mingw32-make tool may not support as many features as the full-fledged Gnu
make provided by MSYS2. You can use Gnu make by adding the folder
C:\msys64\usr\bin to your PATH variable. This would not require changing the build tool on Geany. To build a
make project with Geany, be sure the main program tab is selected, then from the Build menu select Make.
If you have not already done so, download or copy the
example.cxx and its required
adder.cxx and header
adder.h. 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.