You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CMake子目录链接Fortran库时模块查找失败及单独编译问题

问题描述

项目目录结构如下:

└── Project/
    ├── build/
    │   ├── common/
    │   ├── case/
    │   └── case2/
    ├── common/
    │   ├── CMakeLists.txt
    │   └── Mod*.F90
    ├── examples/
    │   ├── case/
    │   │   ├── CMakeLists.txt
    │   │   ├── exe1.F90
    │   │   └── exe2.F90
    │   └── case2/
    │       ├── exe3.F90
    │       └── exe4.F90
    └── CMakeLists.txt

需求是在Project/build目录下执行make common和make case单独编译对应模块,但当前遇到两个问题:

  • 执行make时,common库编译成功,但case下的Fortran文件无法找到common模块
  • make common可正常运行,但make case无法执行

相关CMake配置如下:

根目录CMakeLists.txt

add_subdirectory(common)
install(TARGETS common LIBRARY DESTINATION "bin")

add_subdirectory(examples/case case)

Project/common/CMakeLists.txt

file(GLOB common_F90s "*.F90")
add_library(common "${common_F90s}")
target_include_directories(common PRIVATE ${PETSC_INCLUDE_DIRS} ${NETCDF_INCLUDE})
target_link_libraries(common PRIVATE ${PETSC_LINK_LIBRARIES} ${SPHPK_LIB} ${FFTW_LIB} ${NETCDF_LIB})

Project/examples/case/CMakeLists.txt

file(GLOB case_F90s "*.F90")
cmake_print_variables(case_F90s)

foreach(F90_filepath ${case_F90s})
    get_filename_component(file_target ${F90_filepath} NAME_WE)
    add_executable(${file_target} ${F90_filepath})
    cmake_print_variables(file_target)

    target_include_directories(${file_target} PRIVATE ${PETSC_INCLUDE_DIRS})
    target_link_libraries(${file_target} PRIVATE common ${PETSC_LINK_LIBRARIES})
    message("HERE")
endforeach()

错误信息示例:

[ 90%] Building Fortran object CMakeFiles/initcond.dir/examples/case/initcond.F90.o
~Project/examples/case/initcond.F90:4:7:

    4 |   use ModDataTypes
      |       1
Fatal Error: Cannot open module file 'moddatatypes.mod' for reading at (1): No such file or directory
compilation terminated.
make[2]: *** [CMakeFiles/initcond.dir/examples/case/initcond.F90.o] Error 1
make[1]: *** [CMakeFiles/initcond.dir/all] Error 2

尝试过将common库改为STATIC/SHARED类型,SHARED报错,STATIC无改善。旧版本无嵌套CMakeLists可正常编译case,但无法单独编译模块。


解决方案

1. 修复模块文件路径问题

Fortran模块文件(.mod)默认生成在库的编译目录中,case下的可执行文件找不到这些模块,是因为未将common库的模块输出目录添加到可执行文件的包含路径。

修改Project/common/CMakeLists.txt:

file(GLOB common_F90s "*.F90")
add_library(common "${common_F90s}")

# 统一设置模块文件输出目录
set_target_properties(common PROPERTIES
    Fortran_MODULE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/modules"
)

# 将模块目录设为PUBLIC,依赖common的目标会自动继承该路径
target_include_directories(common
    PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/modules"
    PRIVATE ${PETSC_INCLUDE_DIRS} ${NETCDF_INCLUDE}
)

target_link_libraries(common PRIVATE ${PETSC_LINK_LIBRARIES} ${SPHPK_LIB} ${FFTW_LIB} ${NETCDF_LIB})

这样case下的可执行文件通过target_link_libraries依赖common时,会自动获取模块文件的包含路径,无需手动添加。

2. 创建case虚拟目标,支持make case单独编译

当前make case无法执行,是因为没有定义名为case的目标。用add_custom_target创建虚拟目标,将case下所有可执行文件设为它的依赖:

修改Project/examples/case/CMakeLists.txt:

file(GLOB case_F90s "*.F90")
cmake_print_variables(case_F90s)

# 定义空的case虚拟目标,用于统一编译所有case可执行文件
add_custom_target(case)

foreach(F90_filepath ${case_F90s})
    get_filename_component(file_target ${F90_filepath} NAME_WE)
    add_executable(${file_target} ${F90_filepath})
    cmake_print_variables(file_target)

    target_include_directories(${file_target} PRIVATE ${PETSC_INCLUDE_DIRS})
    target_link_libraries(${file_target} PRIVATE common ${PETSC_LINK_LIBRARIES})
    
    # 将每个可执行文件添加为case目标的依赖
    add_dependencies(case ${file_target})
    message("HERE")
endforeach()

现在执行make case时,CMake会自动编译未完成的common库,再编译所有case下的可执行文件。

3. 验证步骤

  1. 清空build目录,重新执行cmake ..
  2. 执行make common:仅编译common库
  3. 执行make case:编译common(若未编译)和所有case可执行文件
  4. 执行make:编译所有目标

内容的提问来源于stack exchange,提问作者suzm10

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 01:34:54