【问题标题】:How do you bind a language (python, for example) to another (say, C++)?如何将一种语言(例如 python)绑定到另一种语言(例如 C++)?
【发布时间】:2009-09-25 05:55:40
【问题描述】:

我远不是 python 专家,但我一直听到这个,关于它的 C/C++ 绑定。这个概念是如何工作的,Python(和 Java)如何绑定到基于 C 的 API,如 OpenGL?这东西对我来说一直是个谜。

【问题讨论】:

  • 您的意思是在编程级别,即您将如何使用这些绑定,还是在技术级别上它是如何工作的,即实际调用是如何进行的?
  • 无论如何,您现在已经有了答案。 :)
  • Java 使用 native 关键字:stackoverflow.com/questions/6101311/…

标签: java python binding


【解决方案1】:

用 C89 编写的带有反射的解释器,谁知道?


我感觉您正在寻找有关机制的解释,而不是指向 API 的链接或有关如何对其进行编码的说明。所以,据我了解。 . .

主解释器通常是用 C 语言编写的,并且是动态链接的。在动态链接的环境中,即使是 C89 也有一定的反射行为。特别是,dlopen(3)dlsym(3) 调用将加载动态(通常是 ELF)库并查找由字符串命名的符号的地址。给出那个地址,解释器可以调用一个函数。即使是静态链接,解释器也可以知道其名称编译到其中的 C 函数的地址。

那么,只需让解释后的代码告诉解释器调用特定本机库中的特定本机函数即可。

该机制可以是模块化的。用脚本编写的解释器扩展库本身可以调用 dlopen(3)dlsym(3) 的裸钩,并连接到解释器从未知道的新库。

对于按值传递简单对象,一些原型函数通常允许各种调用。但是对于结构化数据对象(想象一下 stat(2)),包装器模块需要知道数据的布局。在某些时候,无论是在打包扩展模块时还是在安装它时,C 接口模块都会包含适当的头文件,并结合手写代码构造一个接口对象。这就是为什么您可能需要安装类似libsqlite3-dev 的东西,即使您的系统上已经有sqlite3;只有-dev 包有重新编译链接代码所需的.h 文件。

我想我们可以这样总结:“这是用蛮力和无知完成的”。 :-)

