Victor
Victor

Reputation: 63

Fortran: makefile with already compiled modules

I have a project structure like this

-Project

 --Common

  ---types.f90

  ---global.f90

  ---common_routines.f90

 --Program 1

  ---program1.f90

  ---module1.f90

  ---module2.f90

  ---etc...

 --Program 2

 --etc...

Where, Common is folder that contains some modules that are shared across all programs. How do I include this modules on my makefile?

I tried this:

FC = gfortran
FCFLAGS = -fbounds-check -O3
FCFLAGS += -I ../Common

all: program1

program1: module1.o module2.o module3.o

program1.o: module1.o module2.o module3.o

module2.o: module1.o

module3.o: module2.o module1.o

%: %.o
    $(FC) $(FCFLAGS) -o $@ $^ 

%.o: %.f90
    $(FC) $(FCFLAGS) -c $<

clean:
    rm -rf *.o *.mod

but I get an undefined reference error to the common modules variables.

Upvotes: 1

Views: 197

Answers (2)

Mike Kinghan
Mike Kinghan

Reputation: 61282

I tried FCFLAGS += -I../Common types.o global.o common_routines.o

This will not work because -I is an option to the GNU Fortran preprocessor to specify a path that the preprocessor shall search for files to be INCLUDE-ed prior to compilation. You cannot use it to specify a path where object files (*.o) will be searched for, after compilation, by the linker. It means nothing to the linker and is not passed to the linker.

For simplicity let's assume that the object files you need to to link for program1 are just program1/program1.o plus the pre-existing common/types.o, common/global.o and common/common_routines.o

Then the following Makefile, placed in directory program1, will build it:

OBJS = program1.o ../common/types.o ../common/global.o ../common/common_routines.o

.phony: all

all: program1

program1: program1.o
    $(FC) -o $@ $(FCFLAGS) $(OBJS) 

clean:
    rm -f *.o program1

Just list all the required object files to the linker, in this case via $(OBJS)

You might wish to take the precaution of making sure that the common modules are up to date before you build program1, and you now might think that you can do that simply be replacing:

program1: program1.o

with:

program1: $(OBJS)

thus prompting make to recompile any of the four object files that is out of date with respect to the corresponding source file, as a prerequisite of building program1

make will certainly endeavour to do that, but take care. That way, it will recompile, say, ../common/types.o from ../common/types.f90 just by its implicit default recipe for making an .o from an .f90, since this makefile is not telling it to do any different. But that may not be the way in which ../common/types.f90 is meant to be compiled, if you also have is a makefile in common that stipulates how to do it in some non-default manner.

In that case, the common object files should always be compiled as per the makefile in common. Better leave the prerequisites of program1 alone but change the recipe to:

program1: program1.o
    $(MAKE) -C ../common
    $(FC) -o $@ $(FCFLAGS) $(OBJS)

Now, any time program1 needs to be rebuilt, the recipe will preemptively run make in ../common before it links the four object files. (It's a small inelegance that this $(MAKE) -C ../common will be invoked even if there's nothing for it to do: this is avoidable by more advanced make usage).

Lastly you might also find a need (if not in this case, then in another) to distinguish between flags passed to preprocessing and/or flags passed to compilation and/or flags passed to linkage. Conventionally, these are assigned to distinct make variables, e.g. FPPFLAGS (preprocessor), FCFLAGS (compiler), LDFLAGS (linker).

Upvotes: 2

Peter Petrik
Peter Petrik

Reputation: 10165

The GNU syntax to define additional include directory is -Idir not -I dir (extra space)

Also make sure that common modules are already compiled and include search path points to the directory where you have compiled modules, not source files:

This path is also used to search for .mod files when previously compiled modules are required by a USE statement.

Upvotes: 0

Related Questions