4

我想请教一下关于通过 C 函数调用 fortran 函数的问题。这些 C 函数将通过 cython 在 python 代码中使用。把事情放在一起,我有这个方案:

Cython 模块 -> C 函数 -> Fortran,其中 -> 表示“调用”。

目前我设法从 cython 调用 C 函数,但我很难调用 fortran 函数。你能帮我吗?(一个简单的例子会很棒)。

提前致谢。编辑:我正在使用 gcc 4.1.2。和 gfortran

4

3 回答 3

7

第一个答案中的链接描述了过时的方法。通过向 Fortran 添加 ISO C 绑定,从 C 调用 Fortran 或从 Fortran 调用 C 变得更加容易。使用此 Fortran 语言功能可指示 Fortran 编译器生成与 C 二进制兼容的可执行代码。程序员不必“破解”连接,因为它是语言的一部分,所以它与编译器和平台无关。从技术上讲,ISO C 绑定是 Fortran 2003 的一部分,但它已经在许多编译器中使用了好几年,例如,自 4.3 版以来的 gfortran 和 Intel ifort。

要从 C 中调用 Fortran 子例程或函数,请使用 bind C 选项声明 Fortran 子例程或函数,并使用绑定中为参数声明提供的 C 兼容类型。在“混合语言编程”下的 gfortran 手册中有示例。由于 ISO C 绑定是该语言的一部分,因此手册的这一部分很大程度上与编译器无关。Stack Overflow 和网络上其他地方的先前答案中还有其他示例。

这是要从 C 调用的子例程的 Fortran 子例程声明的快速代码片段(未经测试):

subroutine test ( varint1, varflt2 )  bind ( C, name="MyTest" )

   use iso_c_binding

   integer (kind=c_int32_t), intent (in) :: varint1
   real (kind=c_float), intent (out) :: varflt2

绑定 C 名称“MyTest”覆盖 Fortran 名称——它区分大小写,与 Fortran 不同。无需担心下划线!变量类型应该很明显......请参阅 gfortran 手册或其他地方了解可用的内容。

于 2010-12-08T03:30:15.257 回答
2

由于这是调试 HPC 代码的有用方法,因此这里有一个简单的 Fortran 中的“hello world”程序,从 Python 调用。

使用GNU Fortran (GCC) 9.3.0Python 3.7.3

你至少需要

  1. 带有 c 绑定的 fortran 代码(即bind(C),对于每个子例程/函数,以及iso_c_binding对于写入/输出的每个变量)。让我们称之为hello_fortran.f90
subroutine hello_fortran() bind(c)

    print *, "Hello world from fortran"

end subroutine hello_fortran

如果您不想使用 iso_c_bindings 修改原始 Fortran 代码,您还可以在 Fortran 中编写一个简单的包装函数,直接调用原始代码。

使用 编译此代码以在-c不链接的情况下进行编译,并-fPIC生成与位置无关的代码。 gfortran hello_fortran.f90 -c -fPIC -o hello_fortran.o 您可以直接链接 setup.py 中的目标文件,但我发现将所有内容捆绑到共享库 gfortran *.o -shared -o libhello_fortran.so 中并将当前工作目录添加到 PATH更容易export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:$(pwd)

2. 允许从 Python 调用 C 函数的 Cython 模块(或者,您可以使用 CFFI——方法类似)。对于我们的示例,我们称之为“hello_cython.pyx”

cdef extern:
    void hello_fortran()

def hello_cython():
    print("Called hello_cython")
    hello_fortran()

至关重要的是,对于您要调用的每个 Fortran 函数,您需要在cdef extern块中声明 C 接口。请记住,fortran 不区分大小写:此块中的所有内容都应为小写。

  1. setup.py用于“编译” Cython 模块的文件。不幸的是,这些很快就会变得非常复杂,所以下面给出的是一个最小的工作示例
from distutils.core import setup, Extension
from Cython.Build import cythonize
import numpy

files = ['hello_cython.pyx']

ext_module = Extension(
    name = "hello_cython_FI",
    sources = files,
    include_dirs = ['.'],
    library_dirs=['.'],
    libraries=["hello_fortran"]
    )

setup(
    name = "hello_cython_FI",
    ext_modules = cythonize(ext_module)
)

需要注意的重要事项是namePython 中将给出模块的名称,files必须包含.pyx文件,并且libraries必须具有共享库的名称(即 for libhello_fortran.so, write hello_fortran

编译这个python setup.py build_ext --inplace

  1. hello_python.py调用 hello_cython_FI的标准 Python 脚本
import hello_cython_FI

print("Called hello_python")
hello_cython_FI.hello_cython()

那么你应该得到

>>> python hello_python.py
Called hello_python
Called hello_cython
Hello world from fortran

在评论中询问 Intel、OpenMP 和 OpenMP 链接方法。

于 2020-05-25T16:07:04.750 回答
1

有一个名为 fwrap 的自动化工具,它生成 C、cython 和 python 到 fortran 例程的绑定。我认为它仍处于 beta 状态,但您可能会发现它很有帮助,链接在此处

于 2010-12-13T09:42:14.340 回答