CMake Fortran Issues
Introduction
CMake has a number of Fortran issues that have been discussed many different times on list and duplicated a fair number of times in the bug tracker as well.
Maik Beckmann is trying to make sense of all the confusion by collecting information on all Fortran issues at http://www.cmake.org/Bug/view.php?id=5809
Please join the work there by
- Contributing patches.
- Testing the patches that already exist there.
- Reporting things that don't work.
- Sending simplified examples of things which don't work.
- Sharing your expert knowledge of CMake.
Concepts expressed using Makefiles
This section is intended to discuss the makefile rules which CMake has to generate.
A simple program
A f9x program which is build by compiling in linking two source files a.f90 and main.f90. The tree structure is:
- example_simpleProgram
- build
- Makefile
- prog.dir
- build.make
- main.f90
- a.f90
- build
a.f90:
SUBROUTINE printHello WRITE(*,*) "Hello f9x world" END SUBROUTINE
main.f90:
PROGRAM hello CALL printHello END PROGRAM
Makefile:
all: prog.dir/all prog.dir/all: $(MAKE) -f prog.dir/build.make prog.dir/all clean: $(MAKE) -f prog.dir/build.make prog.dir/clean
build.make:
prog.dir/all: prog.dir/prog prog.dir/prog: prog.dir/a.o prog.dir/main.o gfortran -o prog.dir/prog prog.dir/a.o prog.dir/main.o prog.dir/a.o: ../a.f90 gfortran -o prog.dir/a.o -c ../a.f90 prog.dir/main.o: ../main.f90 gfortran -o prog.dir/main.o -c ../main.f90 prog.dir/clean: rm prog.dir/a.o prog.dir/main.o prog.dir/prog
Now change into build and type
- $ make
to build. The current CMake is able to build the same without any problems. This is also valid for any fortran code that doesn't use modules.
You can download this example as tarball example_simpleProgram.tar.gz at http://www.cmake.org/Bug/view.php?id=5809
A simple program with module
The same as before, but now a.f90 provides a module which main.f90 uses. The tree structure is:
- example_simpleProgram_withModule
- build
- Makefile
- prog.dir
- build.make
- main.f90
- a.f90
- build
a.f90:
MODULE localMod ! CONTAINS SUBROUTINE printHello WRITE(*,*) "Hello f9x world" END SUBROUTINE END MODULE
main.f90:
PROGRAM hello USE localMod CALL printHello END PROGRAM
Makefile:
all: prog.dir/all prog.dir/all: $(MAKE) -f prog.dir/build.make prog.dir/all clean: $(MAKE) -f prog.dir/build.make prog.dir/clean
build.make:
prog.dir/all: prog.dir/prog prog.dir/prog: prog.dir/a.o prog.dir/main.o gfortran -o prog.dir/prog prog.dir/a.o prog.dir/main.o prog.dir/a.o: ../a.f90 gfortran -o prog.dir/a.o -c ../a.f90 -M prog.dir prog.dir/localmod.mod: prog.dir/a.o prog.dir/main.o: ../main.f90 prog.dir/localmod.mod gfortran -o prog.dir/main.o -c ../main.f90 -I prog.dir prog.dir/clean: rm prog.dir/localmod.mod prog.dir/a.o prog.dir/main.o prog.dir/prog
Now change into build and type
- $ make
to build. This is nothing the current CMake can't do. Now do (you're at the build directory)
$ touch ../a.f90
and enter
$ make
again. You'll see that a.f90 is recompiled, like the current CMake does, but main.f90 is recompiled too! This is different from current CMake, but its the right way, since a module dependency is a compile time dependency like an include.
Executable depending on external lib
This example build a executable target which
- provides a module
- uses the provided module
- uses a module of a external library
structure:
- example_dependingOn_externalLib
- extLib
- include
- externalmod.mod
- lib
- libmylib.a
- include
- myproject
- build
- Makefile
- prog.dir
- build.make
- a.f90
- main.f90
- build
- extLib
You can download this example as tarball example_dependingOn_externalLib.tar.gz
at http://www.cmake.org/Bug/view.php?id=5809 . The extlib folder contains the source and a Makefile to build and install the lib by typing
- $ make install
Now the contents of myproject
a.f90:
MODULE localMod ! CONTAINS SUBROUTINE printLocalModGreeting WRITE(*,*) "Greetings from Module localMod" END SUBROUTINE END MODULE
main.f90:
PROGRAM hello USE localMod USE externalMod CALL printLocalModGreeting CALL printExtModGreeting END PROGRAM
Makefile:
all: prog.dir/all prog.dir/all: $(MAKE) -f prog.dir/build.make prog.dir/all clean: $(MAKE) -f prog.dir/build.make prog.dir/clean
build.make:
prog.dir/all: prog.dir/prog prog.dir/prog: prog.dir/a.o prog.dir/main.o gfortran -o prog.dir/prog prog.dir/a.o prog.dir/main.o ../../extLib/lib/libmylib.a prog.dir/a.o: ../a.f90 gfortran -o prog.dir/a.o -c ../a.f90 -M prog.dir prog.dir/localmod.mod: prog.dir/a.o prog.dir/main.o: ../main.f90 prog.dir/localmod.mod gfortran -o prog.dir/main.o -c ../main.f90 -I prog.dir -I ../../extLib/include prog.dir/clean: rm prog.dir/localmod.mod prog.dir/a.o prog.dir/main.o prog.dir/prog
Executable target depending on lib target
structure:
- example_depending_libTarget
- build
- Makefile
- lib.dir
- build.make
- libmodx.mod.stamp
- libmody.mod.stamp
- prog.dir
- build.make
- lib
- a.f90
- b.f90
- prog
- a.f90
- main.f90
- build
contents...
lib/a.f90:
MODULE libModX USE libModY END MODULE
lib/b.f90:
MODULE libModY END MODULE
prog/a.f90:
MODULE localMod END MODULE
prog/main.f90:
PROGRAM hello USE localMod USE libModX WRITE(*,*) 'Hello, F90 world.' END PROGRAM
build/Makefile:
all: lib.dir/all prog.dir/all lib.dir/all: $(MAKE) -f lib.dir/build.make prog.dir/all: lib.dir/all $(MAKE) -f prog.dir/build.make
build/lib.dir/build.make:
lib.dir/all: lib.dir/mylib lib.dir/mylib: lib.dir/libmylib.a lib.dir/libmylib.a: lib.dir/a.o lib.dir/b.o ar rc lib.dir/libmylib.a lib.dir/a.o lib.dir/b.o ranlib lib.dir/libmylib.a lib.dir/a.o: ../lib/a.f90 lib.dir/libmody.mod gfortran -o lib.dir/a.o -c ../lib/a.f90 -M lib.dir touch lib.dir/libmodx.mod.stamp lib.dir/b.o: ../lib/b.f90 gfortran -o lib.dir/b.o -c ../lib/b.f90 -M lib.dir touch lib.dir/libmody.mod.stamp lib.dir/libmodx.mod: lib.dir/a.o lib.dir/libmody.mod: lib.dir/b.o lib.dir/clean: rm lib.dir/a.o lib.dir/b.o lib.dir/libmylib.a rm lib.dir/libmodx.mod lib.dir/libmody.mod
build/prog.dir/build.make
prog.dir/all: prog.dir/prog prog.dir/prog: prog.dir/main.o prog.dir/a.o gfortran -o prog.dir/prog prog.dir/main.o prog.dir/a.o lib.dir/libmylib.a prog.dir/a.o: ../prog/a.f90 gfortran -o prog.dir/a.o -c ../prog/a.f90 -M prog.dir prog.dir/localmod.mod: prog.dir/a.o prog.dir/main.o: lib.dir/libmodx.mod.stamp prog.dir/main.o: ../prog/main.f90 prog.dir/localmod.mod gfortran -o prog.dir/main.o -c ../prog/main.f90 -I lib.dir -I prog.dir prog.dir/clean: rm prog.dir/a.o prog.dir/main.o prog.dir/prog prog.dir/localmod.mod
Finally: Executable target depending on lib target and external lib
structure:
- example_final
- extLib
- include
- externalmod.mod
- lib
- libmyextlib.a
- include
- myproject
- build
- Makefile
- lib.dir
- build.make
- libmodx.mod.stamp
- libmody.mod.stamp
- prog.dir
- build.make
- lib
- a.f90
- b.f90
- prog
- a.f90
- main.f90
- build
- extLib