Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CMake: Fortran modules and compilation order

Tags:

cmake

fortran

I have a big Fortran program which contains many directories. Each directory is compiled separately in a pseudo-library, but there is still an interdependency mess, so at the end all pseudo-libraries are combined in a single usable library. I'd like to use Fortran modules, but it's very fragile, since I cannot rely on automatic dependency checking, and compilation may fail depending on the order.

For instance, consider the following CMakeLists.txt file:

project (test Fortran)
add_library (lib1 dir1/lib1.f90)
add_library (lib2 dir2/lib2.f90 dir2/mod.f90)
add_executable (exe dir3/exe.f90)
target_link_libraries (exe lib1 lib2)

With the sources:

dir1/lib1.f90:

subroutine bar
use foo, only: foofoo
implicit none
write(6,*) foofoo
end subroutine bar

dir2/lib2.f90:

subroutine bar2
use foo, only: foofoo
implicit none
write(6,*) foofoo,' again'
end subroutine bar2

dir2/mod.f90:

module foo
implicit none
integer :: foofoo=3
end module foo

dir3/exe.f90:

program meh
implicit none
call bar()
call bar2()
end program meh

Compiling from scratch fails:

$ make
[ 25%] Building Fortran object CMakeFiles/lib1.dir/dir1/lib1.f90.o
/home/user/cmake/dir1/lib1.f90:2.4:

use foo, only: foofoo
    1
Fatal Error: Can't open module file 'foo.mod' for reading at (1): No such file or directory
make[2]: *** [CMakeFiles/lib1.dir/dir1/lib1.f90.o] Error 1
make[1]: *** [CMakeFiles/lib1.dir/all] Error 2
make: *** [all] Error 2

but doing it in the right order works:

$ make lib2
Scanning dependencies of target lib2
[ 50%] Building Fortran object CMakeFiles/lib2.dir/dir2/mod.f90.o
[100%] Building Fortran object CMakeFiles/lib2.dir/dir2/lib2.f90.o
Linking Fortran static library liblib2.a
[100%] Built target lib2
$ make
[ 25%] Building Fortran object CMakeFiles/lib1.dir/dir1/lib1.f90.o
Linking Fortran static library liblib1.a
[ 25%] Built target lib1
[ 75%] Built target lib2
Scanning dependencies of target exe
[100%] Building Fortran object CMakeFiles/exe.dir/dir3/exe.f90.o
Linking Fortran executable exe
[100%] Built target exe

Is there any way CMake can figure out the dependency and compile lib2 (or at least mod.f90) before lib1?

ETA: A robust solution should work regardless of the order in which lib1 and lib2 are defined in the CMakeLists.txt file and, once the program has been compiled, after running rm foo.mod ; touch ../dir1/lib1.f90.

like image 900
Jellby Avatar asked Jun 17 '19 15:06

Jellby


2 Answers

The upcoming ninja build system version (1.10.0) has support for dynamic dependencies, which will resolve modules compilation order correctly.

To use it with CMake, you have to specify the Ninja generator:

cmake .. -DCMAKE_GENERATOR=Ninja # generate project
ninja # build the project
like image 160
Guillaume Racicot Avatar answered Nov 03 '22 06:11

Guillaume Racicot


Here problem is that lib1 target required object file for mod.f90. But there is no rule mention in CMakeLists.txt to create mod.f90.o while creating liblib1.a. For lib2 target mod.f90.o is created.

There can be two possible solution as below.

Solution-1

Add mod.f90 to both library.

project (test Fortran)
add_library (lib1 dir1/lib1.f90 dir2/mod.f90)
add_library (lib2 dir2/lib2.f90 dir2/mod.f90)
add_executable (exe dir3/exe.f90)
target_link_libraries (exe lib1 lib2)

Solution-2

Link library with mod.f90.o to other one.

project (test Fortran)
add_library (lib1 dir1/lib1.f90)
add_library (lib2 dir2/lib2.f90 dir2/mod.f90)
add_dependencies(lib1 lib2)
add_executable (exe dir3/exe.f90)
target_link_libraries (exe lib1 lib2)
like image 4
Manthan Tilva Avatar answered Nov 03 '22 06:11

Manthan Tilva