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

CMake构建Fortran共享库时派生类型可分配数组打印异常问题

根本成因

这个异常是gfortran 9.x及更早版本的运行时bug,结合CMake默认Fortran编译参数导致的派生类型对齐/数组描述符读取异常共同引发的,核心逻辑如下:

  • gfortran对可分配数组的实现依赖隐藏的数组描述符(dope vector),该结构体存储了数组的起始地址、维度、各维度长度、步长等元信息,派生类型中的可分配数组成员本质存储的是这个描述符的指针。
  • CMake在编译Fortran共享库时,默认会追加部分影响内存对齐的编译参数(部分版本会默认开启-falign-commons、-fpack-struct相关选项,或是和主程序编译时的对齐参数不一致),导致跨共享库边界传递派生类型时,可分配数组的描述符内存布局和list-directed IO(也就是write(*,*))运行时预期的布局不匹配。
  • list-directed IO输出整个可分配数组时,需要从描述符中读取数组长度信息,此时因为布局不匹配读取到错误的长度值(多数情况为0),因此直接跳过了数组元素的输出;而sum()内置函数解析数组描述符的逻辑和IO模块不同,能正确获取到数组长度与内存地址,因此计算结果正常。
  • 你改用隐式do循环(x%buff(j), j=1, n)输出时,不需要依赖数组描述符的长度信息,直接根据手动指定的循环次数遍历数组元素,因此输出正常。
  • 手动编译共享库时没有触发问题,是因为手动编译时没有追加CMake额外添加的对齐相关参数,主程序和共享库的派生类型内存布局完全一致,描述符能被IO模块正确解析。

验证方法

你可以通过以下操作确认问题根源:

  1. 在print_dummy子程序中加入print *, size(x%buff),使用CMake构建后运行会发现输出为0,进一步说明IO模块读取到的数组长度异常。
  2. 在CMake构建目录下执行make VERBOSE=1查看完整编译参数,对比你手动编译时的参数,即可看到两者的对齐类参数差异。

解决方案

除了你已经验证有效的隐式do循环写法外,还可以选择以下方案解决:

  • 升级gfortran到10及以上版本,该bug在gfortran 10版本中已经被官方修复。
  • 在CMakeLists.txt中强制指定统一的Fortran编译对齐参数,保证共享库和主程序的编译参数完全一致,添加以下配置即可:
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fno-align-commons -fno-pack-derived")
  • 改用静态链接库替代共享库,避免跨库边界的描述符传递问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 04:54:06