具有 bind(C) 的 Fortran C 可互操作子模块过程在由 gfortran 编译时报告错误
Fortran C-interoperable submodule procedure with bind(C) reports error when compiled by gfortran
考虑以下 Fortran 模块 Foo_mod
及其子模块 Foo_smod
,
module CallbackInterface_mod
abstract interface
function getLogFunc4C_proc(ndim,Point) result(logFunc) bind(C)
use, intrinsic :: iso_c_binding, only : c_int32_t, c_double, c_int
integer(c_int32_t), intent(in) :: ndim
real(c_double), intent(in) :: Point(ndim)
real(c_double) :: logFunc
end function getLogFunc4C_proc
end interface
end module CallbackInterface_mod
!***********************************************************************************************************************************
!***********************************************************************************************************************************
module Foo_mod
interface
module subroutine runFoo4C(ndim, getLogFuncFromC, inputString, inputStringLen) bind(C, name="runFoo")
use, intrinsic :: iso_c_binding, only: c_int32_t, c_char, c_funptr, c_f_procpointer, c_size_t
use CallbackInterface_mod, only: getLogFunc4C_proc
implicit none
integer(c_int32_t) , intent(in) :: ndim
character(len=1, kind=c_char), dimension(*), intent(in) :: inputString
integer(c_size_t) , intent(in) :: inputStringLen
type(c_funptr), intent(in), value :: getLogFuncFromC
end subroutine runFoo4C
end interface
contains
subroutine runFoo(ndim, getLogFunc, string)
use CallbackInterface_mod, only: getLogFunc4C_proc
use, intrinsic :: iso_fortran_env, only: RK => real64
implicit none
integer :: ndim
procedure(getLogFunc4C_proc) :: getLogFunc
character(*), intent(in) :: string
real(RK) :: Point(ndim)
character(:), allocatable :: mystring
Point = [1._RK,1._RK]
write(*,*) "Hi again, this is a call from inside runFoo!"
write(*,*) "getLogFunc(2,[1,1]) = ", getLogFunc(ndim,Point)
write(*,*) "string = ", string
end subroutine
end module Foo_mod
!***********************************************************************************************************************************
!***********************************************************************************************************************************
submodule (Foo_mod) Foo_smod
contains
module subroutine runFoo4C(ndim, getLogFuncFromC, InputString, inputStringLen) bind(C, name="runFoo")
use, intrinsic :: iso_c_binding, only: c_double, c_int32_t, c_char, c_funptr, c_f_procpointer, c_size_t
use CallbackInterface_mod, only: getLogFunc4C_proc
implicit none
integer(c_int32_t) , intent(in) :: ndim
character(len=1, kind=c_char), dimension(*), intent(in) :: InputString
integer(c_size_t) , intent(in) :: inputStringLen
type(c_funptr), intent(in), value :: getLogFuncFromC
procedure(getLogFunc4C_proc), pointer :: getLogFunc
real(c_double) :: Point(ndim)
character(:), allocatable :: inputString4tran
integer :: i
write(*,*) "InputString: ", InputString(1:inputStringLen)
allocate( character(len=inputStringLen) :: inputString4tran )
do i=1,inputStringLen
inputString4tran(i:i) = InputString(i)
end do
write(*,*) "inputString4tran: ", inputString4tran
! associate the input C procedure pointer to a Fortran procedure pointer
call c_f_procpointer(cptr=getLogFuncFromC, fptr=getLogFunc)
Point = [1._c_double, 1._c_double]
write(*,*) "getLogFunc(ndim=2, [1._c_double, 1._c_double]): ", getLogFunc( ndim, Point )
call runFoo(ndim, getLogFunc, inputString4tran)
end subroutine runFoo4C
end submodule Foo_smod
现在,这段代码对我来说似乎是一个完美的 Fortran 模块,实际上它确实通过英特尔 Fortran 编译器 2018 在 Windows 和 Linux,并正确运行。但是用gfortran 7.3.0编译时,报如下错误:
gfortran -c ../Foo_mod.f90
../Foo_mod.f90:54:18:
submodule (Foo_mod) Foo_smod
1
Error: BIND(C) attribute at (1) can only be used for variables or common blocks
如果我从模块 Foo_mod
中的可互操作子程序 runFoo4C()
的接口中删除 bind(c)
属性,问题可以解决,如下所示,
...
module subroutine runFoo4C(ndim, getLogFuncFromC, inputString, inputStringLen) ! bind(C, name="runFoo")
...
然而,英特尔 Fortran 编译器会抱怨模块 Foo_mod
中的子例程接口与子模块 Foo_smod
中子例程的实现不兼容。在我看来,这更像是 GFORTRAN 中的错误,而不是编程错误。但在我继续报告之前,您的评论非常感谢。
我很清楚这是一个与子模块相关的 gfortran 错误。由于这是最近才添加的功能,因此可能会出现一些错误并不意外。
我会评论说,当在这里问这样的问题时,强烈建议您提供一个 Minimal, Complete and Verifiable Example 由于您没有显示子模块附带的模块,我们无法验证无需不必要的额外工作即可解决问题。
考虑以下 Fortran 模块 Foo_mod
及其子模块 Foo_smod
,
module CallbackInterface_mod
abstract interface
function getLogFunc4C_proc(ndim,Point) result(logFunc) bind(C)
use, intrinsic :: iso_c_binding, only : c_int32_t, c_double, c_int
integer(c_int32_t), intent(in) :: ndim
real(c_double), intent(in) :: Point(ndim)
real(c_double) :: logFunc
end function getLogFunc4C_proc
end interface
end module CallbackInterface_mod
!***********************************************************************************************************************************
!***********************************************************************************************************************************
module Foo_mod
interface
module subroutine runFoo4C(ndim, getLogFuncFromC, inputString, inputStringLen) bind(C, name="runFoo")
use, intrinsic :: iso_c_binding, only: c_int32_t, c_char, c_funptr, c_f_procpointer, c_size_t
use CallbackInterface_mod, only: getLogFunc4C_proc
implicit none
integer(c_int32_t) , intent(in) :: ndim
character(len=1, kind=c_char), dimension(*), intent(in) :: inputString
integer(c_size_t) , intent(in) :: inputStringLen
type(c_funptr), intent(in), value :: getLogFuncFromC
end subroutine runFoo4C
end interface
contains
subroutine runFoo(ndim, getLogFunc, string)
use CallbackInterface_mod, only: getLogFunc4C_proc
use, intrinsic :: iso_fortran_env, only: RK => real64
implicit none
integer :: ndim
procedure(getLogFunc4C_proc) :: getLogFunc
character(*), intent(in) :: string
real(RK) :: Point(ndim)
character(:), allocatable :: mystring
Point = [1._RK,1._RK]
write(*,*) "Hi again, this is a call from inside runFoo!"
write(*,*) "getLogFunc(2,[1,1]) = ", getLogFunc(ndim,Point)
write(*,*) "string = ", string
end subroutine
end module Foo_mod
!***********************************************************************************************************************************
!***********************************************************************************************************************************
submodule (Foo_mod) Foo_smod
contains
module subroutine runFoo4C(ndim, getLogFuncFromC, InputString, inputStringLen) bind(C, name="runFoo")
use, intrinsic :: iso_c_binding, only: c_double, c_int32_t, c_char, c_funptr, c_f_procpointer, c_size_t
use CallbackInterface_mod, only: getLogFunc4C_proc
implicit none
integer(c_int32_t) , intent(in) :: ndim
character(len=1, kind=c_char), dimension(*), intent(in) :: InputString
integer(c_size_t) , intent(in) :: inputStringLen
type(c_funptr), intent(in), value :: getLogFuncFromC
procedure(getLogFunc4C_proc), pointer :: getLogFunc
real(c_double) :: Point(ndim)
character(:), allocatable :: inputString4tran
integer :: i
write(*,*) "InputString: ", InputString(1:inputStringLen)
allocate( character(len=inputStringLen) :: inputString4tran )
do i=1,inputStringLen
inputString4tran(i:i) = InputString(i)
end do
write(*,*) "inputString4tran: ", inputString4tran
! associate the input C procedure pointer to a Fortran procedure pointer
call c_f_procpointer(cptr=getLogFuncFromC, fptr=getLogFunc)
Point = [1._c_double, 1._c_double]
write(*,*) "getLogFunc(ndim=2, [1._c_double, 1._c_double]): ", getLogFunc( ndim, Point )
call runFoo(ndim, getLogFunc, inputString4tran)
end subroutine runFoo4C
end submodule Foo_smod
现在,这段代码对我来说似乎是一个完美的 Fortran 模块,实际上它确实通过英特尔 Fortran 编译器 2018 在 Windows 和 Linux,并正确运行。但是用gfortran 7.3.0编译时,报如下错误:
gfortran -c ../Foo_mod.f90
../Foo_mod.f90:54:18:
submodule (Foo_mod) Foo_smod
1
Error: BIND(C) attribute at (1) can only be used for variables or common blocks
如果我从模块 Foo_mod
中的可互操作子程序 runFoo4C()
的接口中删除 bind(c)
属性,问题可以解决,如下所示,
...
module subroutine runFoo4C(ndim, getLogFuncFromC, inputString, inputStringLen) ! bind(C, name="runFoo")
...
然而,英特尔 Fortran 编译器会抱怨模块 Foo_mod
中的子例程接口与子模块 Foo_smod
中子例程的实现不兼容。在我看来,这更像是 GFORTRAN 中的错误,而不是编程错误。但在我继续报告之前,您的评论非常感谢。
我很清楚这是一个与子模块相关的 gfortran 错误。由于这是最近才添加的功能,因此可能会出现一些错误并不意外。
我会评论说,当在这里问这样的问题时,强烈建议您提供一个 Minimal, Complete and Verifiable Example 由于您没有显示子模块附带的模块,我们无法验证无需不必要的额外工作即可解决问题。