方法在 C 扩展模块中不可见
Method not visible from C extension module
我正在尝试为 Python 创建一个简单的 C 扩展,并将其添加到 OS X 上的 运行。我正在 运行ning Python 3.6。我的方法显然没有从模块中导出。精简后,我的代码如下所示:
Example.c:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
static PyObject*
myfunc(PyObject* self, PyObject* args)
{
/* Not parsing args because I'm just returning a constant */
return PyLong_FromLong(1);
}
/* Method table */
static PyMethodDef MyMethods[] = {
{"myfunc", myfunc, METH_VARARGS, "Just do something"},
{NULL, NULL, 0, NULL} /* Sentinel */
};
/* Module defintion */
static struct PyModuleDef mymodule = {
PyModuleDef_HEAD_INIT,
"example", /* name of module */
NULL, /* module documentation, may be NULL */
-1, /* size of per-interpreter state of the module,
or -1 if the module keeps state in global variables. */
MyMethods
};
/* Module initialization */
PyMODINIT_FUNC
PyInit_example(void)
{
//import_array(); // initialize numpy arrays
return PyModule_Create(&mymodule);
}
我用
编译
gcc -c -fPIC -I$PYINCLUDE example.c
gcc example.o -shared -o libexample.so -L$PYLIB -lpython3.6m
正在创建 .so 文件。最后,我正在尝试 运行 这个:
import ctypes
m = ctypes.CDLL("libexample.so")
print(m.myfunc("asdf"))
当我得到:
Traceback (most recent call last):
File "test.py", line 3, in <module>
print(m.myfunc("asdf"))
File "/PATH/TO/anaconda3/lib/python3.6/ctypes/__init__.py", line 361, in __getattr__
func = self.__getitem__(name)
File "/PATH/TO/anaconda3/lib/python3.6/ctypes/__init__.py", line 366, in __getitem__
func = self._FuncPtr((name_or_ordinal, self))
AttributeError: dlsym(0x7f96f652e4e0, myfunc): symbol not found
我知道很多教程都推荐使用 setuptools 或 distutils 来打包扩展,但我试图一次只学习一种新工具。有什么明显的地方我做错了吗?
ctypes
模块用于在常规 C 中访问动态加载的库。您正在创建一个 python 扩展。由于 C 中的 python 函数被声明为静态的,因此 myfunc
不会在您的 .so
文件中公开。您需要在 distutils 或 setuptools 中编译扩展,然后在 python 代码中导入模块。如果您想像您的示例一样使用 ctypes,您需要用 C 语言重写您的代码,如下所示。
头文件:
#ifndef _EXAMPLE_H_
#define _EXAMPLE_H_
int myfunc();
#endif
C源文件:
#include "example.h"
int myfunc()
{
/* Not parsing args because function is just returning a constant */
return 1;
}
您创建了(或想要创建和使用)一个 扩展 模块 ([Python.Docs]: Extending Python with C or C++),即使写入在 C 中, 可以/应该像任何其他 Python 模块一样访问 .
[Python.Docs]: ctypes - A foreign function library for Python serves for as totally different purpose: dynamically loading regular (not Python modules (it can load those too, but that's a different story)) .sos (.dlls), and calling functions from them, and thus doesn't belong here. Any tweak to get it in, would be just a (lame) workaround.
There are plenty examples of how to create simple .dlls and use them from CTypes ().
总而言之,您应该能够在 2 行简单的代码中调用您的函数:
import example
example.myfunc()
一个更详细的例子。
test_example.py:
#!/usr/bin/env python
import sys
import example
def main(*argv):
print("Module: {:}".format(example))
print("Functions: {:}".format(dir(example)))
print("myfunc returned: {:}".format(example.myfunc()))
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.")
sys.exit(rc)
输出:
[cfati@cfati-5510-0:/mnt/e/Work/Dev/Whosebug/q069200033]> ~/sopr.sh
*** Set shorter prompt to better fit when pasted in Whosebug (or other) pages ***
[064bit prompt]> ls
examplemodule.c test_example.py
[064bit prompt]>
[064bit prompt]> gcc -fPIC -I/usr/include/python3.6 -shared -o example.cpython-36m-x86_64-linux-gnu.so -L/usr/lib/python3.6 -lpython3.6m examplemodule.c
[064bit prompt]> ls
example.cpython-36m-x86_64-linux-gnu.so examplemodule.c test_example.py
[064bit prompt]>
[064bit prompt]> python3.6 test_example.py
Python 3.6.15 (default, Sep 10 2021, 00:26:58) [GCC 9.3.0] 064bit on linux
Module: <module 'example' from '/mnt/e/Work/Dev/Whosebug/q069200033/example.cpython-36m-x86_64-linux-gnu.so'>
Functions: ['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'myfunc']
myfunc returned: 1
Done.
备注:
- 你的模块名称应该是example.so。我添加了那个时髦的后缀,这样如果我想从多个 Python 版本中 运行 它,我就不必每次更改时都重建它版本,并且还要 [Python]: PEP 3149 - ABI version tagged .so files 兼容
- 在讨论这个主题时,您应该转到较新的 Python 版本
- 我把你的文件名改成了examplemodule.c(这只是约定俗成)
- 不用说,它被视为每个模块(包括模块搜索路径),这里不是这种情况,因为它位于 cwd,但您可能需要添加它到 ${PYTHONPATH}
的路径
我正在尝试为 Python 创建一个简单的 C 扩展,并将其添加到 OS X 上的 运行。我正在 运行ning Python 3.6。我的方法显然没有从模块中导出。精简后,我的代码如下所示:
Example.c:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
static PyObject*
myfunc(PyObject* self, PyObject* args)
{
/* Not parsing args because I'm just returning a constant */
return PyLong_FromLong(1);
}
/* Method table */
static PyMethodDef MyMethods[] = {
{"myfunc", myfunc, METH_VARARGS, "Just do something"},
{NULL, NULL, 0, NULL} /* Sentinel */
};
/* Module defintion */
static struct PyModuleDef mymodule = {
PyModuleDef_HEAD_INIT,
"example", /* name of module */
NULL, /* module documentation, may be NULL */
-1, /* size of per-interpreter state of the module,
or -1 if the module keeps state in global variables. */
MyMethods
};
/* Module initialization */
PyMODINIT_FUNC
PyInit_example(void)
{
//import_array(); // initialize numpy arrays
return PyModule_Create(&mymodule);
}
我用
编译gcc -c -fPIC -I$PYINCLUDE example.c
gcc example.o -shared -o libexample.so -L$PYLIB -lpython3.6m
正在创建 .so 文件。最后,我正在尝试 运行 这个:
import ctypes
m = ctypes.CDLL("libexample.so")
print(m.myfunc("asdf"))
当我得到:
Traceback (most recent call last):
File "test.py", line 3, in <module>
print(m.myfunc("asdf"))
File "/PATH/TO/anaconda3/lib/python3.6/ctypes/__init__.py", line 361, in __getattr__
func = self.__getitem__(name)
File "/PATH/TO/anaconda3/lib/python3.6/ctypes/__init__.py", line 366, in __getitem__
func = self._FuncPtr((name_or_ordinal, self))
AttributeError: dlsym(0x7f96f652e4e0, myfunc): symbol not found
我知道很多教程都推荐使用 setuptools 或 distutils 来打包扩展,但我试图一次只学习一种新工具。有什么明显的地方我做错了吗?
ctypes
模块用于在常规 C 中访问动态加载的库。您正在创建一个 python 扩展。由于 C 中的 python 函数被声明为静态的,因此 myfunc
不会在您的 .so
文件中公开。您需要在 distutils 或 setuptools 中编译扩展,然后在 python 代码中导入模块。如果您想像您的示例一样使用 ctypes,您需要用 C 语言重写您的代码,如下所示。
头文件:
#ifndef _EXAMPLE_H_
#define _EXAMPLE_H_
int myfunc();
#endif
C源文件:
#include "example.h"
int myfunc()
{
/* Not parsing args because function is just returning a constant */
return 1;
}
您创建了(或想要创建和使用)一个 扩展 模块 ([Python.Docs]: Extending Python with C or C++),即使写入在 C 中, 可以/应该像任何其他 Python 模块一样访问 .
[Python.Docs]: ctypes - A foreign function library for Python serves for as totally different purpose: dynamically loading regular (not Python modules (it can load those too, but that's a different story)) .sos (.dlls), and calling functions from them, and thus doesn't belong here. Any tweak to get it in, would be just a (lame) workaround.
There are plenty examples of how to create simple .dlls and use them from CTypes (
总而言之,您应该能够在 2 行简单的代码中调用您的函数:
import example
example.myfunc()
一个更详细的例子。
test_example.py:
#!/usr/bin/env python
import sys
import example
def main(*argv):
print("Module: {:}".format(example))
print("Functions: {:}".format(dir(example)))
print("myfunc returned: {:}".format(example.myfunc()))
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.")
sys.exit(rc)
输出:
[cfati@cfati-5510-0:/mnt/e/Work/Dev/Whosebug/q069200033]> ~/sopr.sh
*** Set shorter prompt to better fit when pasted in Whosebug (or other) pages ***
[064bit prompt]> ls
examplemodule.c test_example.py
[064bit prompt]>
[064bit prompt]> gcc -fPIC -I/usr/include/python3.6 -shared -o example.cpython-36m-x86_64-linux-gnu.so -L/usr/lib/python3.6 -lpython3.6m examplemodule.c
[064bit prompt]> ls
example.cpython-36m-x86_64-linux-gnu.so examplemodule.c test_example.py
[064bit prompt]>
[064bit prompt]> python3.6 test_example.py
Python 3.6.15 (default, Sep 10 2021, 00:26:58) [GCC 9.3.0] 064bit on linux
Module: <module 'example' from '/mnt/e/Work/Dev/Whosebug/q069200033/example.cpython-36m-x86_64-linux-gnu.so'>
Functions: ['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'myfunc']
myfunc returned: 1
Done.
备注:
- 你的模块名称应该是example.so。我添加了那个时髦的后缀,这样如果我想从多个 Python 版本中 运行 它,我就不必每次更改时都重建它版本,并且还要 [Python]: PEP 3149 - ABI version tagged .so files 兼容
- 在讨论这个主题时,您应该转到较新的 Python 版本
- 我把你的文件名改成了examplemodule.c(这只是约定俗成)
- 不用说,它被视为每个模块(包括模块搜索路径),这里不是这种情况,因为它位于 cwd,但您可能需要添加它到 ${PYTHONPATH} 的路径