Fortran makefile recompiling every time - makefile

I'm trying to write a Fortran makefile: there is a single "main" file, but I've placed my modules in separate .f90 files. The makefile attached works, however even if I make no changes it forces a recompile. I'm running x86-64 Linux with gfortan 4.7.2 and GNU Make 3.81.
FC = gfortran
FCFLAGS += -ffree-line-length-none -finit-local-zero
#FCFLAGS += -fbounds-check -ffpe-trap=invalid
all: new
new: ALE.o curvilinear.o new.o
$(FC) $(FCFLAGS) -o new new.o ALE.o curvilinear.o
new.o: ALE.mod curvilinear.mod new.f90
$(FC) $(FCFLAGS) -c new.f90
ALE.o: ALE.f90
$(FC) $(FCFLAGS) -c ALE.f90
ALE.mod: ALE.o ALE.f90
curvilinear.o: ALE.o curvilinear.f90
$(FC) $(FCFLAGS) -c curvilinear.f90
curvilinear.mod: curvilinear.o curvilinear.f90
clean:
rm ale.mod curvilinear.mod ALE.o curvilinear.o new new.o
Output:
$ make clean
rm ale.mod curvilinear.mod ALE.o curvilinear.o new new.o
$ make
gfortran -ffree-line-length-none -finit-local-zero -c ALE.f90
gfortran -ffree-line-length-none -finit-local-zero -c curvilinear.f90
gfortran -ffree-line-length-none -finit-local-zero -c new.f90
gfortran -ffree-line-length-none -finit-local-zero -o new new.o ALE.o curvilinear.o
$ make
gfortran -ffree-line-length-none -finit-local-zero -c new.f90
gfortran -ffree-line-length-none -finit-local-zero -o new new.o ALE.o curvilinear.o
Why is "new" being recompiled when no changes have been made?

Didier's answer probably already solves your question, but I would like to add a nice and clean suggestion for Fortran makefiles (example for one main program):
# Main program
all: program
program: mod1.o mod2.o mod3.o
# Fortran module dependencies
mod1.o: mod2.o mod3.o
# Binary/object rules
%: %.o
$(FC) $(FCFLAGS) -o $# $^ $(LDFLAGS)
%.o: %.f90
$(FC) $(FCFLAGS) -c $<

As per your Makefile, new.o depends on ALE.mod and curvilinear.mod.
I guess these file do never exist, as they have dependencies, but no rule to make them.
Indeed, When trying to build new, make does not found the *.mod files. Hence, make runs the rules to make them, but there's no rule. However, make think that it has build them, and continues the build operation, thinking that these *.mod dependencies have been just rebuild, and are thus recent, triggering the rebuild of new.
To fix this, you should replace the line
new.o: ALE.mod curvilinear.mod new.f90
by
new.o: new.f90

Related

Can't use LAPACK in makefile

I have program (in fortran) where I'm using three custom modules, which make use of LAPACK. Until now I've compiled my program using the following shell script:
filestring="main"
gfortran -c mod_exp.f90 mod_genmat.f90 mod_print.f90 $filestring.f90
gfortran mod_exp.o mod_genmat.o mod_print.o $filestring.o -llapack -lblas
rm mod_exp.o mod_genmat.o mod_print.o $filestring.o exponentiate.mod genmat.mod printing.mod printing_subrtns.mod
mv a.out $filestring
Since I've been using more and more modules and different programs using them, I've decided to start using makefiles. Following a tutorial, I managed to write the following:
FC = gfortran
FFLAGS = -Wall -Wextra -llapack -lblas #-fopenmp
SOURCES = mod_print.f90 mod_genmat.f90 mod_exp.f90 main.f90
OBJ = ${SOURCES:.f90=.o} #substitute .f90 with .o
%.o : %.f90 #creation of all *.o files DEPENDS on *.f90
$(FC) $(FFLAGS) -c -O $< -o $#
main: $(OBJ)
$(FC) $(FFLAGS) -o $# $(OBJ)
clean:
#rm -f *.o *.mod main
However, when executing make, it says that the LAPACK functions are not recognized. One such mistake is the following:
/usr/bin/ld: mod_exp.o: in function `__exponentiate_MOD_diagun':
mod_exp.f90:(.text+0x37f): undefined reference to `zgees_'
...
collect2: error: ld returned 1 exit status
One possible mistake I've seen is that I need to specify the location of the libraries. However, it would seem strange since I didn't need to do it before; also, I don't know how to find it.
Please show the link command that make invoked, that caused the error to be generated.
I'm confident that if you cut and paste that exact command line to your shell prompt, you will get the same error you see when make runs it. So the problem is not make, but your link command.
The problem is that you have put the libraries before the objects in the link line. Libraries should come at the end, after the objects, else when the linker examines the libraries it doesn't know what symbols will need to be included (because no objects have been parsed yet to see what symbols are missing).
This is why LDLIBS is traditionally a separate variable:
FC = gfortran
FFLAGS = -Wall -Wextra #-fopenmp
LDLIBS = -llapack -lblas
SOURCES = mod_print.f90 mod_genmat.f90 mod_exp.f90 main.f90
OBJ = ${SOURCES:.f90=.o} #substitute .f90 with .o
%.o : %.f90 #creation of all *.o files DEPENDS on *.f90
$(FC) $(FFLAGS) -c -O $< -o $#
main: $(OBJ)
$(FC) $(FFLAGS) -o $# $(OBJ) $(LDLIBS)

