CMake Fortran Issues

From KitwarePublic
Jump to navigationJump to search

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. All examples are fully working. To build one change into the corresponding build folder and enter

$ make

Simply building isn't the fancy part. Now try to touch a sourcefile of your choise and check if the build order is right.


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

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

The rules generated by the current CMake covers all dependencies which can occur as long as no modules are used.

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

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

rules like they are generated by current CMake

Makefile:

all: prog.dir/all

prog.dir/all:
	$(MAKE) -f prog.dir/build.make prog.dir/requires
	$(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 
	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
	
	
localmod.mod.proxy: prog.dir/a.o

prog.dir/main.o.requires: localmod.mod.proxy
	
prog.dir/requires: prog.dir/main.o.requires

After you build prog using this set of Makefiles do (you're at the build directory)

 $ touch ../a.f90

and enter

 $ make

You'll see that a.f90 is recompiled and prog.dir/prog is linked again. But main.f90 has to recompiled too, since a module dependency is a compile time dependency like an include.

rules like they could be generated

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

After you build prog using this set of Makefiles do (you're at the build directory)

 $ touch ../a.f90

and enter

 $ make

You'll see that a.f90 is recompiled, like the current CMake does, but main.f90 is recompiled too, as it should be.

Executable depending on external lib

This example build a executable target which

  1. provides a module
  2. uses the provided module
  3. uses a module of a external library

structure:

  • example_dependingOn_externalLib
    • extLib
      • include
        • externalmod.mod
      • lib
        • libmylib.a
    • myproject
      • build
        • Makefile
        • prog.dir
          • build.make
      • a.f90
      • main.f90


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

rules like they are generated by current CMake

Makefile:

all: prog.dir/all

prog.dir/all:
	$(MAKE) -f prog.dir/build.make prog.dir/requires
	$(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: ../../extLib/lib/libmylib.a
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/main.o: ../main.f90 
	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
	
	
externalmod.mod.proxy: # dummy 

localmod.mod.proxy: prog.dir/a.o

prog.dir/main.o.requires: localmod.mod.proxy externalmod.mod.proxy
	
prog.dir/requires: prog.dir/main.o.requires

This rules got the same problem as the example above (simple Program with module) plus it doesn't recognizes if the external modules got updated.

rules like they could be generated

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: ../../extLib/lib/libmylib.a
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

These rules build everything in proper order and considers the timestamp of externalmod.mod.

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

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
    • 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


You can download this example as tarball example_final.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

Content...

lib/a.f90:

MODULE libModX 
    USE libModY
END MODULE

lib/b.f90:

MODULE libModY
END MODULE

prog/a.f90:

MODULE localMod
END MODULE


prog/b.f90:

PROGRAM hello
    USE localMod
    USE libModX
    USE externalMod

    WRITE(*,*) 'Hello, F90 world.'
    CALL printExtModGreeting
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: ../../extLib/lib/libmyextlib.a
prog.dir/prog: prog.dir/main.o prog.dir/a.o ../../extLib/lib/libmyextlib.a
	gfortran -o prog.dir/prog  prog.dir/main.o prog.dir/a.o  lib.dir/libmylib.a ../../extLib/lib/libmyextlib.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: ../../extLib/include/externalmod.mod
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 -I ../../extLib/include



prog.dir/clean:
	rm prog.dir/a.o prog.dir/main.o prog.dir/prog prog.dir/localmod.mod