Thomas Wening
Thomas Wening

Reputation: 131

Autotools and Fortran Modules

I have a problem writing a Makefile.am that will make autotools compile files in the correct order.

My minimal example is some test.f90 which uses routines from a module mod.f90. By hand, I do the following.

gfortran -c mod.f90
gfortran -c test.f90
gfortran -o test test.o mod.o

This works fine. Now, I have read that autotools does not handle Fortran module dependencies and, according to this post (automake with fortran: order of file) one should just put the dependencies into Makefile.am by hand.

Mine looks like the following.

AUTOMAKE_OPTIONS = foreign
bin_PROGRAMS = test
test_SOURCES = mod.f90 test.f90 
test: test.f90 mod.o
mod.o: mod.f90

While the .mod file for the module is generated each time I run ./configure && make, it is apparently not generated before all the other files, i.e. I still get the error message Fatal Error: Cannot open module file ‘mod.mod’ for reading at (1): No such file or directory.

Running ./configure && make twice in a row allows the programme to be compiled but of course this is not really a satisfying solution. Is there some standard way to deal with this? Can I maybe somehow force mod.o to be compiled before test.o?

Upvotes: 2

Views: 481

Answers (1)

John Bollinger
John Bollinger

Reputation: 181149

The second of these two lines is redundant in light of the first:

test_SOURCES = mod.f90 test.f90 
test: test.f90 mod.o

This one is unneeded, because Automake (and GNU make) already know the information it conveys:

mod.o: mod.f90

That effectively leaves you with just this:

AUTOMAKE_OPTIONS = foreign
bin_PROGRAMS = test
test_SOURCES = mod.f90 test.f90

That's ok as far as it goes, but it does not express any dependency information related to the mod.mod file, so builds may fail. To fix that, you need to add one or more rules that express the additional dependencies and how to satisfy them.

The true dependency is that test.o depends on mod.mod, and you could write a dependency-only rule expressing that:

# INSUFFICIENT
test.o: mod.mod

But that leaves you with a problem: make doesn't know that mod.mod is an output of the compilation of mod.f90. Indeed, situations where multiple targets are created by one run of a recipe are problematic to describe to make (and Automake). The Automake manual devotes one of its lengthier sections to this issue. The most robust possible build system would use an approach such as that section describes to express how to build mod.o and mod.mod, but that would about triple the size of your Makefile.am, and you would need similar extra code for every Fortran module.

You can achieve a fairly good workaround by instead telling Automake that test.o depends on mod.o:

# Better
test.o: mod.o

That will yield successful builds from scratch, and under most normal development circumstances, but it does express an incorrect dependency. As a result, it is susceptible to build breakage by, for example, building the project, then removing mod.mod (leaving mod.o in place) and updating test.f90. On subsequent builds, make will then see that mod.o is up to date, so it will do nothing to regenerate the missing mod.mod. A clean build would rescue that, and as a developer, I would probably be prepared to accept that situation for the sake of Makefile.am simplicity.

Speaking of a clean build, you should also add mod.mod to the list of files that make clean should remove:

CLEANFILES = mod.mod

Overall, then, the final result is:

AUTOMAKE_OPTIONS = foreign

bin_PROGRAMS = test

test_SOURCES = mod.f90 test.f90

# A fib -- the real dependency is test.o: mod.mod
test.o: mod.o

CLEANFILES = mod.mod

Upvotes: 2

Related Questions