|
|
| src/Main/MainCmd.cpp |
CLI版本的入口程序 |
| src/Main/MainGui.cpp |
GUI版本的入口程序 |
| src/Main/MainPy.cpp |
Python模块(FreeCAD)的初始化函数,负责在Python环境中加载FreeCAD核心功能 |
| src/Main/FreeCADGuiPy.cpp |
Python模块(FreeCADGui)的初始化函数,负责在Python环境中加载FreeCADGui核心功能 |
1. Python模块初始化
FreeCAD定义了宏——PyMOD_INIT_FUNC来辅助实现Python模块的初始化函数:
1
|
#define PyMOD_INIT_FUNC(name) PyMODINIT_FUNC PyInit_##name(void)
|
这里的PyMODINIT_FUNC其实是 Python/C API 库中的一个宏,在 Python 3 中,PyMODINIT_FUNC 就是 PyObject*,表示函数返回值。
PyInit_xxx(void),就是模块的初始化函数,它在import模块时执行,并返回一个Python模块对象。
2. FreeCAD模块初始化
FreeCAD模块初始化函数定义在MainPy.cpp中:
1
2
3
4
5
6
7
8
|
PyMOD_INIT_FUNC(FreeCAD)
{
// ......
// 这个函数负责Python模块的初始化。
// ......
return module; // 返回模块对象
}
|
这个宏(PyMOD_INIT_FUNC)展开就是:
1
2
3
4
5
6
|
PyObject* PyInit_FreeCAD(void)
{
// ......
return module; // 返回一个 PyObject* 类型的对象
}
|
我们复制 “PyMOD_INIT_FUNC(” 到FreeCAD工程源码中搜索,就能看到都有那些模块。
3. FreeCADGui模块初始化
加载FreeCADGui模块时会先加载FreeCAD模块。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
// FreeCADGuiPy.cpp
PyMOD_INIT_FUNC(FreeCADGui)
{
try {
Base::Interpreter().loadModule("FreeCAD"); // 加载FreeCAD模块, Base::Interpreter()返回 Python 解释器单例
App::Application::Config()["AppIcon"] = "freecad";
App::Application::Config()["SplashScreen"] = "freecadsplash";
App::Application::Config()["CopyrightInfo"] = "\xc2\xa9 Juergen Riegel, Werner Mayer, Yorik van Havre and others 2001-2024\n";
App::Application::Config()["LicenseInfo"] = "FreeCAD is free and open-source software licensed under the terms of LGPL2+ license.\n";
App::Application::Config()["CreditsInfo"] = "FreeCAD wouldn't be possible without FreeCAD community.\n";
if (Base::Type::fromName("Gui::BaseView").isBad()) {
Gui::Application::initApplication();
}
static struct PyModuleDef FreeCADGuiModuleDef = {PyModuleDef_HEAD_INIT, // 这个参数是固定的。
"FreeCADGui", // 模块名称
"FreeCAD GUI module\n", // 模块的描述
-1, // 模块实例的大小(-1 表示动态分配)
FreeCADGui_methods, // 模块导出的方法表
nullptr,
nullptr,
nullptr,
nullptr};
PyObject* module = PyModule_Create(&FreeCADGuiModuleDef); // 创建模块对象
return module;
}
catch (const Base::Exception& e) {
PyErr_Format(PyExc_ImportError, "%s\n", e.what());
}
catch (...) {
PyErr_SetString(PyExc_ImportError, "Unknown runtime error occurred");
}
return nullptr;
}
|
上面代码中涉及到一个struct PyModuleDeff结构体类型, 这是定义 Python 模块的核心结构体。它描述了模块的基本信息、方法、资源管理等。
1
2
3
4
5
6
7
8
9
10
11
|
struct PyModuleDef {
PyModuleDef_Base m_base; // 这个参数是固定的,就是PyModuleDef_HEAD_INIT
const char* m_name; // 模块名称
const char* m_doc; // 模块文档字符串
Py_ssize_t m_size; // 模块实例的大小(-1 表示动态分配)
PyMethodDef *m_methods; // 模块导出的方法表
PyModuleDef_Slot *m_slots; // 模块的插槽(slots)
traverseproc m_traverse; // 遍历函数(垃圾回收)
inquiry m_clear; // 清理函数(垃圾回收)
freefunc m_free; // 释放函数
};
|
这里面需要注意的是PyMethodDef m_methods成员,这是模块的方法列表,PyMethodDef结构的原型是:
1
2
3
4
5
6
7
|
struct PyMethodDef
{
const char *ml_name; // 定义该方法在 Python 中的名称(即用户调用时使用的函数名)。
PyCFunction ml_meth; // 指向实现该方法的 C 函数指针。
int ml_flags; // 标志位组合,描述该方法的参数规则和行为。
const char *ml_doc; // 方法的描述
};
|
FreeCADGui的模块方法列表如下(m_methods参数),包含5个核心GUI操作方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
struct PyMethodDef FreeCADGui_methods[] = {
// 创建并显示主窗口
{"showMainWindow",
FreeCADGui_showMainWindow,
METH_VARARGS,
"showMainWindow() -- Show the main window\n"
"If no main window does exist one gets created"},
// 启动GUI事件循环
{"exec_loop",
FreeCADGui_exec_loop,
METH_VARARGS,
"exec_loop() -- Starts the event loop\n"
"Note: this will block the call until the event loop has terminated"},
// 设置非GUI模式
{"setupWithoutGUI",
FreeCADGui_setupWithoutGUI,
METH_VARARGS,
"setupWithoutGUI() -- Uses this module without starting\n"
"an event loop or showing up any GUI\n"},
{"embedToWindow",
FreeCADGui_embedToWindow,
METH_VARARGS,
"embedToWindow() -- Embeds the main window into another window\n"},
{nullptr, nullptr, 0, nullptr} /* sentinel */
};
|