如何修复 Cython 接口中的程序突然退出到 Fortran
How to fix abrupt program exit in Cython interface to Fortran
简短版
我有旧的 Fortran 代码,我正尝试通过 Cython 扩展模块对其进行包装来访问(已经为其他 Fortran 库完成了该操作)。当从 Fortran 内部调用时,该代码有效,但当通过 Cython 包装器访问时,它会强制程序停止,退出代码为 -1073741819 (0xC0000005)
或 -1
,并且没有其他消息。更重要的是:这个 崩溃是随机发生的 :有时 Fortran 代码设法 return,但 Python 脚本仍然在之后崩溃。
我不确定问题出在哪里,因为 Fortran 子例程有一个简单的签名,应该使界面相对简单。下面有更多详细信息(尽可能多地删减)。
非常感谢您的想法!
Cython 设置
相关文件:
mylib.lib
:原始 Fortran 库代码
wrapper.h
:Cython 的头文件
cython_module.pyx
: Cython 代码
wrapper.f90
:用于将 Fortran 库绑定到 C 代码的包装器代码
wrapper.o
: 获得使用ifort编译器编译Fortran wrapper。
命令:ifort wrapper.f90 /c /o wrapper.o /O3
setup.py
: 编译设置
这是编译设置文件。正如我之前提到的,我已经为其他 Fortran-Cython 界面使用了几乎相同的脚本,所以应该没问题,但是...
from distutils.core import setup
from Cython.Distutils import build_ext
from Cython.Distutils import Extension # Adds functionality to the standard distutils.extension.Extension
import Cython.Compiler.Options
from numpy import get_include
module_name = 'cython_module'
cython_interface = 'cython_module.pyx'
link_args = ['wrapper.o', 'mylib.lib']
fortran_libs = [ # Additional library directories for .lib files
r'C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2020.2.254\windows\compiler\lib\intel64_win'
]
# Generate an additional HTML file with some feedback on optimization quality
Cython.Compiler.Options.annotate = True
ext_modules = [Extension(
module_name,
[cython_interface],
# I need this for using Complex numbers in other library functions not shown here
define_macros=[("CYTHON_CCOMPLEX", "0")],
extra_compile_args=['/O2'],
extra_link_args=link_args,
library_dirs=fortran_libs,
cython_directives={'language_level': "3"}
)]
setup(name='cython_module',
cmdclass={'build_ext': build_ext},
# Needed if building with NumPy.
include_dirs=[get_include()],
ext_modules=ext_modules)
Cython 代码
cython_module.pyx
的内容:
import numpy as np
cdef extern from "<complex.h>": # You can ignore this
ctypedef struct _Dcomplex
cdef extern from "wrapper.h" nogil:
void py_indexh(double* a, double* b, long long* m, long long* n);
def indexh(double px, double py):
cdef long long[:] m = np.empty((1000,), dtype=np.int64, order='F')
cdef long long[:] n = np.empty((1000,), dtype=np.int64, order='F')
py_indexh(&px, &py, <long long*> m[0], <long long*> n[0])
return m, n
以及头文件(仅供参考,非常简单):
#include <complex.h>
extern void py_indexh(double* a, double* b, long long* m, long long* n);
Fortran 包装器
我只展示 Fortran 包装器,而不是整个库子例程主体,因为它相当长且令人费解,而且当从 Fortran 本身调用时它显然可以工作。这是:
subroutine py_indexh(a, b, M, N) bind(c)
use iso_c_binding, only: c_float, c_double, c_int, c_int32_t, c_int64_t, c_double_complex, c_bool
implicit none
interface
subroutine indexh(a, b, M, N)
real(8), intent(in) :: a, b
integer(8), intent(out) :: M(1000), N(1000)
end subroutine indexh
end interface
real(c_double), intent(in) :: a, b
integer(C_INT64_T), intent(out) :: M(1000), N(1000)
print *, 'Entering indexh from Fortran...'
call indexh(a, b, M, N)
print *, 'Exitted indexh from Fortran...'
end subroutine py_indexh
问题/输出
代码编译没有重大问题。仅显示此警告,我认为这与 .lib
文件的编译方式有关。请让我知道我是否应该对此更加担心,它对我所做的 Fortran 的其他 Cython 包装没有造成任何伤害:
LINK : warning LNK4098: defaultlib 'LIBCMT' conflicts with use of other libs; use /NODEFAULTLIB:library
当导入 cython 模块并调用 cython_module.indexh(3e-3, 4e-3)
时,它无提示地崩溃,退出代码为 -1
或 -1073741819 (0xC0000005)
。然而,在崩溃之前,Fortran 子例程已成功进入,因为 'Entering indexh from Fortran...'
打印在控制台上。有时,甚至显示第二个 print 'Exitted indexh from Fortran...'
,这应该表明子程序已完成。但是,无论显示一个还是两个打印,程序都会在函数调用后立即崩溃。
澄清一下,indexh(...)
的主体中没有奇怪的多线程业务或任何不寻常的东西,只有很多嵌套循环动作。
再次感谢任何帮助或想法!如果我可以显示更多信息,请告诉我。
<long long*> m[0], <long long*> n[0]
这会将 m
和 n
的第一个元素(即整数)转换为 long long*
.
你想要
&m[0], &n[0]
获取第一个元素的地址。
当编译器告诉您错误时,转换通常只是关闭编译器的一种方式。
简短版
我有旧的 Fortran 代码,我正尝试通过 Cython 扩展模块对其进行包装来访问(已经为其他 Fortran 库完成了该操作)。当从 Fortran 内部调用时,该代码有效,但当通过 Cython 包装器访问时,它会强制程序停止,退出代码为 -1073741819 (0xC0000005)
或 -1
,并且没有其他消息。更重要的是:这个 崩溃是随机发生的 :有时 Fortran 代码设法 return,但 Python 脚本仍然在之后崩溃。
我不确定问题出在哪里,因为 Fortran 子例程有一个简单的签名,应该使界面相对简单。下面有更多详细信息(尽可能多地删减)。
非常感谢您的想法!
Cython 设置
相关文件:
mylib.lib
:原始 Fortran 库代码wrapper.h
:Cython 的头文件cython_module.pyx
: Cython 代码wrapper.f90
:用于将 Fortran 库绑定到 C 代码的包装器代码wrapper.o
: 获得使用ifort编译器编译Fortran wrapper。 命令:ifort wrapper.f90 /c /o wrapper.o /O3
setup.py
: 编译设置
这是编译设置文件。正如我之前提到的,我已经为其他 Fortran-Cython 界面使用了几乎相同的脚本,所以应该没问题,但是...
from distutils.core import setup
from Cython.Distutils import build_ext
from Cython.Distutils import Extension # Adds functionality to the standard distutils.extension.Extension
import Cython.Compiler.Options
from numpy import get_include
module_name = 'cython_module'
cython_interface = 'cython_module.pyx'
link_args = ['wrapper.o', 'mylib.lib']
fortran_libs = [ # Additional library directories for .lib files
r'C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2020.2.254\windows\compiler\lib\intel64_win'
]
# Generate an additional HTML file with some feedback on optimization quality
Cython.Compiler.Options.annotate = True
ext_modules = [Extension(
module_name,
[cython_interface],
# I need this for using Complex numbers in other library functions not shown here
define_macros=[("CYTHON_CCOMPLEX", "0")],
extra_compile_args=['/O2'],
extra_link_args=link_args,
library_dirs=fortran_libs,
cython_directives={'language_level': "3"}
)]
setup(name='cython_module',
cmdclass={'build_ext': build_ext},
# Needed if building with NumPy.
include_dirs=[get_include()],
ext_modules=ext_modules)
Cython 代码
cython_module.pyx
的内容:
import numpy as np
cdef extern from "<complex.h>": # You can ignore this
ctypedef struct _Dcomplex
cdef extern from "wrapper.h" nogil:
void py_indexh(double* a, double* b, long long* m, long long* n);
def indexh(double px, double py):
cdef long long[:] m = np.empty((1000,), dtype=np.int64, order='F')
cdef long long[:] n = np.empty((1000,), dtype=np.int64, order='F')
py_indexh(&px, &py, <long long*> m[0], <long long*> n[0])
return m, n
以及头文件(仅供参考,非常简单):
#include <complex.h>
extern void py_indexh(double* a, double* b, long long* m, long long* n);
Fortran 包装器
我只展示 Fortran 包装器,而不是整个库子例程主体,因为它相当长且令人费解,而且当从 Fortran 本身调用时它显然可以工作。这是:
subroutine py_indexh(a, b, M, N) bind(c)
use iso_c_binding, only: c_float, c_double, c_int, c_int32_t, c_int64_t, c_double_complex, c_bool
implicit none
interface
subroutine indexh(a, b, M, N)
real(8), intent(in) :: a, b
integer(8), intent(out) :: M(1000), N(1000)
end subroutine indexh
end interface
real(c_double), intent(in) :: a, b
integer(C_INT64_T), intent(out) :: M(1000), N(1000)
print *, 'Entering indexh from Fortran...'
call indexh(a, b, M, N)
print *, 'Exitted indexh from Fortran...'
end subroutine py_indexh
问题/输出
代码编译没有重大问题。仅显示此警告,我认为这与 .lib
文件的编译方式有关。请让我知道我是否应该对此更加担心,它对我所做的 Fortran 的其他 Cython 包装没有造成任何伤害:
LINK : warning LNK4098: defaultlib 'LIBCMT' conflicts with use of other libs; use /NODEFAULTLIB:library
当导入 cython 模块并调用 cython_module.indexh(3e-3, 4e-3)
时,它无提示地崩溃,退出代码为 -1
或 -1073741819 (0xC0000005)
。然而,在崩溃之前,Fortran 子例程已成功进入,因为 'Entering indexh from Fortran...'
打印在控制台上。有时,甚至显示第二个 print 'Exitted indexh from Fortran...'
,这应该表明子程序已完成。但是,无论显示一个还是两个打印,程序都会在函数调用后立即崩溃。
澄清一下,indexh(...)
的主体中没有奇怪的多线程业务或任何不寻常的东西,只有很多嵌套循环动作。
再次感谢任何帮助或想法!如果我可以显示更多信息,请告诉我。
<long long*> m[0], <long long*> n[0]
这会将 m
和 n
的第一个元素(即整数)转换为 long long*
.
你想要
&m[0], &n[0]
获取第一个元素的地址。
当编译器告诉您错误时,转换通常只是关闭编译器的一种方式。