Python C扩展:链接器说“符号的多个定义”

dw1jzc5e  于 2023-02-03  发布在  Python
关注(0)|答案(1)|浏览(166)

我目前正在使用C语言创建一个Python扩展,其中包括一个自定义对象类型的定义。为了保持一个清晰和有组织的代码库,我选择在一个单独的文件中定义和实现这个对象。然而,根据Python C API,函数和对象必须定义为静态的。
尽管如此,我还是为这个对象使用了__attribute__((visibility("hidden")))属性。不幸的是,我遇到了一个来自链接器的重复错误,特别是"符号的多重定义"。
下面提供的代码是对我的大型项目中遇到的问题的最小化和易于复制的演示。由于主项目中存在大量类型对象,我正在寻求将它们组织到单独的文件中以提高可维护性。

我的项目结构:
.
├── example.c
├── include
│   ├── lcg.h
│   └── macros.h
├── lcg.c
└── setup.py
示例. c
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "lcg.h"

static PyMethodDef example_methods[] = {
    {NULL, NULL, 0, NULL}
};

static struct PyModuleDef example_module = {
    PyModuleDef_HEAD_INIT,
    "example",
    "An example module",
    -1,
    example_methods
};

PyMODINIT_FUNC PyInit_example(void) {
    PyObject *module;

    if (PyType_Ready(&LCG) < 0)
        return NULL;

    module = PyModule_Create(&example_module);

    if (module == NULL)
        return NULL;

    Py_INCREF(&LCG);
    PyModule_AddObject(module, "LCGType", (PyObject*)&LCG);

    return module;
}
lcg. c

SYM_PRIVATEmacros.h中定义,并扩展为__attribute__((visibility("hidden")))

#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "structmember.h"
#include "macros.h"  /* for SYM_PRIVATE */
#include "lcg.h"

static PyObject *LCG__dummy(LCG_Type *self)
{
    int value = 10;
    return PyFloat_FromDouble(value);
}

static PyMemberDef LCG_members[] = {
    {NULL} /* sentinel */
};

static PyMethodDef LCG_methods[] = {
    {"dummy", (PyCFunction)LCG__dummy, METH_NOARGS, "A simple dummy function on LCG module."},
    {NULL} /* sentinel */
};

SYM_PRIVATE PyTypeObject LCG = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "example.LCG",
    .tp_doc = PyDoc_STR("Linear Congruential Generator"),
    .tp_basicsize = sizeof(LCG_Type),
    .tp_itemsize = 0,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_members = LCG_members,
    .tp_methods = LCG_methods,
};
长度. h
#ifndef LCG_H
#define LCG_H

#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "structmember.h"
#include "macros.h"  /* for SYM_PRIVATE */

typedef struct {
    PyObject_HEAD
    int foo;
} LCG_Type;

SYM_PRIVATE PyTypeObject LCG;

#endif /* LCG_H */
www.example.comsetup.py
from setuptools import Extension
from setuptools import setup

example_module = Extension('example', sources=['example.c', 'lcg.c'], include_dirs=['include'])

setup(name = 'example',
      version = '1.0',
      description = 'An example module',
      ext_modules = [example_module]
)

执行python3.10 setup.py build时,我得到:

running build
running build_ext
building 'example' extension
creating build
creating build/temp.linux-x86_64-cpython-310
x86_64-linux-gnu-gcc -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -Iinclude -I/usr/include/python3.10 -c example.c -o build/temp.linux-x86_64-cpython-310/example.o
x86_64-linux-gnu-gcc -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -Iinclude -I/usr/include/python3.10 -c lcg.c -o build/temp.linux-x86_64-cpython-310/lcg.o
creating build/lib.linux-x86_64-cpython-310
x86_64-linux-gnu-gcc -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -g -fwrapv -O2 build/temp.linux-x86_64-cpython-310/example.o build/temp.linux-x86_64-cpython-310/lcg.o -L/usr/lib/x86_64-linux-gnu -o build/lib.linux-x86_64-cpython-310/example.cpython-310-x86_64-linux-gnu.so
/usr/bin/ld: build/temp.linux-x86_64-cpython-310/lcg.o:/home/user/workspaces/python-extension-example/src/include/lcg.h:14: multiple definition of `LCG'; build/temp.linux-x86_64-cpython-310/example.o:/home/user/workspaces/python-extension-example/src/include/lcg.h:14: first defined here
collect2: error: ld returned 1 exit status
error: command '/usr/bin/x86_64-linux-gnu-gcc' failed with exit code 1

我正在运行gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0GNU ld (GNU Binutils for Ubuntu) 2.38Python 3.10.6

wlp8pajw

wlp8pajw1#

lcg.h中,注解掉:

// SYM_PRIVATE PyTypeObject LCG;

example.c中,添加:

extern LCG;

然后,您将成功构建Python模块。

相关问题