cppyy 顶层#

cppyy 在模块级别提供了一些辅助函数,这些函数提供(直接)访问 Cling 解释器的功能(任何 C++ 代码总是通过全局命名空间 cppyy.gbl 访问)。文档中会频繁使用这些辅助函数,因此它们首先在这里列出,但通过 Python 解释器本身使用 help() 函数可以更方便地访问它们的文档。

import cppyy
help(cppyy)
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[1], line 1
----> 1 import cppyy
      2 help(cppyy)

ModuleNotFoundError: No module named 'cppyy'

cppyy 加载 C++#

C++ 代码可以作为文本加载并即时编译(JIT),或者提前编译并以共享库的形式提供。在后一种情况下,还需要加载 C++ 头文件以向 Cling 声明类、函数和变量。除了头文件,还可以使用预编译代码;特别是所有标准 C++ 头文件和一些系统头文件在启动时都已预编译。cppyy 提供了以下辅助工具来加载 C++ 代码:

  • cppdef: 直接访问解释器。此函数接受 C++ 声明作为字符串并即时编译(JIT)它们(在实际使用之前不会创建绑定)。代码被加载到全局范围内,因此从一个 cppdef 调用到下一个调用,任何先前加载的代码以及所有已通过预编译头文件加载的标准 C++ 头文件都是可用的。示例:

cppyy.cppdef(r"""\
void hello() {
    std::cout << "Hello, World!" << std::endl;
}""")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[2], line 1
----> 1 cppyy.cppdef(r"""\
      2 void hello() {
      3     std::cout << "Hello, World!" << std::endl;
      4 }""")

NameError: name 'cppyy' is not defined
cppyy.gbl.hello()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[3], line 1
----> 1 cppyy.gbl.hello()

NameError: name 'cppyy' is not defined
  • cppexec: 直接访问解释器。此函数接受 C++ 语句作为字符串,即时编译并执行它们。就像 cppdef 一样,执行在全局范围内进行,所有先前加载的代码都是可用的。如果语句是声明,效果与 cppdef 相同,但 cppexec 也接受可执行的代码行。示例:

cppyy.cppexec(r"""std::string hello = "Hello, World!";""")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[4], line 1
----> 1 cppyy.cppexec(r"""std::string hello = "Hello, World!";""")

NameError: name 'cppyy' is not defined
cppyy.cppexec("std::cout << hello << std::endl;")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[5], line 1
----> 1 cppyy.cppexec("std::cout << hello << std::endl;")

NameError: name 'cppyy' is not defined
  • include: 将声明加载到解释器中。此函数接受来自文件的 C++ 声明,通常是头文件。文件通过给定给 Cling 的包含路径来定位。示例:

cppyy.include("vector")   # equivalent to "#include <vector>"
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[6], line 1
----> 1 cppyy.include("vector")   # equivalent to "#include <vector>"

NameError: name 'cppyy' is not defined
  • c_include: 将声明加载到解释器中。此函数接受来自文件的 C++ 声明,通常是头文件。名称修饰是 C 和 C++ 代码之间的一个重要区别。使用 c_include 而不是 include 可以防止名称修饰。

  • load_library: 将编译好的 C++ 代码加载到解释器中。此函数接受共享库的名称,并将其加载到当前进程中,将所有外部符号暴露给 Cling。库通过给定给 Cling 的加载路径来定位,可以通过“-L”编译器标志或动态搜索路径环境变量(系统依赖)来实现。任何将符号引入进程的方法(包括常规链接,例如在 C++ 应用程序中嵌入 Python 时)都适合用于暴露符号。作为 load_library 的替代方案,例如可以使用ctypes.CDLL,但该函数并非在所有平台上都支持动态加载路径。

如果在使用上述辅助函数中的任何一个对 C++ 代码进行即时编译(JIT)时发生编译错误,会引发 Python SyntaxError 异常。如果发生编译警告,则会发出 Python 警告。

cppyy 配置 Cling#

当加载模块时,通常方便地为 Cling 添加额外的搜索路径以查找头文件和库(Python 没有标准位置来放置头文件和库,但通常可以根据模块的位置推断出它们的位置,即其 __file__ 属性)。cppyy 提供了以下两个辅助函数:

  • add_include_path: 为 Cling 添加额外的路径以查找头文件。

  • add_library_path: 为 Cling 添加额外的路径以查找库。

这两个函数都接受一个字符串(单个路径)或一个列表(用于添加多个路径)。允许使用相对路径,但建议使用绝对路径。

cppyy C++ 语言#

一些 C++ 编译时特性在 Python 中没有等效项。相反,提供了便利函数:

  • sizeof: 接受一个代理的 C++ 类型或其名称作为字符串,并返回存储大小(以 char 为单位)。

  • typeid: 接受一个代理的 C++ 类型或其名称作为字符串,并返回 C++ 运行时类型信息(RTTI)。

  • nullptr: C++ NULL

cppyy 预处理器#

在 Python 端,预处理器宏(#define)不可用,因为没有可用的类型信息。然而,它们通常用于常量数据(例如标志或数字;请注意,现代 C++ 推荐使用 constconstexpr)。在限制范围内,表示常量数据的宏可以通过 macro 辅助函数访问。示例:

import cppyy
cppyy.cppdef('#define HELLO "Hello, World!"')
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[7], line 1
----> 1 import cppyy
      2 cppyy.cppdef('#define HELLO "Hello, World!"')

ModuleNotFoundError: No module named 'cppyy'
cppyy.macro("HELLO")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[8], line 1
----> 1 cppyy.macro("HELLO")

NameError: name 'cppyy' is not defined