makefile fortran multiple directories

This has been asked many times but from none of the answers can I figure out how to do it.
Simply put, I have directory structure: SRC/ for all *.for and *.f90 files, BLD/ for all files needed for building (that is *.o and *.mod) and lib/ for necessary libraries that need to be linked.
I want to build all source files in the SRC/ directory and put *.o and *.mod to the BLD/ directory while keeping the executable in the root where makefile is. I don't want to have multiple makefiles. The current makefile that does not work is below. I think that one issue there are lines that refere e.g. $(BLD)/$(objects) which probably expands to BLD/nrtype.o nrutil.o nr.o mtypes.o polint.o polyin2.o a.o but I am not really sure, and I am just trying and erroring since I do not have enough knowledge and the manuals are not clear for me to be able to figure it out. In one of the trials, *.mod some got to BLD/ some stayed in the root, it seems that the rules do not work I think they do.
# Compilation related variables
SRC = src
BLD = build
LIB = lib
FC = gfortran
LDFLAGS = $(LIB)/asm_functions.o
FFLAGS = -O0
# the name of the output executable
target = a
# all objects to generate
objects = nrtype.o nrutil.o nr.o mtypes.o polint.o polyin2.o a.o
#
modules = nrtype.mod nrutil.mod nr.mod mtypes.mod
# set module dependencies
nrtype_mod = polint.o polyin2.o
nrutil_mod = polint.o polyin2.o
nr_mod = polin2.o
mtypes_mod = a.o
# set default target
default: $(target)
# add dependencies to the targets
$(nrtype_mod): nrtype.mod
$(nrutil_mod): nrutil.mod
$(nr_mod): nr.mod
$(mtypes_mod): mtypes.mod
# compile modules
$(BLD)/%.mod: $(SRC)/%.f90 $(BLD)/%.o
$(FC) -c $(FFLAGS) -o $# $<
# compile old fortran files
$(BLD)/%.o: $(SRC)/%.for
$(FC) -c $(FFLAGS) -o $# $<
# compile new fortran files
$(BLD)/%.o: $(SRC)/%.f90
$(FC) -c $(FFLAGS) -o $(BLD)$# $<
# link everything
$(target): $BLD/$(objects)
$(FC) -o $# $(FFLAGS) $^ $(LDFLAGS)
# cleaning up
clean:
rm -f $(BLD)/$(objects) $(BLD)/$(modules)
clobber: clean
rm -f $(BLD)/$(target)
.PHONY: default clean clobber
Update
I edited the makefile to the form:
# Compilation related variables
SRC = src
BLD = build
LIB = lib
FC = gfortran
LDFLAGS = $(LIB)/asm_functions.o
FFLAGS = -O0
# the name of the output executable
target = a
# all objects to generate
objects = $(BLD)/nrtype.o $(BLD)/nrutil.o $(BLD)/nr.o $(BLD)/mtypes.o $(BLD)/polint.o $(BLD)/polyin2.o $(BLD)/a.o
#
modules = $(BLD)/nrtype.mod $(BLD)/nrutil.mod $(BLD)/nr.mod $(BLD)/mtypes.mod
# set module dependencies
nrtype_mod = polint.o polyin2.o
nrutil_mod = polint.o polyin2.o
nr_mod = polin2.o
mtypes_mod = a.o
# set default target
default: $(target)
# add dependencies to the targets
$(nrtype_mod): nrtype.mod
$(nrutil_mod): nrutil.mod
$(nr_mod): nr.mod
$(mtypes_mod): mtypes.mod
# compile modules
$(BLD)/%.mod: $(SRC)/%.f90 $(BLD)/%.o
$(FC) -c $(FFLAGS) -o $# $<
# compile old fortran files
$(BLD)/%.o: $(SRC)/%.for
$(FC) -c $(FFLAGS) -o $# $<
# compile new fortran files
$(BLD)/%.o: $(SRC)/%.f90
$(FC) -c $(FFLAGS) -o $# $<
# link everything
$(target): $(objects)
$(FC) -o $# $(FFLAGS) $^ $(LDFLAGS)
# cleaning up
clean:
rm -f $(BLD)/$(objects) $(BLD)/$(modules)
clobber: clean
rm -f $(BLD)/$(target)
.PHONY: default clean clobber
While with this modification the build is successful, it is still not obeying orders. Specifically, *.mod files are being generated where the makefile is but I found in the meantime that it is gfortran who is disobedient and for mod files the output directory is controlled by some other switch. Nevertheless:
Other things that are not clear:
Should the lines look like:
$(BLD)/%.o: $(SRC)/%.for
$(FC) -c $(FFLAGS) -o $# $<
Or
%.o: %.f90
$(FC) -c $(FFLAGS) -o $(BLD)/$# $(SRC)/$<
or is it the same (i prefer the second one for readability).
Why the line such as
nrtype_mod = polint.o polyin2.o
do not need to be prepended by the paths? Or do they have to be (but it built correctly). This is where it is very confusing.
The maual would really benefit from some basic examples of a full makefile.
I think that one issue there are lines that refere e.g. $(BLD)/$(objects) which probably expands to BLD/nrtype.o nrutil.o nr.o mtypes.o polint.o polyin2.o a.o
You are exactly correct in your assessment here.
You can use a GNU make function like addprefix to fix this.
It would be useful to understand what part of the manual you had trouble understanding, so it can be improved.

