【发布时间】:2015-03-13 17:50:45
【问题描述】:
我正在使用 gcc 4.8.2 和 Python 2.7 在 Linux 中为我的自定义 C++ 库构建 python 绑定。 我的代码中有以下文件夹结构
module/
__init__.py
submodule1.so # first part of lib
submodule2.so # second part of lib
submodule3.py # additional python tools
在__init__.py
import submodule1, submodule2 submodule3
我需要在 submodule1 和 submodule2 之间传递对应于静态类成员变量的 C++ 指针。
为此,我一直在使用capsules。基本上在 submodule1 我有一个 PyObject * exportCapsule() 函数,在 submodule2 我有一个 importCapsule(PyObject *)
现在,我发现我不需要使用这些功能,我想了解原因。 我收到了 John Bollinger 的解释(见下面的回复),关于不同的 Python 模块为静态类成员变量共享相同的命名空间这一事实。
我对记录进行了完整的设置,如下所示:
文件singleton.hpp 为类似单例的行为定义静态类成员::
#ifndef _SINGLETON_HPP
#define _SINGLETON_HPP
// Singleton.hpp
// declaration of class
// + many more things
template<typename T>
class Singleton
{
private:
static T * _ptrInstance;
public:
static void setInstance(T* p)
{
_ptrInstance = p;
}
static bool doesInstanceExist()
{
bool output = not(NULL == _ptrInstance);
return output;
}
static T* getInstance()
{
return _ptrInstance;
}
};
// declaration of static class
template<typename T>
T * Singleton<T>::_ptrInstance(NULL);
#endif
文件 submodule1.cpp 定义了第一个模块::
//submodule1.cpp
#include <Python.h>
#include "singleton.hpp"
static PyObject*errorObject;
PyObject * exportCapsule(PyObject *dummy, PyObject *args)
{
long * ptr = Singleton<long>::getInstance();
const char * caps_name = "ptrInstance";
return PyCapsule_New((void *)ptr, caps_name, NULL);
}
PyObject* setValue(PyObject* self, PyObject* args)
{
if(not(Singleton<long>::doesInstanceExist()))
{
// printf("Singleton ptr %p \n",Singleton<long>::getInstance());
// printf("Singleton is null %d \n",NULL==Singleton<long>::getInstance());
PyErr_SetString(errorObject, "Singleton does not exist");
return NULL;
}
PyObject * input;
PyArg_ParseTuple(args, "O", &input);
if (!PyLong_Check(input))
{
PyErr_SetString(errorObject, "Input should be a long integer");
return NULL;
}
long * ptr = Singleton<long>::getInstance();
*ptr = PyLong_AsLong(input);
Py_INCREF(Py_None);
return Py_None;
}
PyMethodDef fonctions[] = {
{"setValue", setValue, METH_VARARGS, "set singleton value from long "},
{"exportCapsule", exportCapsule, METH_VARARGS, "export singleton"},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC initsubmodule1(void)
{
PyObject* m = Py_InitModule("submodule1", fonctions);
errorObject = PyErr_NewException("submodule1.Exception", NULL, NULL);
Py_INCREF(errorObject);
PyModule_AddObject(m, "Exception",errorObject);
long * ptr = new long(0);
Singleton<long>::setInstance(ptr);
}
文件submodule2.cpp 定义了第二个模块::
//submodule2.cpp
#include <Python.h>
#include "singleton.hpp"
static PyObject*errorObject;
// to be checked
PyObject * importCapsule(PyObject *dummy, PyObject *args)
{
const char * caps_name = "ptrInstance";
PyObject * caps;
PyArg_ParseTuple(args, "O", &caps);
// we should also check the name... laziness
if (not(PyCapsule_CheckExact(caps)))
{
PyErr_SetString(errorObject, "Input is not a capsule");
return NULL;
}
long * ptr = (long *) PyCapsule_GetPointer(caps, caps_name);
// if we want to set the same pointer it is ok
if (Singleton<long>::doesInstanceExist());
{
long * ptrPrevious = Singleton<long>::getInstance();
if (not(ptr == ptrPrevious))
{
PyErr_SetString(errorObject, "You've asked for setting the global ptr with a different value");
return NULL;
}
else
{
PyErr_SetString(errorObject, "You've asked for setting the global ptr with same value");
return NULL;
}
}
Singleton<long>::setInstance(ptr);
Py_INCREF(Py_None);
return Py_None;
}
PyObject* getValue(PyObject* self, PyObject* args)
{
if (not(Singleton<long>::doesInstanceExist()))
{
PyErr_SetString(errorObject, "Singleton does not exist");
return NULL;
}
long val = *Singleton<long>::getInstance();
return PyLong_FromLong(val);
}
PyMethodDef fonctions[] = {
{"getValue", getValue, METH_VARARGS, "get long from singleton value"},
{"importCapsule", importCapsule, METH_VARARGS, "import singleton as capsule"},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC initsubmodule2(void)
{
PyObject* m = Py_InitModule("submodule2", fonctions);
errorObject = PyErr_NewException("submodule2.Exception", NULL, NULL);
Py_INCREF(errorObject);
PyModule_AddObject(m, "Exception", errorObject);
}
用于构建第一个模块的文件setup_submodule1.py::
from distutils.core import setup, Extension
submodule1 = Extension('submodule1', sources = ['submodule1.cpp'])
setup (name = 'PackageName',
version = '1.0',
description = 'This is a demo package',
ext_modules = [submodule1])
用于构建第二个模块的文件setup_submodule2.py::
from distutils.core import setup, Extension
submodule2 = Extension('submodule2', sources = ['submodule2.cpp'])
setup (name = 'PackageName',
version = '1.0',
description = 'This is a demo package',
ext_modules = [submodule2])
文件test.py用于测试目的::
if __name__ == "__main__":
print '----------------------------------------------'
print 'import submodule2'
print 'submodule2.getValue()'
import submodule2
try:
submodule2.getValue()
except Exception, e:
print ' ## catched :', e
print '----------------------------------------------'
print 'import submodule1'
print 'submodule1.setValue(1L)'
import submodule1
submodule1.setValue(1L)
print 'submodule2.getValue() ->', submodule2.getValue()
print '----------------------------------------------'
print 'capsule = submodule1.exportCapsule()'
print 'submodule2.importCapsule(capsule)'
capsule = submodule1.exportCapsule()
try:
submodule2.importCapsule(capsule)
except Exception, e:
print ' ## catched :', e
文件 Makefile 用于链接所有内容::
submodule1:
python setup_submodule1.py build_ext --inplace
submodule2:
python setup_submodule2.py build_ext --inplace
test:
python test.py
all: submodule1 submodule2 test
而make all 输出::
python test.py
----------------------------------------------
import submodule2
submodule2.getValue()
## catched : Singleton does not exist
----------------------------------------------
import submodule1
submodule1.setValue(1L)
submodule2.getValue() -> 1
----------------------------------------------
capsule = submodule1.exportCapsule()
submodule2.importCapsule(capsule)
## catched : You've asked for setting the global ptr with same value
原来的问题是:
编译后,我有两个不同的模块
submodule1.so和submodule2.so。 我可以导入它们,我不明白的是,我的胶囊东西不是必需的。这两个模块共享静态变量Singleton<myClass>::_ptrInstance,而不必使用胶囊导出和导入。我怀疑这与
*.so中的符号有关。如果我打电话给nm -g *.so,我可以看到相同的符号。我真的很惊讶两个独立编译的模块可以共享一个变量。正常吗?
我收到了一个明确的答案:这两个模块共享变量,因为命名空间对所有模块都是通用的,而我期待不同的命名空间。
【问题讨论】:
-
template<typename T> T * Singleton<T>::_ptrInstance(NULL);实际上在标题中吗?那应该行不通。 -
根据您的评论,我用完整的设置更新了问题。您可以找到重现我的实验所需的所有文件。
标签: python c++ c static shared-libraries