【问题标题】:Cython, C and FortranCython、C 和 Fortran
【发布时间】:2010-12-08 02:41:02
【问题描述】:

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

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

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

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

【问题讨论】:

  • 更准确的答案可能需要了解您所询问的特定 C 和 Fortran 编译器。
  • 已编辑。对不起,我忘记了:)
  • 你知道fwrap吗?

标签: python c fortran cython


【解决方案1】:

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

要从 C 调用 Fortran 子例程或函数,请使用绑定 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 手册或其他地方了解可用的内容。

【讨论】:

  • 嗯,我想我可以做到,而无需修改 fortran 代码,因为它是作为黑匣子给我的。我只是设法做到了,感谢您的见解,非常感谢:)
【解决方案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 并使用export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:$(pwd)将当前工作目录添加到PATH

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)
)

需要注意的重要事项是name 将给出 Python 中模块的名称,files 必须包含 .pyx 文件,libraries 必须具有共享库的名称(即用于libhello_fortran.so,写hello_fortran)

python setup.py build_ext --inplace编译它

  1. 标准 Python 脚本 hello_python.py 调用 hello_cython_FI
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

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-18
      • 2015-04-28
      相关资源
      最近更新 更多