使用f2py编译Fortran模块

10 投票
3 回答
12845 浏览
提问于 2025-04-17 08:39

我有一个Fortran模块,想用f2py来编译(下面有代码)。当我把模块声明去掉,只留下子程序时,一切都正常。但是,如果像下面这样声明模块,我就遇到了问题:

> f2py.py -c -m its --compiler=mingw itimes-s2.f
...
Reading fortran codes...
    Reading file 'itimes-s2.f' (format:fix,strict)
crackline: groupcounter=1 groupname={0: '', 1: 'module', 2: 'interface', 3: 'subroutine'}
crackline: Mismatch of blocks encountered. Trying to fix it by assuming "end" statement.
...
c:\users\astay13\appdata\local\temp\tmpgh5ag8\Release\users\astay13\appdata\local\temp\tmpgh5ag8\src.win32-3.2\itsmodule.o:itsmodule.c:(.data+0xec): undefined reference to `itimes_'
collect2: ld returned 1 exit status

在f2py中编译模块和子程序有什么不同呢?我是不是在模块中漏掉了什么重要的东西,导致f2py出问题?需要注意的是,当我单独使用gfortran时,模块是可以正常编译的。

软件环境:Windows 7;gcc,gfortran 4.6.1(MinGW);python 3.2.2;f2py v2

itimes-s2.f:

  module its

  contains

  subroutine itimes(infile,outfile)

    implicit none

    ! Constants
    integer, parameter :: dp = selected_real_kind(15)

    ! Subroutine Inputs
    character(*), intent(in) :: infile
    character(*), intent(in) :: outfile

    ! Internal variables
    real(dp) :: num
    integer :: inu
    integer :: outu
    integer :: ios

    inu = 11
    outu = 22

    open(inu,file=infile,action='read')
    open(outu,file=outfile,action='write',access='append')

    do
      read(inu,*,IOSTAT=ios) num
      if (ios < 0) exit

      write(outu,*) num**2
    end do

  end subroutine itimes

  end module its

3 个回答

1

要用 f2py 来包装一个 F90 模块,你需要指定哪些功能可以从模块外部访问。为此,你可以使用 Fortran90 的 privatepublic 关键字。你还需要把文件的扩展名从 .f 改成 .F90 或 .f90。我对你的代码做了一些修改,演示了如何使用 publicprivate 关键字。

首先,创建一个签名文件,这个文件包含模块对象的 Fortran 接口:

f2py -h interface.pyf -m module_name module_its.f90 --overwrite-signature

然后编译这个模块:

f2py interface.pyf -c module_its.f90 

你的代码经过修改后,命名为 module_its.f90:

module its   
  ! use other modules
  implicit none
  private          ! everything in this module is private by standard 
                   ! (it can be used only inside this F90 module)
  public :: itimes ! Make you subroutine public
 
  contains

  subroutine itimes(infile,outfile)
    ! use other modules here to

    !implicit none holds for everthing in this module

    ! Constants
    integer, parameter :: dp = selected_real_kind(15)

    ! Subroutine Inputs
    character(*), intent(in) :: infile
    character(*), intent(in) :: outfile

    ! Internal variables
    real(dp) :: num
    integer :: inu
    integer :: outu
    integer :: ios

    inu = 11
    outu = 22

    open(inu,file=infile,action='read')
    open(outu,file=outfile,action='write',access='append')

    do
      read(inu,*,IOSTAT=ios) num
      if (ios < 0) exit

      write(outu,*) num**2
    end do

  end subroutine itimes

end module its
3

要让f2py正常工作,你需要一个签名文件来指导接口的创建,或者在你的源代码中添加f2py的注释,以帮助生成接口。想了解更多信息,可以查看这个链接:https://numpy.org/doc/stable/f2py/signature-file.html

从那个网站上:

C FILE: FIB3.F
      SUBROUTINE FIB(A,N)
C
C     CALCULATE FIRST N FIBONACCI NUMBERS
C
      INTEGER N
      REAL*8 A(N)
Cf2py intent(in) n
Cf2py intent(out) a
Cf2py depend(n) a
      DO I=1,N
         IF (I.EQ.1) THEN
            A(I) = 0.0D0
         ELSEIF (I.EQ.2) THEN
            A(I) = 1.0D0
         ELSE 
            A(I) = A(I-1) + A(I-2)
         ENDIF
      ENDDO
      END
C END FILE FIB3.F

现在可以通过一个命令来构建扩展模块:

f2py -c -m fib3 fib3.f
12

你想在一个Python模块里使用Fortran模块。如果你想这样做,两个模块的名字必须不一样,比如:

 f2py.py -c -m SOMEDIFFERENTNAME itimes-s2.f

这样调用的时候会变成 pythonmodule.fortranmodule.yourfunction()

你也可以这样导入它:

from pythonmodule import fortranmodule
fortranmodule.yourfunction()

否则在我的机器上是可以正常工作的。

撰写回答