SWIG Python 未定义符号错误

5 投票
6 回答
12774 浏览
提问于 2025-04-18 07:38

我正在尝试使用SWIG创建一个*.so文件,以便在Python中进一步使用,但遇到了一些问题。

我有两个文件:

DataGatherer.h

#include <iostream>
#include <stdlib.h>
#include <time.h>
#include "gnublin.h"
#include <pthread.h>

class dataGatherer
{
    private:
    int threshold;
    int timeThreshold;
    int data[4096];
    bool running;
    gnublin_spi* spiDevice;
    pthread_t spiThread;
    void *params;

    public:

    dataGatherer(void);
    dataGatherer(int, int);
    void initData();
    int getThreshold(void);
    int* getData(void);
    int getPeak(void);
    void initSPI(void);
    void gatherData();

    void * run(void * arg);
    void stop(void);

    // for use of thread we have to implement some methods from C
    static void * start_static(void * params)
    {
        dataGatherer * thread_this = static_cast<dataGatherer*>(params);
        return thread_this->run(thread_this->params);
    }

    void start(void * params)
    {
        this->params = params;
        pthread_create(&spiThread, 0, &dataGatherer::start_static, this);
    }

};

和spiController.h

#include "dataGatherer.h"

class spiController
{
    private:
    bool runGather;
    dataGatherer* gatherer;
    int data[4096];

    public:
    spiController(void);
    spiController(int, int);
    void initData();
    bool checkStop();
    void stop();
    void start();
};

我的spiController.i接口文件看起来是这样的:

/* spiController.i */
%module spiController
%{
#include "dataGatherer.h"
#include "spiController.h"
#include "gnublin.h"
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
extern void initData();
extern bool checkStop();
extern void stop();
extern void start();
%}

extern void initData();
extern bool checkStop();
extern void stop();
extern void start();

最后,我尝试使用终端中的命令来创建*.so文件,像SWIG页面上的示例一样:

swig -python -c++ spiController.i
c++ -c spiController_wrap.c -I/usr/include/python2.7
c++ -shared spiController_wrap.o -o _spiController.so

*.cxx、*.o和*.so文件都创建成功,没有错误,但当我在Python代码中导入spiController时,我得到了:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "spiController.py", line 26, in <module>
    _spiController = swig_import_helper()
  File "spiController.py", line 22, in swig_import_helper
    _mod = imp.load_module('_spiController', fp, pathname, description)
ImportError: ./_spiController.so: undefined symbol: _Z9checkStopv

这是我第一次使用SWIG,现在卡在这里了。我该如何解决这个问题呢?

6 个回答

0

在我的情况下,我也遇到了那个错误,花了一些时间尝试各种方法但都没有成功。我的问题是,虽然我的源文件是普通的C语言,但我把它命名为.cpp的扩展名,以为这没关系。把扩展名改成.c后,问题就自动解决了。

另外一种解决方法是,在SWIG的.i文件的头部添加这一行#include "example.cpp"

所以,总结一下:

example.c

int fact(int n) {
  if (n <= 1) return 1;
  else return n*fact(n-1);
}

example.i

%module example
%{
  extern int fact(int n);
%}
extern int fact(int n);

然后在我的Ubuntu 17.10上,以下代码就能正常工作:

swig -c++ -python example.i
gcc -fPIC -c example.c example_wrap.c -I /usr/include/python2.7
gcc -shared example.o example_wrap.o -o _example.so
python -c "import example; print example.fact(5)"

希望这能帮助到某些人!
谢谢

2

虽然这个问题可能有很多原因,但我在用 Python 3.5 的头文件编译共享库时,遇到了完全相同的错误,比如:

swig -python example.i
gcc -fPIC -c example.c example_wrap.c -I/usr/include/python3.5 # <-- ISSUE HERE
gcc -shared example.o example_wrap.o -o _example.so

后来我尝试用 python test.py 来使用这个示例库,但系统上运行的是 Python 2.7(所以这是一个 Python 版本不匹配的问题)。

3

就像Adam的评论和我的经验一样,你首先需要把你的 XXX.cpp 文件编译成 XXX.o 文件,整个命令行可能像下面这样:

  1. swig -python -c++ XXX.i

  2. g++ -c -fpic XXX.cpp* (这个命令会生成 XXX.o 文件)

  3. g++ -c -fpic XXX_wrap.cxx -I/usr/include/python2.7* (这个命令会生成 XXX_wrap.o 文件)

  4. g++ -shared XXX.o XXX_wrap.o -o XXX.so

5

我刚遇到同样的错误,最后终于搞明白了原因。就像上面的人说的,当你看到“找不到符号”这样的提示,并且出现了未定义的函数名'_Z9checkStopv'时,一定要检查一下这个函数在.cpp文件中的实现情况,还有同名函数的声明!

在我的情况下,我的.cpp文件确实定义了那个“找不到符号”的构造函数,但在我的.h文件里,我有一个重载的赋值运算符(针对构造函数),这个在.cpp文件里没有实现。所以swig会把默认构造函数(在.cpp里实现的)和赋值运算符(没有实现的)都包装起来。因此在导入时,这个未实现的赋值运算符就会产生错误。希望这能帮到你!

3

你需要链接一个库,这个库里定义了你在代码中声明的C++函数,比如checkStop等等。你需要在你示例的编译步骤的第三行添加-L<你的C++ DLL的路径> -l<你的C++ DLL的名字>

就像这样:

c++ -L<path to DLL> -l<name of your dll> -shared spiController_wrap.o -o _spiController.so

撰写回答