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

Fortran中设置OpenBLAS子程序指针兼容单双精度编译报错求助

解决Fortran中过程指针指向OpenBLAS子程序的显式接口错误

错误原因

编译器报错Error: Explicit interface required for ‘sgemv’ at (1): value argument,核心原因是:

  • 仅通过external声明sgemv/dgemv只能告诉编译器它们是外部子程序,但无法提供参数的类型、属性(比如value)等关键信息。
  • Fortran标准规定:当子程序参数使用value属性时,必须提供显式接口才能正确调用或赋值给过程指针,否则编译器无法验证参数匹配性。

解决方案

方案一:修改原有双模块结构,添加显式接口

在每个精度模块中,为对应的OpenBLAS子程序定义显式接口块,替代单纯的external声明:

单精度模块修改后代码

module SinglePrecision  
   implicit none 
   integer, parameter                                :: precision = selected_real_kind(6, 37)
   
   ! 为sgemv定义显式接口,匹配OpenBLAS单精度gemv原型
   interface
      subroutine sgemv(trans, m, n, alpha, a, lda, x, incx, beta, y, incy) bind(C, name='sgemv')
         import :: precision
         character(len=1), intent(in)                :: trans
         integer(4), intent(in), value               :: m, n, lda, incx, incy
         real(precision), intent(in), value          :: alpha, beta
         real(precision), dimension(lda, *), intent(in) :: a
         real(precision), dimension(*), intent(in)   :: x
         real(precision), dimension(*), intent(inout):: y
      end subroutine sgemv
   end interface

   abstract interface
      subroutine gemv(trans, m, n, alpha, a, lda, x, incx, beta, y, incy) 
         import :: precision
         character                                      :: trans
         integer(4), value                              :: m, n, lda, incx, incy
         real(precision), value                         :: alpha, beta
         real(precision), dimension(lda, *), intent(in) :: a
         real(precision), dimension(*), intent(in)      :: x
         real(precision), dimension(*), intent(inout)   :: y
      end subroutine gemv
   end interface 

   procedure(gemv), pointer                          :: MatrixVectorMultiplication => null()

end module SinglePrecision

双精度模块修改后代码

module DoublePrecision  
   implicit none 
   integer, parameter                                :: precision = selected_real_kind(15, 307)

   ! 为dgemv定义显式接口,匹配OpenBLAS双精度gemv原型
   interface
      subroutine dgemv(trans, m, n, alpha, a, lda, x, incx, beta, y, incy) bind(C, name='dgemv')
         import :: precision
         character(len=1), intent(in)                :: trans
         integer(4), intent(in), value               :: m, n, lda, incx, incy
         real(precision), intent(in), value          :: alpha, beta
         real(precision), dimension(lda, *), intent(in) :: a
         real(precision), dimension(*), intent(in)   :: x
         real(precision), dimension(*), intent(inout):: y
      end subroutine dgemv
   end interface

   abstract interface
      subroutine gemv(trans, m, n, alpha, a, lda, x, incx, beta, y, incy) 
         import :: precision
         character                                      :: trans
         integer(4), value                              :: m, n, lda, incx, incy
         real(precision), value                         :: alpha, beta
         real(precision), dimension(lda, *), intent(in) :: a
         real(precision), dimension(*), intent(in)      :: x
         real(precision), dimension(*), intent(inout)   :: y
      end subroutine gemv
   end interface 

   procedure(gemv), pointer                          :: MatrixVectorMultiplication => null()

end module DoublePrecision

主程序代码保持不变,编译命令也无需调整。

方案二:合并为单模块,用编译宏控制精度(更简洁)

将两个模块合并为一个,通过编译宏直接切换精度和对应的BLAS接口,减少冗余代码:

合并后的模块代码

module BLAS_GEMV
   implicit none
   ! 默认单精度,编译时-Ddouble切换为双精度
   integer, parameter :: precision = selected_real_kind(6, 37)
#ifdef double
   integer, parameter :: precision = selected_real_kind(15, 307)
#endif

   ! 定义统一的抽象接口
   abstract interface
      subroutine gemv_interface(trans, m, n, alpha, a, lda, x, incx, beta, y, incy)
         import :: precision
         character(len=1)                             :: trans
         integer(4), value                            :: m, n, lda, incx, incy
         real(precision), value                       :: alpha, beta
         real(precision), dimension(lda, *), intent(in) :: a
         real(precision), dimension(*), intent(in)    :: x
         real(precision), dimension(*), intent(inout) :: y
      end subroutine gemv_interface
   end interface

   ! 根据编译宏绑定对应精度的OpenBLAS接口,并初始化过程指针
#ifdef double
   interface
      subroutine dgemv(trans, m, n, alpha, a, lda, x, incx, beta, y, incy) bind(C, name='dgemv')
         import :: precision
         character(len=1), intent(in)                :: trans
         integer(4), intent(in), value               :: m, n, lda, incx, incy
         real(precision), intent(in), value          :: alpha, beta
         real(precision), dimension(lda, *), intent(in) :: a
         real(precision), dimension(*), intent(in)   :: x
         real(precision), dimension(*), intent(inout):: y
      end subroutine dgemv
   end interface
   procedure(gemv_interface), pointer :: MatrixVectorMultiplication => dgemv
#else
   interface
      subroutine sgemv(trans, m, n, alpha, a, lda, x, incx, beta, y, incy) bind(C, name='sgemv')
         import :: precision
         character(len=1), intent(in)                :: trans
         integer(4), intent(in), value               :: m, n, lda, incx, incy
         real(precision), intent(in), value          :: alpha, beta
         real(precision), dimension(lda, *), intent(in) :: a
         real(precision), dimension(*), intent(in)   :: x
         real(precision), dimension(*), intent(inout):: y
      end subroutine sgemv
   end interface
   procedure(gemv_interface), pointer :: MatrixVectorMultiplication => sgemv
#endif

end module BLAS_GEMV

简化后的主程序

program test_MatrixMultiplication
   use BLAS_GEMV
   ! 直接使用MatrixVectorMultiplication调用对应精度的gemv,无需手动赋值
end program test_MatrixMultiplication

编译命令和原命令一致:

! 单精度编译
gfortran -Dsingle -cpp -L/usr/local/opt/openblas/lib/ -I/usr/local/opt/openblas/include/ -lopenblas -ffree-line-length-1024 SingleDoublePrecisionMatrixMultiplication.f90

! 双精度编译
gfortran -Ddouble -cpp -L/usr/local/opt/openblas/lib/ -I/usr/local/opt/openblas/include/ -lopenblas -ffree-line-length-1024 SingleDoublePrecisionMatrixMultiplication.f90 

关键注意事项

  • 添加bind(C, name='sgemv')/bind(C, name='dgemv')是为了确保子程序名称与OpenBLAS的C接口严格匹配,避免编译器修改Fortran名称导致链接错误。
  • 抽象接口的参数必须与具体BLAS接口的参数类型、属性(value、intent)完全一致,否则过程指针赋值会失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 02:25:00