PyAPI_xxx#
在cpython源码中, 可以看到很多地方使用了PyAPI_DATA, PyAPI_FUNC, PyMODINIT_FUNC, 我们一起来看看这些都是什么。 在pyport.h中,我们可以看到对它们的定义(摘选部分)
以下代码中会用到的一些宏标识符,先进行一下说明: - Py_ENABLE_SHARED
值为1 ,windows平台下,Python核默认在DLL中,允许外部链接性 -
HAVE_DECLSPEC_DLL
所有windows编译器和cygwin均会定义,用于支持__declspec(). - Py_BUILD_CORE
构建Python内核。提供对Python内部构件的访问权,但不应被第三方模块使用。 -
Py_BUILD_CORE_MODULE 构建一个Python
stdlib模块作为一个动态库,Windows上导出“PyInit_xxx”符号。
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
35
36
37/* only get special linkage if built as shared or platform is Cygwin */
#if defined(Py_ENABLE_SHARED) || defined(__CYGWIN__)
# if defined(HAVE_DECLSPEC_DLL)
# if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
//被预定义了的
# ...
# else /* Py_BUILD_CORE */
/* Building an extension module(扩展模块), or an embedded situation */
/* public Python functions and data are imported */
# if !defined(__CYGWIN__)
# define PyAPI_FUNC(RTYPE) Py_IMPORTED_SYMBOL RTYPE
# endif /* !__CYGWIN__ */
# define PyAPI_DATA(RTYPE) extern Py_IMPORTED_SYMBOL RTYPE
/* module init functions outside the core must be exported */
# if defined(__cplusplus)
# define PyMODINIT_FUNC extern "C" Py_EXPORTED_SYMBOL PyObject*
# else /* __cplusplus */
# define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject*
# endif /* __cplusplus */
# endif /* Py_BUILD_CORE */
# endif /* HAVE_DECLSPEC_DLL */
#endif /* Py_ENABLE_SHARED */
/* If no external linkage macros defined by now, create defaults(如 GCC, Unix) */
#ifndef PyAPI_FUNC
# define PyAPI_FUNC(RTYPE) Py_EXPORTED_SYMBOL RTYPE
#endif
#ifndef PyAPI_DATA
# define PyAPI_DATA(RTYPE) extern Py_EXPORTED_SYMBOL RTYPE
#endif
#ifndef PyMODINIT_FUNC
# if defined(__cplusplus)
# define PyMODINIT_FUNC extern "C" Py_EXPORTED_SYMBOL PyObject*
# else /* __cplusplus */
# define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject*
# endif /* __cplusplus */
#endif
Py_xxx_SYMBOL#
我们在export.h下可以看到Py_EXPORTED_SYMBOL、Py_IMPORTED_SYMBOL的定义。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24//跨平台通用性
#if defined(_WIN32) || defined(__CYGWIN__)
/* 对于win32和Cygwin,使用__declspec()指定属性 */
#define Py_IMPORTED_SYMBOL __declspec(dllimport) //从dll导入。其它模块可见
#define Py_EXPORTED_SYMBOL __declspec(dllexport) //导出到dll。其它模块可见
#define Py_LOCAL_SYMBOL
#else
#else
//__has_attribute参数为属性名,可以评估当前编译目标是否支持该属性,支持为1,不支持为0
#ifndef __has_attribute
#define __has_attribute(x) 0 // Compatibility with non-clang compilers.
#endif
#if (defined(__GNUC__) && (__GNUC__ >= 4)) ||\ //如果 gcc版本>=4 或 clang判定编译目标支持visibility属性,则添加属性
(defined(__clang__) && __has_attribute(visibility))
#define Py_IMPORTED_SYMBOL __attribute__ ((visibility ("default"))) //具有外部链接性 (external linkage),可以被外部其它模块引用,并且有可能被重写
#define Py_EXPORTED_SYMBOL __attribute__ ((visibility ("default")))
#define Py_LOCAL_SYMBOL __attribute__ ((visibility ("hidden"))) //只能在同一共享对象(可简单理解为库文件)中被引用
#else
#define Py_IMPORTED_SYMBOL
#define Py_EXPORTED_SYMBOL
#define Py_LOCAL_SYMBOL
#endif
#endif
- Py_IMPORTED_SYMBOL:用于在Windows编译器或cygwin中,构建非核心模块时定义宏 PyAPI_FUNC,PyAPI_DATA,意义是直接导入核心模块,不编译, 防止编译器再次编译。
- Py_EXPORTED_SYMBOL: default,指定函数, class, struct 等为公开可重写的。编译导出到动态库(DLL或so)
- Py_LOCAL_SYMBOL: hidden,指定函数, class, struct 等只能在同一共享对象中被引用
visibility 属性#
visibility 属性用于指定可见性,可以用于
函数, class, struct, union, enum。
1
2void __attribute__ ((visibility ("protected"))) f () { /* Do something. */; }
int i __attribute__ ((visibility ("hidden")));
PyAPI_FUNC#
在gcc下, 以genobject.h中的PyGen_New为例:
1
PyAPI_FUNC(PyObject *) PyGen_New(PyFrameObject *);
1
Py_EXPORTED_SYMBOL PyObject * PyGen_New(PyFrameObject *)
1
__attribute__ ((visibility ("default"))) PyObject * PyGen_New(PyFrameObject *)
结论#
PyAPI_FUNC 指定函数可以被各个模块访问。
PyAPI_DATA#
以boolobject.h中的PyBool_Type为例
1
PyAPI_DATA(PyTypeObject) PyDictRevIterKey_Type;
1
Py_EXPORTED_SYMBOL PyTypeObject PyDictRevIterKey_Type;
1
__attribute__ ((visibility ("default"))) PyTypeObject PyDictRevIterKey_Type;
结论#
PyAPI_DATA指定变量可以被其它模块访问。
PyMODINIT_FUNC#
以binassi.h的中的模块初始化函数为例
1
2
3
4
5PyMODINIT_FUNC
PyInit_binascii(void)
{
return PyModuleDef_Init(&binasciimodule);
}1
2
3
4Py_EXPORTED_SYMBOL PyObject* PyInit_binascii(void)
{
return PyModuleDef_Init(&binasciimodule);
}1
2
3
4__attribute__ ((visibility ("default"))) PyObject* PyInit_binascii(void)
{
return PyModuleDef_Init(&binasciimodule);
}
结论#
PyMODINIT_FUNC指定模块初始化函数可以&&被其它模块访问&&,并返回PyObject结构体的指针变量
reference#
1.GCC __attribute__语法:visibility属性在cpython中的应用(PyAPI_FUNC, PyAPI_DATA, PyMODINIT_FUNC)