繁体   English   中英

f2py 链接 quadmath 库? 使用 ctypes 代替 fortran 包装?

[英]f2py linking quadmath libraries? Use ctypes for fortran wrapper instead?

2019 年 11 月 23日更新:这开始是关于为什么我无法让 f2py 为简单的 fortran 包装器工作的问题。 我的“答案”(如下)是使用 ctypes 代替。

原帖:过去三天我一直在尝试使用 f2py 将 fortran 连接到 python。 我正在使用 cygwin 和 mingw 处理 windows。 这篇文章是关于使用 cygwin,但我担心两者之间的冲突。 这是源 multxy.f90:

        subroutine multxy(x,y,z)
           integer, parameter :: flt = selected_real_kind(15)
           real(flt), intent(in) :: x,y
           real(flt), intent(out) :: z
           write(*,'(a,3g12.5)')'multxy'
           write(*,'(a,3g12.5)')'multxy',x,y,x*y
           z = x*y
        end subroutine multxy

如果我像我见过的所有示例一样运行 f2py: f2py -m multxyC -c multxy.f90它会产生链接错误。 在大量的 output 中,我收到了有关strtoflt128的投诉。 这是 gnu gcc 四元数学库中的 function。 我的flt kind 相当于 C 中的 double。 代码中没有四元数学,那么为什么要使用它呢? 我试图创建一个扩展文件以查看它是否会告诉我任何信息,但它仍然尝试链接,因此没有生成(或保存)代码。 此时,我使用strtofl128构建了一个小的 c 程序。 如果我包含 quadmath 库,它会编译和链接: gcc main.c -lquadmath它运行不正确,但我稍后会研究。 我相信实际的 quadmath 库文件是…./cwin/lib/gcc/x86_64-pc-cygwin/8.3.0/libquadmath.a 运行 f2py 的 output 显示了这个目录,所以你会认为它会链接库。 我尝试使用-l选项的各种变体来运行 f2py。 通常它会抱怨找不到库。 我有一个变体可以工作,但链接仍然失败。 我还使用过 integer function:

integer function intfunc(n)
   integer, intent(in) :: n
   intfunc = n*n
end function intfunc

我已经能够创建一个 dll 并在不使用 f2py 的情况下从 python 调用它。 它似乎可以通过 f2py 运行。 它会创建一个文件intfunc.cp37-win_amd64.pyd和一个包含 a.dll 的目录,该目录具有巨大的名称。 我还不能从 python 调用它,但我会继续努力。

问题:

  1. 为什么 f2py 使用四精度? 是否有避免使用它的选项?
  2. 如何包含正确的库?
  3. 如何在不调用 linker 的情况下创建 C 扩展代码?
  4. Cygwin和MinGW之间会不会有冲突? 如何避免?
  5. f2py 准备好迎接黄金时段了吗? 使用 C 扩展做手动界面会更简单吗?
  6. f2py 可以处理 fortran 功能吗? 有几个地方推荐使用子程序?

f2py 被吹捧为易于使用。 也许是这样,但只有在你让它正常工作之后。 25 年来,我一直在接触不同的语言,例如。 c/c++, fortran, excel/vba, matlab/octave,几乎没有这么多困难。 这似乎是一个隐藏在幕后的很多功能的程序,这使得故障排除变得困难。

一个问题是运行 f2py 的 output 与核心转储一样容易阅读。 我运行时的 output 是:

running build
running config_cc
unifing config_cc, config, build_clib, build_ext, build commands --compiler options
running config_fc
unifing config_fc, config, build_clib, build_ext, build commands --fcompiler options
running build_src
build_src
building extension "multxyC" sources
f2py options: []
f2py:> C:\cwin\tmp\tmprix0z7i7\src.win-amd64-3.7\multxyCmodule.c
creating C:\cwin\tmp\tmprix0z7i7\src.win-amd64-3.7
Reading fortran codes...
    Reading file 'multxy.f90' (format:free)
Post-processing...
    Block: multxyC
            Block: multxy
