【问题标题】:interfacing Python, C, and Fortran连接 Python、C 和 Fortran
【发布时间】:2015-05-13 22:56:45
【问题描述】:

我已经为 python 编写了一个 C 扩展(使用 Python/C API),它使用 distutils 构建并且运行良好。现在我想在 C 代码中添加一些 Fortran 例程的包装器。我正在寻找的最终结果是一个调用 Fortran 函数的 C 函数的 python 函数。

这可能吗?我可以成功地从 Python 调用 C,从 C 调用 Fortran,但是我无法将这三者结合起来。有任何想法吗?谢谢!


已编辑 这是我想要的结构的更详细示例:

假设我有一个名为 fortranfunc.f90 的 Fortran 例程和一个名为 cfunc.c 的 C 代码,其格式如下:

#include <Python.h> 
#include<numpy/arrayobject.h> 

static PyObject *cfunc(PyObject *self, PyObject *args); 
extern double fortranfunc_(double*);  

static PyObject *cfunc(PyObject *self, PyObject *args)
{       
     /* a bunch of C code here to calculate the double x */

      y = fortranfunc_(&x);   //now call the fortran function

     /* now finish up using the value of y returned by the fortran function */
}       

static PyMethodDef cfunc_methods[] = {{"cfunc", cfunc, METH_VARARGS, NULL},{NULL}};

void initcfunc(void)
{
      Py_InitModule("cfunc", cfunc_methods);
      import_array();
}

我正在尝试使用类似这样的 setup.py 文件来构建它:

from distutils.core import setup, Extension
import numpy as np

module1 = Extension('cfunc', sources = ['cfunc.c'])

setup (name = 'cfunc',
        version = '1.0',
        include_dirs = [np.get_include()],
        ext_modules = [module1])

但是我不知道如何处理对fortranfunc.f90的依赖。

我希望这是独立于平台的 - 如果这不可能,我会寻找另一种解决方案!感谢您迄今为止提出的所有建议。

【问题讨论】:

  • 您可以为 Fortan 代码使用 C 包装器。不确定这两种语言是否兼容 ABI。我想这取决于目标平台。如果包装器只是以 1:1 的比例转发所有参数,这甚至可能不会生成实际代码。
  • 是的,这是可能的(我以前做过)。正确的方法取决于您的编译器和操作系统。在编译 C 代码和 Fortran 代码时,您现在使用哪些编译器标志?
  • Fortran 和 C 的互操作性甚至在标准中。请参阅 fortran-iso-c 绑定...
  • 你想要 C 放在中间有什么特别的原因吗?
  • @IgnacioVazquez-Abrams:问我?只是一个建议。但是,如果 ABI 允许,它可能只需要一个 C 头文件和一个适当的 Python/C-API 模块。我只是不确定。那时,我为 Pascal 准备了一些东西,它主要需要 C-header 中的函数来反转参数列表。但那是十多年前的事了。

标签: python c fortran fortran-iso-c-binding


【解决方案1】:

我建议您考虑 NumPy 对 distutils 的扩展,它带来了对 Fortran http://docs.scipy.org/doc/numpy/reference/distutils.html 的支持。

值得注意的是,您可以像添加 .c 源文件一样包含 Fortran 源文件

from numpy.distutils.core import Extension, setup

setup(name='hw',
       ext_modules=[Extension(name='hw', sources=['../hw.f'])],
       )

根据Combining Python with Fortran, C and C++.

【讨论】:

    【解决方案2】:

    一般来说,你可以在任何OBJ文件或LIB中调用任何导出的函数,但是当涉及到不同语言的不同编译器时,问题就开始了。

    虽然它不是标准,但通常是一种语言编译器可以方便地装饰/修改外部符号以供链接器稍后使用。因此,例如在 c 源代码中以名称 "printf" 定义的 c 库中的函数将在目标文件中修饰为 "_printf" 然后当您尝试从另一种语言编译器调用它时,该语言编译器可能会跟随不同的装饰规则。因此,当您在 python 源代码中使用它的名称 "printf" 声明它时,编译器会将其修改为其他名称,例如 _printf_

    稍后,当链接器尝试解析 C 库和您的 python 目标文件之间的外部符号时,他会发现 "_printf""_printf_" 之间不匹配,这将引发致命错误并停止构建可执行文件。

    http://en.wikipedia.org/wiki/Name_mangling

    【讨论】:

    • 添加像_ 这样的后缀或前缀在 80 年代和部分 90 年代很常见,但现在已经不常见了。所以你应该把你的陈述相对化。例如,gcc 不再像那样修改外部符号(如果它在过去曾经做过 - 比如说 - 15 年)。但是,特别是对于 Fortran,这可能是可能的。但更成问题的是函数参数的编组、寄存器文件布局和复合数据类型的打包。对于标量类型,大多有简单的解决方案,因为它们大多数时候是由硬件处理的。
    • Python 是一种解释型语言;它不像 C 代码那样链接。这是关于提供一个在编译代码和 Python 程序之间进行接口的 C 模块。 Python 二进制文件确实存在,但它们是字节码(类似于 Java)并在运行时加载。此外,Python 代码的命名空间完全独立于编译/链接的代码。
    【解决方案3】:

    如果 C 代码的唯一目的是充当包装器以允许您在 Python 中运行 Fortran 代码,那么使用f2py 直接从 Fortran 代码生成 Python 模块可能会更好。

    【讨论】:

    • 我的大部分代码是用 C 编写的,所以很遗憾我不能直接从 python 调用 Fortran。
    • 如果功能可以分开,你可以创建两个模块。
    • 不幸的是他们不是——否则我会这样做!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-18
    • 2013-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多