【讨论】:

    【解决方案2】:

    主要的一般概念被称为FFI,“外来函数接口”——对于Java,它是JNI,对于Python,它是“Python C API”,对于Perl,它是XS,等等,但我认为这很重要为您提供艺术的一般术语,以帮助您更彻底地研究它。

    给定一个 FFI,您可以编写(例如)直接尊重它的 C 程序,和/或您可以使用代码生成器从接收到的元信息生成此类 C 代码和/或从其他语言编写的代码(通常使用一些帮助,例如,为了驱动 SWIG 代码生成器,您通常使用 SWIG 特定的额外信息来装饰 .h C 头文件中的信息以获得更好的包装器)。

    还有一些特殊的语言,例如 Cython,它是 Python 的“扩展子集”,旨在轻松生成 FFI 代码,同时匹配 Python 的大部分语法和语义——对于大多数 Python 程序员来说,这通常是最简单的方法编写一个 Python 扩展模块,它可以编译成快速的机器代码,并且可能使用一些现有的 C 可调用库。

    ctypes 方法不同于传统的 FFI 方法,尽管它自我描述为“Python 的外部函数库”——它依赖于 DLL(或等效项,例如.so Linux 中的动态库),并在运行时生成并执行代码以访问此类动态加载的 C 代码(通常所有这些都是通过 Python 中的显式编程完成的——我不知道基于自省和 ctypes 的 ctypes 包装器-代码生成,但是)。方便避免为使用 Python 访问现有 DLL 的简单任务安装任何特殊的东西,但我认为它的扩展性不如 FFI“基于链接器”的方法(因为它需要更多的运行时消耗等) .除了 Python 的 ctypes 之外,我不知道这种方法的任何其他实现,针对其他语言(我想有些确实存在,鉴于当今 DLL 和 .so 包装的流行,并且很想了解它们)。

    【讨论】:

      【解决方案3】:

      通常这些语言都有一种加载用 C 编写的扩展的方法。Java 接口称为 JNI(Java Native Interface)。 Python有全面的documentation关于它的扩展接口。

      Python 的另一个选项是ctypes 模块,它允许您使用可动态加载的 C 库,而无需编写自定义扩展代码。

      【讨论】:

        【解决方案4】:

        下面的概念可以相对容易地概括,但是为了清楚起见,我将专门提到 C 和 Python。

        从 Python 调用 C

        这是可行的,因为大多数较低级别的语言/架构/操作系统都有定义明确的应用程序二进制接口,这些接口指定了应用程序如何与彼此以及操作系统交互的所有低级细节。例如,x86-64(AMD64) 的 ABI:AMD64 System V Application Binary Interface。它指定了所有细节,例如函数调用约定和链接 C 对象文件。

        有了这些信息,由语言实现者来决定

        1. 实现语言的 ABI 你想打电话给

        2. 通过 语言/库访问 实施

        (1) 实际上在大多数语言中几乎是免费获得的,因为它们的解释器/编译器是用 C 编码的,这显然支持 C ABI :)。这也是为什么难以从非 C 语言的实现调用 C 代码的原因,例如 IronPython(C# 中的 Python 实现)和 PyPy(Python 中的 Python 实现)对调用 C 代码没有特别好的支持,尽管我相信 IronPython 已经在这方面做了一些工作。

        所以为了具体化,假设我们有 CPython(Python 的标准实现,用 C 语言完成)。我们免费获得 (1),因为我们的解释器是用 C 编写的,并且我们可以从解释器访问 C 库,就像从任何其他 C 程序(dlopen、LoadLibrary 等)访问 C 库一样。现在我们需要为用我们的语言写作的人们提供一种访问这些设施的方法。 Python 通过The Python C/C++ APIctypes 执行此操作。每当程序员使用这些 API 编写代码时,我们都可以执行相应的库加载/调用代码来调用库。

        从 C 调用 Python

        这个方向其实解释起来稍微简单一些。继续前面的例子,我们的解释器,CPython 只不过是一个用 C 编写的程序,所以它可以导出函数并被编译为库/链接到我们想用 C 编写的任何程序。CPython 导出一组 C用于访问/运行 Python 程序的函数,我们可以调用这些函数从我们的应用程序中运行 Python 代码。例如 CPython 库导出的函数之一是:

        PyObject* PyRun_StringFlags(const char *str, int start, PyObject *globals, PyObject *locals, PyCompilerFlags *flags)¶
        

        返回值:新引用。

        从str中执行Python源代码 指定的上下文 字典 globals 和 locals 与 flags 指定的编译器标志。 参数 start 指定 应该用于的启动令牌 解析源代码。

        我们可以通过向这个函数传递一个包含有效 Python 代码(以及执行所需的其他一些细节)的字符串来执行 Python 代码。有关详细信息,请参阅 Embedding Python in another application

        【讨论】:

          【解决方案5】:

          c/c++与python的集成基本上有两种方式:

          • 扩展:从 python 访问 c/c++
          • 嵌入:从 c/c++ 访问 python 解释器

          你提到的是第一种情况。它通常通过编写包装函数来实现,该函数充当不同语言之间的粘合代码,将函数参数和数据类型转换为匹配所需的语言。通常使用名为SWIG 的工具来生成此胶水代码。

          有关详细说明,请参阅tutorial

          【讨论】:

            【解决方案6】:

            对于 Perl,有两种方法可以调用 C++ 子例程:

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2014-11-04
              • 2011-01-04
              • 2014-12-27
              • 2012-06-26
              • 2011-05-07
              • 1970-01-01
              • 2016-04-28
              相关资源
              最近更新 更多