Post-processing (stage 2)...
Building modules...
    Building module "multxyC"...
        Constructing wrapper function "multxy"...
          z = multxy(x,y)
    Wrote C/API module "multxyC" to file "C:\cwin\tmp\tmprix0z7i7\src.win-amd64-3.7\multxyCmodule.c"
  adding 'C:\cwin\tmp\tmprix0z7i7\src.win-amd64-3.7\fortranobject.c' to sources.
  adding 'C:\cwin\tmp\tmprix0z7i7\src.win-amd64-3.7' to include_dirs.
copying c:\program files\python37\lib\site-packages\numpy\f2py\src\fortranobject.c -> C:\cwin\tmp\tmprix0z7i7\src.win-amd64-3.7
copying c:\program files\python37\lib\site-packages\numpy\f2py\src\fortranobject.h -> C:\cwin\tmp\tmprix0z7i7\src.win-amd64-3.7
build_src: building npy-pkg config files
running build_ext
No module named 'numpy.distutils._msvccompiler' in numpy.distutils; trying from distutils
customize MSVCCompiler
customize MSVCCompiler using build_ext
get_default_fcompiler: matching types: '['gnu', 'intelv', 'absoft', 'compaqv', 'intelev', 'gnu95', 'g95', 'intelvem', 'intelem', 'flang']'
customize GnuFCompiler
Could not locate executable g77
Could not locate executable f77
customize IntelVisualFCompiler
Could not locate executable ifort
Could not locate executable ifl
customize AbsoftFCompiler
Could not locate executable f90
customize CompaqVisualFCompiler
Found executable C:\cwin\bin\DF.exe
customize IntelItaniumVisualFCompiler
Could not locate executable efl
customize Gnu95FCompiler
Found executable C:\cwin\bin\gfortran.exe
Using built-in specs.
COLLECT_GCC=/usr/bin/gfortran
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-cygwin/8.3.0/lto-wrapper.exe
Target: x86_64-pc-cygwin
Configured with: /cygdrive/i/szsz/tmpp/gcc/gcc-8.3.0-1.x86_64/src/gcc-8.3.0/configure --srcdir=/cygdrive/i/szsz/tmpp/gcc/gcc-8.3.0-1.x86_64/src/gcc-8.3.0 --prefix=/usr --exec-prefix=/usr --localstatedir=/var --sysconfdir=/etc --docdir=/usr/share/doc/gcc --htmldir=/usr/share/doc/gcc/html -C --build=x86_64-pc-cygwin --host=x86_64-pc-cygwin --target=x86_64-pc-cygwin --without-libiconv-prefix --without-libintl-prefix --libexecdir=/usr/lib --enable-shared --enable-shared-libgcc --enable-static --enable-version-specific-runtime-libs --enable-bootstrap --enable-__cxa_atexit --with-dwarf2 --with-tune=generic --enable-languages=ada,c,c++,fortran,lto,objc,obj-c++ --enable-graphite --enable-threads=posix --enable-libatomic --enable-libgomp --enable-libitm --enable-libquadmath --enable-libquadmath-support --disable-libssp --enable-libada --disable-symvers --with-gnu-ld --with-gnu-as --with-cloog-include=/usr/include/cloog-isl --without-libiconv-prefix --without-libintl-prefix --with-system-zlib --enable-linker-build-id --with-default-libstdcxx-abi=gcc4-compatible --enable-libstdcxx-filesystem-ts
Thread model: posix
gcc version 8.3.0 (GCC) 
customize Gnu95FCompiler
Using built-in specs.
COLLECT_GCC=/usr/bin/gfortran
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-cygwin/8.3.0/lto-wrapper.exe
Target: x86_64-pc-cygwin
Configured with: /cygdrive/i/szsz/tmpp/gcc/gcc-8.3.0-1.x86_64/src/gcc-8.3.0/configure --srcdir=/cygdrive/i/szsz/tmpp/gcc/gcc-8.3.0-1.x86_64/src/gcc-8.3.0 --prefix=/usr --exec-prefix=/usr --localstatedir=/var --sysconfdir=/etc --docdir=/usr/share/doc/gcc --htmldir=/usr/share/doc/gcc/html -C --build=x86_64-pc-cygwin --host=x86_64-pc-cygwin --target=x86_64-pc-cygwin --without-libiconv-prefix --without-libintl-prefix --libexecdir=/usr/lib --enable-shared --enable-shared-libgcc --enable-static --enable-version-specific-runtime-libs --enable-bootstrap --enable-__cxa_atexit --with-dwarf2 --with-tune=generic --enable-languages=ada,c,c++,fortran,lto,objc,obj-c++ --enable-graphite --enable-threads=posix --enable-libatomic --enable-libgomp --enable-libitm --enable-libquadmath --enable-libquadmath-support --disable-libssp --enable-libada --disable-symvers --with-gnu-ld --with-gnu-as --with-cloog-include=/usr/include/cloog-isl --without-libiconv-prefix --without-libintl-prefix --with-system-zlib --enable-linker-build-id --with-default-libstdcxx-abi=gcc4-compatible --enable-libstdcxx-filesystem-ts
Thread model: posix
gcc version 8.3.0 (GCC) 
customize Gnu95FCompiler using build_ext
building 'multxyC' extension
compiling C sources
creating C:\cwin\tmp\tmprix0z7i7\Release\cwin
creating C:\cwin\tmp\tmprix0z7i7\Release\cwin\tmp
creating C:\cwin\tmp\tmprix0z7i7\Release\cwin\tmp\tmprix0z7i7
creating C:\cwin\tmp\tmprix0z7i7\Release\cwin\tmp\tmprix0z7i7\src.win-amd64-3.7
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\bin\HostX86\x64\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MT -IC:\cwin\tmp\tmprix0z7i7\src.win-amd64-3.7 -Ic:\program files\python37\lib\site-packages\numpy\core\include -Ic:\program files\python37\include -Ic:\program files\python37\include -IC:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\ATLMFC\include -IC:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include -IC:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\ucrt -IC:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared -IC:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\um -IC:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\winrt -IC:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\cppwinrt /TcC:\cwin\tmp\tmprix0z7i7\src.win-amd64-3.7\multxyCmodule.c /FoC:\cwin\tmp\tmprix0z7i7\Release\cwin\tmp\tmprix0z7i7\src.win-amd64-3.7\multxyCmodule.obj
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\bin\HostX86\x64\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MT -IC:\cwin\tmp\tmprix0z7i7\src.win-amd64-3.7 -Ic:\program files\python37\lib\site-packages\numpy\core\include -Ic:\program files\python37\include -Ic:\program files\python37\include -IC:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\ATLMFC\include -IC:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include -IC:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\ucrt -IC:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared -IC:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\um -IC:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\winrt -IC:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\cppwinrt /TcC:\cwin\tmp\tmprix0z7i7\src.win-amd64-3.7\fortranobject.c /FoC:\cwin\tmp\tmprix0z7i7\Release\cwin\tmp\tmprix0z7i7\src.win-amd64-3.7\fortranobject.obj
compiling Fortran sources
Fortran f77 compiler: C:\cwin\bin\gfortran.exe -Wall -g -ffixed-form -fno-second-underscore -O3 -funroll-loops
Fortran f90 compiler: C:\cwin\bin\gfortran.exe -Wall -g -fno-second-underscore -O3 -funroll-loops
Fortran fix compiler: C:\cwin\bin\gfortran.exe -Wall -g -ffixed-form -fno-second-underscore -Wall -g -fno-second-underscore -O3 -funroll-loops
compile options: '-IC:\cwin\tmp\tmprix0z7i7\src.win-amd64-3.7 -Ic:\program files\python37\lib\site-packages\numpy\core\include -Ic:\program files\python37\include -Ic:\program files\python37\include -c'
gfortran.exe:f90: multxy.f90
C:\cwin\bin\gfortran.exe -Wall -g -Wall -g -shared ..\..\..\..\cwin\tmp\tmprix0z7i7\Release\multxy.o -L/usr/lib/gcc/x86_64-pc-cygwin/8.3.0 -Lc:\program files\python37\libs -Lc:\program files\python37\PCbuild\amd64 -o C:\cwin\tmp\tmprix0z7i7\Release\.libs\libmultxy.J7YCD6VUIR3DWPQ3PSLGVWZTCQ2KMJO6.gfortran-win_amd64.dll -Wl,--allow-multiple-definition -Wl,--output-def,C:\cwin\tmp\tmprix0z7i7\Release\libmultxy.J7YCD6VUIR3DWPQ3PSLGVWZTCQ2KMJO6.gfortran-win_amd64.def -Wl,--export-all-symbols -Wl,--enable-auto-import -static -mlong-double-64
/usr/lib/gcc/x86_64-pc-cygwin/8.3.0/../../../../x86_64-pc-cygwin/bin/ld: /usr/lib/gcc/x86_64-pc-cygwin/8.3.0/libgfortran.a(read.o): in function `_gfortrani_convert_real':
/usr/src/debug/gcc-8.3.0-1/libgfortran/io/read.c:173:(.text$_gfortrani_convert_real+0x85): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `strtoflt128'
/usr/lib/gcc/x86_64-pc-cygwin/8.3.0/../../../../x86_64-pc-cygwin/bin/ld: /usr/lib/gcc/x86_64-pc-cygwin/8.3.0/libgfortran.a(read.o): in function `_gfortrani_convert_infnan':
/usr/src/debug/gcc-8.3.0-1/libgfortran/io/read.c:249:(.text$_gfortrani_convert_infnan+0x5c): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `strtoflt128'
collect2: error: ld returned 1 exit status
error: Command "C:\cwin\bin\gfortran.exe -Wall -g -Wall -g -shared ..\..\..\..\cwin\tmp\tmprix0z7i7\Release\multxy.o -L/usr/lib/gcc/x86_64-pc-cygwin/8.3.0 -Lc:\program files\python37\libs -Lc:\program files\python37\PCbuild\amd64 -o C:\cwin\tmp\tmprix0z7i7\Release\.libs\libmultxy.J7YCD6VUIR3DWPQ3PSLGVWZTCQ2KMJO6.gfortran-win_amd64.dll -Wl,--allow-multiple-definition -Wl,--output-def,C:\cwin\tmp\tmprix0z7i7\Release\libmultxy.J7YCD6VUIR3DWPQ3PSLGVWZTCQ2KMJO6.gfortran-win_amd64.def -Wl,--export-all-symbols -Wl,--enable-auto-import -static -mlong-double-64" failed with exit status 1

