19

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
Bob
  • 263
  • 1
  • 3
  • 6
  • Make is just a way to automate tasks you could do by hand. Can you compile this code on the command line, without Make? If not, then fiddling with the makefile won't help. – Beta May 03 '11 at 15:24
  • 5
    You are applying the link flags to the compilation, and vice versa. –  May 03 '11 at 15:26
  • There are too many source and header files with too many dependencies for me to do this by hand. unapersson, you are correct. I foolishly switched those two variables. Switching them back allowed me to build the .f files. gfortran is giving me errors for the .h files though. It seems to think they are C files. But that's another question. Thanks for the help. – Bob May 03 '11 at 15:49
  • It looks like you are trying to build your `*.h` files, which you shouldn't need to do. If I remember correctly, the `$<` under `%.mod: *.h` will pick out the first `*.h` file. Maybe you want to lead with `*.F` files that contain modules? (though I must confess I've never worried about `*.mod`s in my makefiles) – marshall.ward May 04 '11 at 01:03
  • Keen observation, MLW. I posted again about this and found that to be one of the problems. There are no modules in this legacy code, actually and I was mistaken in trying to compile *.h files (I'm not used to working with them). I will put my latest makefile in my original question. – Bob May 05 '11 at 13:16
  • Note: GNU Make uses the implicit Fortran flag variable `FFLAGS` http://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html – Mike T May 07 '13 at 09:45
  • 1
    Also, I want to add to the comments that the final solution to this question may not work for F90, F2003 and F2008 source files because using modules imposes dependencies and then object "*.o" files have their own dependencies and they need to be reordered in a special way. In this general case, the solution is posted in http://stackoverflow.com/questions/25705273/automatic-ordering-of-obejct-files-o-in-a-fortran-makefile. – argasm Sep 12 '14 at 19:06

1 Answers1

14

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.

sverre
  • 6,768
  • 2
  • 27
  • 35
  • 3
    Yes, this is perfect. I made the change and it worked. The final, working makefile is posted in my original question. Funny thing is, I actually tracked down a makefile for this code in my office the other day. However, it's like 20 times longer than mine because they list each individual dependency. Very glad I learned the right way to do this. – Bob May 09 '11 at 14:28
  • Typically folks use `$(FFLAGS)` instead of `$(FLFLAGS)` – Mike T Jun 26 '16 at 10:19