链接四元数学库?用ctypes代替fortran包装器?

2024-10-02 06:23:08 发布

您现在位置:Python中文网/ 问答频道 /正文

更新日期: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 它会产生链接错误。在成吨的产出中,我收到了关于strtoflt128的抱怨。这是gnu gcc四元数学库中的一个函数。我的flt类型相当于C中的double。代码中没有四元数学,所以为什么要使用它?我试图创建一个扩展文件,看看它是否能告诉我什么,但它仍然试图链接,所以没有生成(或保存)任何代码。 此时,我使用strtofl128构建了一个小型c程序。如果我包含quadmath库,它会编译并链接:gcc main.c -lquadmath 它运行不正确,但这是我稍后将研究的内容。 我相信实际的quadmath库文件是…./cwin/lib/gcc/x86_64-pc-cygwin/8.3.0/libquadmath.a。运行f2py的输出显示了这个目录,因此您可能认为它链接了库。我试过用各种不同的-l选项运行f2py。通常它会抱怨找不到图书馆。我得到了一个变种工作,但链接仍然失败。 我还使用了一个整数函数:

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

我已经能够创建一个dll并从python调用它,而不需要使用f2py。它似乎通过f2py运行很好。它创建一个文件intfunc.cp37-win_amd64.pyd和一个目录,其中包含一个名称巨大的.dll。我还不能从python调用它,但我会继续努力。你知道吗

问题:

  1. 为什么f2py使用quad precision?有没有办法避免使用它?你知道吗
  2. 如何包含正确的库?你知道吗
  3. 如何在不调用链接器的情况下创建C扩展代码?你知道吗
  4. Cygwin和MinGW之间会有冲突吗?如何避免?你知道吗
  5. f2py准备好黄金时间了吗?使用C扩展实现手动接口会更简单吗?你知道吗
  6. f2py能处理fortran函数吗?有几个地方建议使用子程序?你知道吗

f2py被吹捧为易于使用。也许是的,但只有在你让它正常工作之后。我已经接触不同的语言25年了,例如c/c++、fortran、excel/vba、matlab/octave,几乎没有这么多困难。这似乎是一个程序,做了很多,这是隐藏在封面下,这使它很难排除故障。你知道吗

一个问题是运行f2py的输出与核心转储一样容易读取。运行时的输出是:

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

Tags: buildsrcincludeenableusrwintmpx86
1条回答
网友
1楼 · 发布于 2024-10-02 06:23:08

我没有准确地找出问题所在,所以请不要因为这个不回答而责怪我。我只想用一个简单的包装器包装一些fortran。我解决了这个问题,所以这篇文章是我的答案。我张贴它,希望它可以帮助其他人与类似的问题。你知道吗

在这篇文章发表后,我决定我需要降到一个较低的级别来弄清楚到底发生了什么。由于f2py是基于C-api构建的,所以我决定直接使用它。C-fortran互操作性定义良好。我得到了一些简单的代码来工作,但当我开始研究传递数组和阅读有关引用计数的内容时,我被吓坏了。因此,我决定C-api对于我的需求来说,它的级别太低了。Cython似乎倾向于编写可编译的类似Python的代码。我最终决定使用ctypes,因为我真正需要的是转换内部python类型,然后调用(它认为是)c代码。这里有一些例子,但似乎没有一个完全适合,所以我将张贴一些测试代码,希望它可以帮助其他人。该示例显示函数和子例程来回传递int、double和数组。如果.so.dll替换,那么同样的代码在windows中也可以工作

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代码运行。这段代码中的许多步骤可以组合在一起,但我认为分解它们更能说明问题。我不完全理解函数原型(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()

输出为:

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

相关问题 更多 >

    热门问题