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
.
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
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With