子目录结构破坏了 C++ 扩展构建
Subdirectory structure breaks C++ extension build
我似乎无法解决使用子目录结构时导入 C++ 扩展模块不再起作用的问题。
下面的两个案例展示了一个简单的工作案例和一个我终生无法工作的稍微改动的案例。
场景 1(有效)
项目树:
demo_cext/ # Current working directory for all of this
├── _cmodule.cc
└── setup.py
setup.py
的内容:
import setuptools
module = setuptools.Extension("_cmod", sources=["_cmodule.cc"], language="c++")
if __name__ == "__main__":
setuptools.setup(name="cmod", ext_modules=[module])
_cmodule.cc
的内容,基本上是 C 扩展的 hello world,它创建了一个不带参数的函数 foo()
和 returns 5.
#define PY_SSIZE_T_CLEAN
#include <Python.h>
static PyObject *
foo(PyObject *self, PyObject *args) {
/* noargs() */
if (!PyArg_ParseTuple(args, "")) {
return NULL;
}
return PyLong_FromLong(5);
}
static PyMethodDef FooMethods[] = {
{"foo", foo, METH_VARARGS, "Do the foo"},
{NULL, NULL, 0, NULL}
};
PyDoc_STRVAR(module_doc, "This is the module docstring.");
static struct PyModuleDef cmodule = {
PyModuleDef_HEAD_INIT,
"cmod",
module_doc,
-1,
FooMethods,
NULL,
NULL,
NULL,
NULL
};
PyMODINIT_FUNC
PyInit__cmod(void) {
PyObject* m = PyModule_Create(&cmodule);
if (m == NULL) {
return NULL;
}
return m;
}
整个事情就像一个魅力:
$ python3 -V
Python 3.7.4
$ python3 setup.py build install
>>> import _cmod
>>> _cmod.foo()
5
场景 2(损坏)
将项目稍微调整为 the Python docs 中具体介绍的布局。
$ rm -rf build/ dist/ cmod.egg-info/ && \
> mkdir cmod/ && touch cmod/__init__.py && \
> mv _cmodule.cc cmod/
给我留下:
demo_cext/ # Current working directory for all of this
├── cmod
│ ├── __init__.py
│ └── _cmodule.cc
└── setup.py
我稍微改一下setup.py
:
import setuptools
module = setuptools.Extension("cmod._cmod", sources=["cmod/_cmodule.cc"], language="c++")
if __name__ == "__main__":
setuptools.setup(name="cmod", ext_modules=[module])
再接再厉运行:
$ python3 setup.py build install
尝试导入模块让我得到:
>>> from cmod import _cmod
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: cannot import name '_cmod' from 'cmod' (.../demo_cext/cmod/__init__.py)
>>> import cmod._cmod
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'cmod._cmod'
我这里有什么问题吗?我敢肯定,命名约定很简单。 这似乎直接面对 how this is all laid out in the Python docs。
尝试在启动前更改目录 Python(例如 cd ..
)。您的回溯表明您在 demo_cext/cmod
中找到 cmod
(您的源目录,而不是安装目录),但是构建的扩展不会在那里(它会在 demo_cext/build
中的某个地方build
之后,以及 install
之后的系统站点包目录)。
如果只在 Python 3 上使用,另一种解决方案是删除 cmod/__init__.py
文件;由于 PEP 420,空 __init__.py
文件不需要在 Python 3 中制作包。通过删除 __init__.py
,隐式命名空间包装应该接管,它应该自动搜索 all cmod
包在 sys.path
中的子模块正在尝试导入。
我似乎无法解决使用子目录结构时导入 C++ 扩展模块不再起作用的问题。
下面的两个案例展示了一个简单的工作案例和一个我终生无法工作的稍微改动的案例。
场景 1(有效)
项目树:
demo_cext/ # Current working directory for all of this
├── _cmodule.cc
└── setup.py
setup.py
的内容:
import setuptools
module = setuptools.Extension("_cmod", sources=["_cmodule.cc"], language="c++")
if __name__ == "__main__":
setuptools.setup(name="cmod", ext_modules=[module])
_cmodule.cc
的内容,基本上是 C 扩展的 hello world,它创建了一个不带参数的函数 foo()
和 returns 5.
#define PY_SSIZE_T_CLEAN
#include <Python.h>
static PyObject *
foo(PyObject *self, PyObject *args) {
/* noargs() */
if (!PyArg_ParseTuple(args, "")) {
return NULL;
}
return PyLong_FromLong(5);
}
static PyMethodDef FooMethods[] = {
{"foo", foo, METH_VARARGS, "Do the foo"},
{NULL, NULL, 0, NULL}
};
PyDoc_STRVAR(module_doc, "This is the module docstring.");
static struct PyModuleDef cmodule = {
PyModuleDef_HEAD_INIT,
"cmod",
module_doc,
-1,
FooMethods,
NULL,
NULL,
NULL,
NULL
};
PyMODINIT_FUNC
PyInit__cmod(void) {
PyObject* m = PyModule_Create(&cmodule);
if (m == NULL) {
return NULL;
}
return m;
}
整个事情就像一个魅力:
$ python3 -V
Python 3.7.4
$ python3 setup.py build install
>>> import _cmod
>>> _cmod.foo()
5
场景 2(损坏)
将项目稍微调整为 the Python docs 中具体介绍的布局。
$ rm -rf build/ dist/ cmod.egg-info/ && \
> mkdir cmod/ && touch cmod/__init__.py && \
> mv _cmodule.cc cmod/
给我留下:
demo_cext/ # Current working directory for all of this
├── cmod
│ ├── __init__.py
│ └── _cmodule.cc
└── setup.py
我稍微改一下setup.py
:
import setuptools
module = setuptools.Extension("cmod._cmod", sources=["cmod/_cmodule.cc"], language="c++")
if __name__ == "__main__":
setuptools.setup(name="cmod", ext_modules=[module])
再接再厉运行:
$ python3 setup.py build install
尝试导入模块让我得到:
>>> from cmod import _cmod
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: cannot import name '_cmod' from 'cmod' (.../demo_cext/cmod/__init__.py)
>>> import cmod._cmod
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'cmod._cmod'
我这里有什么问题吗?我敢肯定,命名约定很简单。 这似乎直接面对 how this is all laid out in the Python docs。
尝试在启动前更改目录 Python(例如 cd ..
)。您的回溯表明您在 demo_cext/cmod
中找到 cmod
(您的源目录,而不是安装目录),但是构建的扩展不会在那里(它会在 demo_cext/build
中的某个地方build
之后,以及 install
之后的系统站点包目录)。
如果只在 Python 3 上使用,另一种解决方案是删除 cmod/__init__.py
文件;由于 PEP 420,空 __init__.py
文件不需要在 Python 3 中制作包。通过删除 __init__.py
,隐式命名空间包装应该接管,它应该自动搜索 all cmod
包在 sys.path
中的子模块正在尝试导入。