CMake找不到Fortran模块文件

chr*_*ris 6 fortran cmake

我在Fortran中有一个拆分项目,其子目录作为库:

# ./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)
Run Code Online (Sandbox Code Playgroud)

根目录只包含一个Fortran源代码文件:

! ./main.f90:

program simulation
use physicalConstants

implicit none

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

end program simulation
Run Code Online (Sandbox Code Playgroud)

我的子目录lib包含另一个CMakeLists.txt以及Fortran模块源文件:

# ./lib/CMakeLists.txt:

cmake_minimum_required (VERSION 2.8)
enable_language(Fortran)

project(physicalConstants)
add_library( physicalConstants SHARED physicalConstants.f90)
Run Code Online (Sandbox Code Playgroud)
! ./lib/physicalConstants.f90:

module physicalConstants
implicit none
save

real, parameter :: k_B = 1.38e-23

end module physicalConstants
Run Code Online (Sandbox Code Playgroud)

我尝试使用cmake构建那些.Make physicalconstants.modlib目录中生成,但在构建过程中找不到此文件main.f90.o:

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

我在这里错过了什么?

Rei*_*ica 5

为了让目标 A 成功使用目标 B 中的模块,B 存储模块文件的目录必须在 A 的包含目录中。

变体 1

实现这一Fortran_MODULE_DIRECTORY目标的一种方法是在目标 B 上设置属性,然后添加该属性的内容以包含 A 的目录。

您声称支持古老的 CMake 2.8.0,您需要在其中执行以下操作:

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})
Run Code Online (Sandbox Code Playgroud)

在更现代的 CMake 中,你可以这样做:

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

你甚至可以为它创建一个函数:

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()
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它:

add_executable(Simulation main.f90)
include_directories(lib)
LinkFortranLibraries(Simulation physicalConstants)
Run Code Online (Sandbox Code Playgroud)

变体 2

如果不使用该Fortran_MODULE_DIRECTORY属性,模块文件将存储在与生成它们的目标的源目录相对应的二进制目录中。这可以从目标的 property 中检索BINARY_DIR,您可以完全按照Fortran_MODULE_DIRECTORY变体 1 使用它。

但是,CMake 2.8.0 不支持 target 属性BINARY_DIR,因此您必须手动“重建”其值:

add_executable(Simulation main.f90)
include_directories(lib ${CMAKE_CURRENT_BINARY_DIR}/lib)
target_link_libraries(Simulation physicalConstants)
Run Code Online (Sandbox Code Playgroud)