我没有完全弄清楚f2py的问题,所以请不要因为这个不回答而叮嘱我。 我想要的只是在一些 fortran 周围放置一个简单的包装器。 我解决了这个问题,所以这篇文章是我的答案。 我发布它希望它可以帮助其他有类似问题的人。

发布后,我决定我需要降到较低的级别以弄清楚发生了什么。 由于f2py是基于C-api构建的,我决定直接使用它。 C - fortran 互操作性定义明确。 我得到了一些简单的代码来工作,但是当我开始查看通过 arrays 并阅读有关引用计数的内容时,我被吓到了。 所以,我认为C-api对于我的需求来说太低了。 Cython似乎倾向于编写可编译的类似 Python 的代码。 我终于选择了ctypes ,因为我真正需要的是转换内部 python 类型,然后调用(它认为是) c 代码。 周围有例子,但似乎没有一个完全适合,所以我会发布一些测试代码,希望它可以帮助其他人。 该示例显示了函数和子例程来回传递整数、双精度和 arrays。 The same code works in windows if .so is replaced with .dll .This information was helpful - How to dereference a memory location from python ctypes?

fortran 是:

Integer Function intfunc(n)
   integer, intent(in) :: n
   intfunc = n*n
end Function intfunc
! ---------------------------------------------------------------------------------------
subroutine Asub(acf,af)
   include 'defs.fi' !  integer, parameter :: float = selected_real_kind(12)
   Real(float), intent(in) :: acf
   Real(float), intent(out) :: af
   if(acf < 0.49)then
      af = 0.37464 + acf*(1.54226 - 0.26992*acf)
   else
      af = 0.379642 + acf*(1.48503 + acf*(-0.164423 + 0.016666*acf))
   endif
