Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fortran module files not found by CMake

Tags:

cmake

fortran

I have a split project in Fortran with a subdirectory as a library:

# ./CMakeLists.txt
cmake_minimum_required (VERSION 2.8)
project (Simulation Fortran)
enable_language(Fortran)

add_subdirectory(lib)

add_executable(Simulation main.f90)
include_directories(lib)
add_dependencies(Simulation physicalConstants)
target_link_libraries(Simulation physicalConstants)

The root directory contains only a single Fortran source code file:

! ./main.f90:

program simulation
use physicalConstants

implicit none

write(*,*) "Boltzmann constant:", k_b

end program simulation

And my subdirectory lib contains another CMakeLists.txt as well as a Fortran module source file:

# ./lib/CMakeLists.txt:

cmake_minimum_required (VERSION 2.8)
enable_language(Fortran)

project(physicalConstants)
add_library( physicalConstants SHARED physicalConstants.f90)
! ./lib/physicalConstants.f90:

module physicalConstants
implicit none
save

real, parameter :: k_B = 1.38e-23

end module physicalConstants

I tried to build those using cmake. Make generates the physicalconstants.mod in the lib directory, but this file is not found during the build process of main.f90.o:

Fatal Error: Can't open module file 'physicalconstants.mod' for reading at (1): No such file or directory

What am I missing here?

like image 914
chris Avatar asked May 11 '17 13:05

chris


People also ask

How to fix CMake error no CMake_Fortran_compiler could be found?

CMake Error at CMakeLists.txt:3 (project): No CMAKE_Fortran_COMPILER could be found. Tell CMake where to find the compiler by setting either the environment variable "FC" or the CMake cache entry CMAKE_Fortran_COMPILER to the full path to the compiler, or to the compiler name if it is in the PATH. -- Configuring incomplete, errors occurred!

How are Fortran modules placed in the build directory?

If the target contains Fortran source files that provide modules and the compiler supports a module output directory this specifies the directory in which the modules will be placed. When this property is not set the modules will be placed in the build directory corresponding to the target's source directory.

What happens if CMake_Fortran_module_directory is not set?

When this property is not set the modules will be placed in the build directory corresponding to the target's source directory. If the variable CMAKE_Fortran_MODULE_DIRECTORY is set when a target is created its value is used to initialize this property.

Is mpifort a Fortran compiler?

mpifort is not a Fortran compiler, but a wrapper around one provided by the MPI implementation. CMake generally prefers to run compilers directly (because wrappers can do…funny things). Can the NAG compiler be taught about the .tbd suffix?


1 Answers

For target A to successfully use modules from target B, the directory where B stores module files must be among A's include directories.

Variant 1

One way to achieve that is to set the property Fortran_MODULE_DIRECTORY on target B and then add that property's contents to include directories of A.

You're claiming to support ancient CMake 2.8.0, in which you'll need to do something like this:

add_executable(Simulation main.f90)
include_directories(lib)
# note that add_dependencies call is not necessary when you're actually linking
target_link_libraries(Simulation physicalConstants)
get_property(moduleDir TARGET physicalConstants PROPERTY Fortran_MODULE_DIRECTORY)
include_directories(${moduleDir})

In more modern CMake, you could do this instead:

add_executable(Simulation main.f90)
include_directories(lib)
target_link_libraries(Simulation physicalConstants)
target_include_directories(Simulation PUBLIC $<TARGET_PROPERTY:physicalConstants,Fortran_MODULE_DIRECTORY>)

You can even create a function for it:

function(LinkFortranLibraries Target)
  target_link_libraries(Target ${ARGN})
  foreach(Lib IN LISTS ARGN)
    target_include_directories(Simulation PUBLIC $<TARGET_PROPERTY:${Lib},Fortran_MODULE_DIRECTORY>)
  endforeach()
endfunction()

and then use it like this:

add_executable(Simulation main.f90)
include_directories(lib)
LinkFortranLibraries(Simulation physicalConstants)

Variant 2

If you do not use the Fortran_MODULE_DIRECTORY property, module files are stored in the binary directory corresponding to the source directory of the target producing them. This can be retrieved from the target's property BINARY_DIR, which you could use exactly as Fortran_MODULE_DIRECTORY in variant 1.

However, CMake 2.8.0 does not support the target property BINARY_DIR, so you will have to "reconstruct" its value manually:

add_executable(Simulation main.f90)
include_directories(lib ${CMAKE_CURRENT_BINARY_DIR}/lib)
target_link_libraries(Simulation physicalConstants)
like image 73
Angew is no longer proud of SO Avatar answered Oct 10 '22 23:10

Angew is no longer proud of SO