Ocean Modeling Discussion


Search for:
It is currently Thu Aug 16, 2018 4:30 am

Post new topic Reply to topic  [ 1 post ] 

All times are UTC

Author Message
 Post subject: make
PostPosted: Tue Mar 14, 2006 11:18 pm 
User avatar

Joined: Wed Jul 02, 2003 5:29 pm
Posts: 3485
Location: IMS/UAF, USA
This is the prequel to the gmake thread. These articles first appeared in the ARSC HPC Newsletter.

Introduction to Make

Make is a tool which is almost as old as Unix, designed primarily for keeping track of how programs are compiled. That is what we will describe here, although it can be used for other things, including web page maintenance. It is just a matter of telling make what commands need to be run to update your files.

Make gets its instructions from a description file, by default named Makefile. This file is also called the Makefile, but other files can be used by invoking make with the -f option, e.g.:

<TAB> make -f Makefile.yukon

When I first got our ocean model, its Makefile looked something like:

model: main.o init.o plot.o
<TAB> f90 -o model main.o init.o plot.o

main.o: main.f
<TAB> f90 -c -O main.f

init.o: init.f
<TAB> f90 -c -O init.f

plot.o: plot.f
<TAB> f90 -c -O0 plot.f

<TAB> rm *.o core

The default thing to build is "model", the first target. The syntax is

target: dependencies
<TAB> command
<TAB> command

The target model depends on the object files, main.o and friends. They have to exist and be up to date before model's link command can be run. The other targets tell make how to create the object files. The original version of this Makefile turned off optimization on plot.f due to a compiler bug, but hopefully you won't ever have to worry about that.

Compiling model is simple, just type "make". Make will look for the file Makefile, read it, and do whatever is necessary to make model up to date. If you edit init.f, that file will be newer than init.o. Make would see that init.o is out of date and run the f90 -c -O init.f command. Now init.o is newer than model, so the link command f90 -o model main.o init.o plot.o must be executed.

Clean up by typing "make clean". The clean target will be brought up to date. clean has no dependencies, so the command rm *.o core will always be executed.


Make supports a simple string substitution macro. Set it with:

MY_MACRO = nothing today

and refer to it with:


The convention is to put the macros near the top of your Makefile and to use upper case. Also, use separate macros for the name of your compiler and the flags it needs:

F90 = f90
F90FLAGS = -O3
LIBDIR = /usr/local/lib
LIBS = -L$(LIBDIR) -lmylib

Let's rewrite our Makefile using macros:

# IBM version
F90 = xlf90
F90FLAGS = -O3 -qstrict
LDFLAGS = -bmaxdata:0x40000000

model: main.o init.o plot.o
<TAB> $(F90) $(LDFLAGS) -o model main.o init.o plot.o

main.o: main.f
<TAB> $(F90) -c $(F90FLAGS) main.f

init.o: init.f
<TAB> $(F90) -c $(F90FLAGS) init.f

plot.o: plot.f
<TAB> $(F90) -c $(F90FLAGS) plot.f

<TAB> rm *.o core

Now when we change computers, we only have to change the compiler name in one place. Likewise, if we want to try different optimization levels, we only specify that in one place.

By the way, you can use comments by starting the line with a #

Implicit Rules

Make has some rules already built in. For fortran, you might be able to get away with:

OBJS = main.o init.o plot.o

model: $(OBJS)
<TAB> $(FC) $(LDFLAGS) -o model $(OBJS)

as your whole Makefile. Make will automatically invoke its default Fortran compiler, possibly f77or g77, with whatever default compile options it happens to have (FFLAGS). One built in rule often looks like:

<TAB> $(CC) $(CFLAGS) -c $<

which says to compile .c files to .o files using the compiler CC and options CFLAGS. We can write our own suffix rules in this same style. The only thing to watch for is that make by default has a limited set of file extensions that it knows about. Let's write our Makefile using a suffix rule:

# Cray version
F90 = f90
F90FLAGS = -O3

<TAB> $(F90) $(F90FLAGS) -c $<

model: main.o init.o plot.o
<TAB> $(F90) $(LDFLAGS) -o model main.o init.o plot.o

<TAB> rm *.o core


There may be additional dependencies beyond the source->object ones. In our little example, all our source files include a file called commons.h. If commons.h gets modified to add a new variable, everything must be recompiled. Make won't know that unless you tell it, using the syntax:

# include dependencies
main.o: commons.h
init.o: commons.h
plot.o: commons.h

Fortran 90 introduces module dependencies as well, but we'll save them for another day.

In conclusion, make is a very powerful tool. The book to read is "Managing projects with make" by Andrew Oram and Steve Talbott, 1991, O'Reilly.

Make has a portable subset of features, with system-dependent extensions. If you want to use extensions, I suggest sticking with those supported by gnu make (gmake), since it is available most everywhere.

The most common newbie mistake is to forget that the commands after a target *have* to start with a tab.

Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 1 post ] 

All times are UTC

Who is online

Users browsing this forum: No registered users and 1 guest

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group