FreeCAD(06)— Python与C++互操作

先简单梳理一下,以后慢慢研究。

FreeCAD的Python绑定机制

1. 基础架构:PyObjectBase

FreeCAD中所有需要导出到Python的C++类都继承自PyObjectBase基类。这个基类提供了C++对象与Python对象之间的桥接功能,包含了Python对象头部结构和各种Python C API的包装方法。

2. XML接口定义

FreeCAD使用XML文件来定义Python绑定的接口。例如,Mesh模块的Python绑定在MeshPy.xml中定义,其中指定了导出的类名、命名空间、继承关系和要导出的方法。

3. 代码生成系统

FreeCAD使用模板系统自动从XML定义生成C++绑定代码。这个系统会生成必要的C++包装器代码,实现Python对象与C++对象之间的转换。

4. Python模块注册

每个模块都实现一个继承自Py::ExtensionModule的类来创建Python模块。这个模块类注册了要导出的函数和方法。

5. 模块初始化

通过PyMOD_INIT_FUNC宏定义的模块入口点函数,调用initModule()函数创建并注册模块到Python命名空间。最终通过Base::Interpreter().addModule()将扩展模块添加到Python环境中。


PyObjectBase 类型

FreeCAD的Python绑定系统基于PyObjectBase基类,这是所有需要导出到Python命名空间的C++类的基础类。该类提供了Python对象的标准接口,包括属性访问、方法调用和生命周期管理。FreeCAD 中几乎所有关键类都需要在 Python 中可见,以便用于宏录制(macro recording)和自动化(automation)目的。
Python绑定系统的基础代码位于PyObjectBase.h文件中,这篇文章就主要讲解该文件中的内容。

1
2
3
4
5
6
class BaseExport PyObjectBase : public PyObject //NOLINT
{
      Py_Header  // 注入 Python 类型元信息

      // ... 其他成员 ...
};

PyObject实际上是struct _object,可以理解为所有Python对象的根类型。
Py_Header宏:

1
2
3
4
5
#define Py_Header                                           \
public:                                                     \
    static PyTypeObject   Type;                             \
    static PyMethodDef    Methods[];                        \
    virtual PyTypeObject *GetType(void) {return &Type;}

通过宏展开注入 Type 类型对象和 Methods 方法表使 PyObjectBase 子类在 Python 中表现为完整类型。

  • Type 是 Python 类型对象,使 C++ 类能在 Python 中表现为完整类型。
  • Methods 是 Python 方法表,通过 PyMethodDef 数组声明所有可导出方法。

为了简化从PyObjectBase类继承并定义导出到 Python 的新方法,FreeCAD还提供了一些便捷的宏(macro):

  • PYFUNCDEF_D 定义一个新的导出方法。
  • PYFUNCIMP_D 定义这个新导出方法的具体实现。在实现的时候,可以使用 Py_Return、Py_Error、Py_Try 和 Py_Assert 等宏。
  • PYMETHODEDEF 宏用于在 Python 方法表中创建对应的条目。
comments powered by Disqus