Make did not work after I changed my file

These are my files:
add.c add.h main.c makefile
This is makefile:
main:main.o add.o
gcc -o main main.o add.o
main.o:$(#:%.o=%.c)
gcc -o main.o -c main.c
add.o:$(#:%.o=%.c) $(#:%.o=%.h)
gcc -o add.o -c add.c
.PHONY:clean
clean:
rm *.o -rf
rm main -rf
Then after I change the main.c and make.
But make told me this:
make: `main' is up to date.
If I change my makefile:
main:main.o add.o
gcc -o main main.o add.o
main.o:main.c
gcc -o main.o -c main.c
add.o:$(#:%.o=%.c) $(#:%.o=%.h)
gcc -o add.o -c add.c
.PHONY:clean
clean:
rm *.o -rf
rm main -rf
Then after I change the main.c and make.
It can work.
I donot know the reason.
The dependencies in
main.o:$(#:%.o=%.c)
add.o:$(#:%.o=%.c) $(#:%.o=%.h)
are not valid make syntax.
Replace these two rules with one pattern (generic) rule:
%.o : %.c
gcc -c -o $# ${CPPFLAGS} ${CFLAGS} $<
The above rule is actually very similar to the built-in rule for compiling .o files from .c:
Compiling C programs
n.o is made automatically from n.c with a recipe of the form $(CC) $(CPPFLAGS) $(CFLAGS) -c.
In other words, you can remove your original rules for main.o and add.o and it should build correctly.

Creating a FORTRAN makefile

I have a FORTRAN source code consisting of many different .F and .h files. I need to build an executable from it, but I'm having some problems. The makefile that I produced so far (which may have errors as I'm new to this) is:
# compiler
FC = /usr/bin/gfortran-4.5
# compile flags
FCFLAGS = -g -c -fdefault-real-8 -fbacktrace -fno-align-commons
# link flags
FLFLAGS = -g -fbacktrace
# source files and objects
SRCS = $(patsubst %.F, %.o, $(wildcard *.F)) \
$(patsubst %.h, %.mod, $(wildcard *.h))
# program name
PROGRAM = blah
all: $(PROGRAM)
$(PROGRAM): $(SRCS)
$(FC) $(FCFLAGS) $# $<
%.o: %.F
$(FC) $(FLFLAGS) -o $# $<
%.mod: %.h
$(FC) $(FLFLAGS) -o $# $<
clean:
rm -f *.o *.mod
When I try to make the program, however, I'm getting a slew of undefined reference errors. I mean, every function and subroutine call in the very first compiled .F file gives back an undefined reference error. I thought this was because gfortran was trying to link the files instead of just compiling them and then linking at the end, but I thought the '-c' option was supposed to prevent that.
UPDATE:
As commenters have pointed out, I mixed up the compile and link flags. Furthermore, you shouldn't compile *.h files. Here is the latest, corrected makefile:
# compiler
FC = /usr/bin/gfortran-4.4
# compile flags
FCFLAGS = -g -c -fdefault-real-8 -fbacktrace -fno-align-commons -fbounds-check -std=legacy
# link flags
FLFLAGS =
# source files and objects
SRCS = $(patsubst %.F, %.o, $(wildcard *.F))
# program name
PROGRAM = blah
all: $(PROGRAM)
$(PROGRAM): $(SRCS)
$(FC) $(FLFLAGS) -o $# $<
%.o: %.F
$(FC) $(FCFLAGS) -o $# $<
clean:
rm -f *.o *.mod
Now when I run make, it will compile each *.F file in the code, but it fails at the linking stage. I get a bunch of undefined reference errors in the very first *.F file. The compiler seems to be going over each *.F file individually in the linking stage, which I'm not sure is correct. Then I get an error:
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/libgfortranbegin.a(fmain.o): In function `main':
(.text+0x26): undefined reference to `MAIN__'
collect2: ld returned 1 exit status
However, if I type the command:
gfortran -o blah *.o
The executable will be built, so it seems like I did something wrong in the makefile for the linking stage.
UPDATE: 5/9/2011
Sverre pointed out the final problem with my makefile. In my first target that builds the program, I use the shortcut command for only the first dependency ($<), but I need to include all dependencies (i.e. all *.o files) using the ($^) shortcut. The final, working makefile is as follows:
# compiler
FC := /usr/bin/gfortran-4.5
# compile flags
FCFLAGS = -g -c -fdefault-real-8 -fbacktrace -fno-align-commons -fbounds-check
# link flags
FLFLAGS =
# source files and objects
SRCS = $(patsubst %.F, %.o, $(wildcard *.F))
# $(patsubst %.h, %.mod, $(wildcard *.h))
# program name
PROGRAM = vipre
all: $(PROGRAM)
$(PROGRAM): $(SRCS)
$(FC) $(FLFLAGS) -o $# $^
%.o: %.F
$(FC) $(FCFLAGS) -o $# $<
# %.mod: %.h
# $(FC) $(FCFLAGS) -o $# $<
clean:
rm -f *.o *.mod
Are you using GNU make? If so,
$(FC) $(FLFLAGS) -o $# $<
may be the culprit. $< is the name of the first prerequisite, but you want all the *.o files. Try using $^ instead.

How to define rules in the Makefile to compile only that *.cpp files which was modified (and their dependencies), not all *.cpp files

Lets say I have files:
Libs:
one.cpp, one.h
two.cpp, two.h
three.cpp, three.h
Program:
program.cpp
Is there way, to create Makefile which will compile only that *.cpp which were modified from last compilation?
Currently I have something like that:
SRCS = one.cpp two.cpp three.cpp
OBJS = $(SRCS:.cpp=.o)
all: $(OBJS) program
.cpp.o:
g++ -Wall -c $<
program:
g++ -Wall $(OBJS) program.cpp -o program
clean:
rm -f $(OBJS) program
I works fine, but when I compile my program and then change two.cpp or two.h I need to run "make clean" first, because when I secondly run "make" I get:
Nothing to be done for 'all'.
I would like to change my Makefile in that way, it would recognize my changes and recompile that file and its dependencies (if one.cpp uses code from two.cpp which was modified, both files should be recompiled).
So if I modify two.cpp, make should do:
g++ -Wall -c two.cpp
g++ -Wall $(OBJS) program.cpp -o program
But if one.cpp uses code from two.cpp which was modified, make shold do:
g++ -Wall -c one.cpp
g++ -Wall -c two.cpp
g++ -Wall $(OBJS) program.cpp -o program
First we make the object files prerequisites of the executable. Once this is done, Make will rebuild program whenever one of the SRCS changes, so we don't need OBJS as an explicit target:
all: program
program: $(OBJS)
g++ -Wall $(OBJS) program.cpp -o program
Then we make the header files prerequisites of the objects, so that if we change three.h, Make will rebuild three.o:
$(OBJS): %.o : %.h
And finally since one.cpp uses code from two.cpp by means of two.h (I hope), we make two.h a prerequisite of one.o:
one.o: two.h
And to make things cleaner and easier to maintain we use automatic variables:
program: $(OBJS)
g++ -Wall $^ program.cpp -o $#
Put it all together and we get:
SRCS = one.cpp two.cpp three.cpp
OBJS = $(SRCS:.cpp=.o)
all: program
$(OBJS): %.o : %.h
one.o: two.h
.cpp.o:
g++ -Wall -c $<
program: $(OBJS)
g++ -Wall $^ program.cpp -o $#
clean:
rm -f $(OBJS) program
There are a few more things we could do (like adding program.o to OBJS), but this is enough for today.
Add the files a command depends upon to run to the right of the target name.
Example:
default: hello.c
gcc -o hello.bin hello.c
install: hello.bin
cp hello.bin ../
All you need to do is tell make that the .o file depends on the .cpp file:
%.cpp.o: %.cpp
g++ -Wall -c -o $# $<

Resources