end subroutine Asub
! ---------------------------------------------------------------------------------------
Function Afactor(acf) result(af)
   include 'defs.fi'
   Real(float), intent(in) :: acf
   Real(float) :: af
   if(acf < 0.49)then
      af = 0.37464 + acf*(1.54226 - 0.26992*acf)
   else
      af = 0.379642 + acf*(1.48503 + acf*(-0.164423 + 0.016666*acf))
   endif
End Function Afactor
! ---------------------------------------------------------------------------------------
Function MultXY(x,y) result(z)
   include 'defs.fi'
   Real(float), intent(in) :: x,y
   Real(float)::z
   z = x*y
End Function MultXY
! ---------------------------------------------------------------------------------------
subroutine arrays(n,m,a)
   include 'defs.fi'
   integer, intent(in) :: n,m
   real(float), intent(out) :: a(n,m)
   integer :: i,j
   do j=1,m
      do i=1,n
         a(i,j) = real(100*i+j,float)
      enddo
   enddo
end subroutine arrays

代码通过以下方式编译成共享库:

gfortran -shared -o code.so code.f90 -fPIC -Xlinker -Map=code.map

它可以使用以下 python 代码运行。 这段代码中的许多步骤可以组合起来,但我认为将它们分解更能说明问题。 我不完全理解 function 原型(argtypes & restypes)。 他们似乎允许一些捷径,例如 Python 执行适当的演员。 有人可以详细说明吗?

import ctypes as ct
import numpy as np
from numpy.ctypeslib import ndpointer
flib = ct.CDLL('code.so')
flib.asub_.argtypes = [ct.POINTER(ct.c_double),ct.POINTER(ct.c_double)]
flib.afactor_.argtypes = [ct.POINTER(ct.c_double)]
flib.afactor_.restype = ct.c_double
flib.multxy_.argtypes = [ct.POINTER(ct.c_double),ct.POINTER(ct.c_double)]
flib.multxy_.restype = ct.c_double
flib.arrays_.argtypes = [ct.POINTER(ct.c_int),ct.POINTER(ct.c_int),ndpointer(ct.c_double)]
def main():
   nval = 4
   nptr = ct.pointer(ct.c_int(nval))
   # integer function intfunc(n)
   nx = flib.intfunc_(nptr)
   print('intfunc(',nval,') =',nx)
   x = 0.35
   xc = ct.c_double(x)
   yc = ct.c_double(0.50)
   zc = ct.c_double(0.0)
   # subroutine Asub(acf,af)
   flib.asub_(ct.byref(xc),ct.byref(zc))
   z = zc.value
   x = xc.value
   y = yc.value
   print(' x,z =',x,z)
   # Function Afactor(acf) result(af)
   z = flib.afactor_(ct.byref(xc))
   print(' x,z =',x,z)
   # Function MultXY(x,y) result(z)
   z = flib.multxy_(ct.byref(xc),ct.byref(yc))
   print('multxy(',x,y,') =',z)
   n = 3
   m = 4
   nc = ct.c_int(n)
   mc = ct.c_int(m)
   a = np.empty((m,n),dtype=np.double) # m,n not n,m
   # subroutine arrays(n,m,a)
   flib.arrays_(ct.byref(nc),ct.byref(mc),a)
   for i in range(n):   # note reversal of indices
      for j in range(m):
         print('i,j,a(j,i) =',i+1,j+1,a[j,i])
main()

output 是:

intfunc( 4 ) = 16
 x,z = 0.35 0.8813658067584037
 x,z = 0.35 0.8813658067584037
multxy( 0.35 0.5 ) = 0.175
i,j,a(j,i) = 1 1 101.0
i,j,a(j,i) = 1 2 102.0
i,j,a(j,i) = 1 3 103.0
i,j,a(j,i) = 1 4 104.0
i,j,a(j,i) = 2 1 201.0
i,j,a(j,i) = 2 2 202.0
i,j,a(j,i) = 2 3 203.0
i,j,a(j,i) = 2 4 204.0
i,j,a(j,i) = 3 1 301.0
i,j,a(j,i) = 3 2 302.0
i,j,a(j,i) = 3 3 303.0
i,j,a(j,i) = 3 4 304.0

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM