python - 使用 SWIG 将 C++ 类导出为 Python,导入模块后出现未定义符号错误
问题描述
我正在尝试学习 SWIG(http://www.swig.org/),以便将 C++ 库扩展/公开到 Python 和 Java 语言中。
在开始这项工作之前,我先从一个简单的 SWIG 示例 ( http://www.swig.org/tutorial.html ) 开始,然后让它发挥作用。
见下文(你可以在我的系统上看到 swig wok 并且我可以在 Python shell 中加载“示例”模块):
linux{me}% swig -python example.i
linux{me}% gcc -c -fPIC example.c example_wrap.c / -I/usr/include/python2.7
gcc: warning: /: linker input file unused because linking not done
linux{me}% gcc -c -fPIC example.c example_wrap.c -I/usr/include/python2.7
linux{me}% ld -shared example.o example_wrap.o -o _example.so
linux{me}% python
Python 2.7.5 (default, Aug 2 2016, 04:20:16)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
import example
example.fact(5)
120
example.my_mod(5)
Traceback (most recent call last):
File "", line 1, in
TypeError: my_mod() takes exactly 2 arguments (1 given)
example.my_mod(7,3)
1
example.get_time()
'Fri Feb 28 14:54:08 2020\n'
一切都很好,现在下一步是公开一个 C++ 类,所以我最初遵循本教程(https://realmike.org/blog/2010/07/18/python-extensions-in-cpp-using-swig/)。与官方 SWIG 文档相比,本教程缺少一些步骤,例如加载 .so 共享库,以便 Python 可以在库上调用“导入”,我们稍后会介绍...
我对 SomeClass.h 进行了一些更改,以添加常量“#define TypeBool 0”等...
这是相关的虚拟 C++ 标头:
#ifndef _SOME_CLASS_H_
#define _SOME_CLASS_H_
class SomeClass {
public:
SomeClass();
SomeClass(int a, int b);
virtual ~SomeClass();
void MethodA(int a = -1);
void MethodB(int b = -1);
void setType(int type);
int GetValA();
int GetValB();
int GetType();
private:
int mValA;
int mValB;
int type;
};
#endif // _SOME_CLASS_H_
下面是实现 SomeClass.h 的相关类文件:
#include "SomeClass.h"
//refactor to use enum
#define TypeBool 0
#define TypeChar 1
#define TypeByte 2
#define TypeInt 3
#define TypeShort 4
#define TypeFloat 5
#define TypeDouble 6
#define TypeString 7
#define TypeComposite 8
SomeClass::SomeClass() {
mValA = -1;
mValB = -1;
}
SomeClass::~SomeClass() {
}
void SomeClass::MethodA(int a)
{
mValA = mValA * -1;
}
void setType(int type)
{
switch (type)
{
case 0:
type = TypeBool;
break;
case 1:
type = TypeChar;
break;
case 2:
type = TypeByte;
break;
case 3:
type = TypeInt;
break;
case 4:
type = TypeShort;
break;
case 5:
type = TypeFloat;
break;
case 6:
type = TypeDouble;
break;
case 7:
type = TypeString;
break;
case 8:
type = TypeComposite;
break;
}
}
void SomeClass::MethodB(int b)
{
mValB = b;
}
int SomeClass::GetValA()
{
return mValA;
}
int SomeClass::GetValB()
{
return mValB;
}
int SomeClass::GetType()
{
return type;
}
尝试 #1 这是 SWIG 所需的“接口”文件,基于( https://realmike.org/blog/2010/07/18/python-extensions-in-cpp-using-swig/ ) 或http:// www.swig.org/Doc4.0/SWIGDocumentation.pdf第 25-32 页。
%module mymodule
%{
#include "SomeClass.h"
%}
%include "SomeClass.h"
1)然后我发出命令:
痛饮 -c++ -python -I/home/me/NetBeansProjects/example mymodule.i
此命令运行并且似乎创建了 python 和 cpp 自动生成的包装器:
-rw-r--r-- 1 我 linuxlusers 350 3 月 3 日 15:53 mymodule.i -rw-r--r-- 1 我 linuxlusers 2864 3 月 3 日 15:55 mymodule.py -rw-r--r- - 1 我 linuxlusers 121327 Mar 3 15:55 mymodule_wrap.cxx
2)然后我编译:
g++ -c -fPIC SomeClass.cpp mymodule_wrap.cxx -I/usr/include/python2.7
这会创建目标文件:
-rw-r--r-- 1 我 linuxlusers 60136 3 月 3 日 15:56 mymodule_wrap.o -rw-r--r-- 1 我 linuxlusers 4384 3 月 3 日 15:56 SomeClass.o
3)然后,我将我的目标文件捆绑到共享库文件“.so”中,并使该共享库在系统范围内可用,以便我可以从 Python 加载它:
linux{me}% ld -shared mymodule_wrap.o -o _mymodule.so
4)最后,我从命令行调用 python shell 并尝试导入 mymodule:
linux{me}% python
Python 2.7.5 (default, Aug 2 2016, 04:20:16)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import mymodule
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "mymodule.py", line 15, in <module>
import _mymodule
ImportError: ./_mymodule.so: undefined symbol: __gxx_personality_v0
>>>
可以看到错误:ImportError: ./_mymodule.so: undefined symbol: __gxx_personality_v0。
尝试 $2(我在 %inline 标记中使用 .cpp 实现重写了接口文件):
%module mymodule
%{
#include "SomeClass.h"
%}
%include "SomeClass.h"
%constant TypeBool 0
%constant TypeChar 1
%constant TypeByte 2
%constant TypeInt 3
%constant TypeShort 4
%constant TypeFloat 5
%constant TypeDouble 6
%constant TypeString 7
%constant TypeComposite 8
%inline %{
SomeClass::SomeClass() {
mValA = -1;
mValB = -1;
}
SomeClass::~SomeClass() {
}
void SomeClass::MethodA(int a)
{
mValA = mValA * -1;
}
void setType(int type)
{
switch (type)
{
case 0:
type = TypeBool;
break;
case 1:
type = TypeChar;
break;
case 2:
type = TypeByte;
break;
case 3:
type = TypeInt;
break;
case 4:
type = TypeShort;
break;
case 5:
type = TypeFloat;
break;
case 6:
type = TypeDouble;
break;
case 7:
type = TypeString;
break;
case 8:
type = TypeComposite;
break;
}
}
void SomeClass::MethodB(int b)
{
mValB = b;
}
int SomeClass::GetValA()
{
return mValA;
}
int SomeClass::GetValB()
{
return mValB;
}
int SomeClass::GetType()
{
return type;
}
%}
我再次运行了 swig 命令和编译,但是我得到了同样的错误:
linux{me}% swig -c++ -python -I/home/me/NetBeansProjects/example mymodule.i
linux{me}% g++ -c -fPIC SomeClass.cpp mymodule_wrap.cxx -I/usr/include/python2.7
linux{me}% ld -shared mymodule_wrap.o -o _mymodule.so
linux{me}% python
Python 2.7.5 (default, Aug 2 2016, 04:20:16)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import mymodule
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "mymodule.py", line 15, in <module>
import _mymodule
ImportError: ./_mymodule.so: undefined symbol: __gxx_personality_v0
>>>
KeyboardInterrupt
>>>
尝试 3(我在 %inline 标记中重写了带有头 .h 的接口文件):
%module mymodule
%{
#include "SomeClass.h"
%}
%include "SomeClass.h"
%constant TypeBool 0
%constant TypeChar 1
%constant TypeByte 2
%constant TypeInt 3
%constant TypeShort 4
%constant TypeFloat 5
%constant TypeDouble 6
%constant TypeString 7
%constant TypeComposite 8
%inline %{
class SomeClass {
public:
SomeClass();
SomeClass(int a, int b);
virtual ~SomeClass();
void MethodA(int a = -1);
void MethodB(int b = -1);
void setType(int type);
int GetValA();
int GetValB();
int GetType();
private:
int mValA;
int mValB;
int type;
};
%}
同样,我得到了与上述其他 2 次尝试相同的错误(ImportError: ./_mymodule.so: undefined symbol: __gxx_personality_v0.) 。
从java加载库时,我尝试了“未定义符号:__cxa_pure_virtual”错误中推荐的编译器标志
但是,我得到了同样的错误。
1)我该如何解决这个错误?
尝试#4 某种解决方案:
我根据另一个在线指南编写了全新的更简单的类,但没有重载构造函数和函数。
我通过删除多个构造函数导入了 SWIG 包装的 C++ 类 (Word.cpp),并且只有一个默认常量。
见下文:
#ifndef WORD_H
#define WORD_H
#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;
class Word {
public:
Word();
// REMOVED Word(std::string the_word);
//REMOVED Word(const Word& orig);
virtual ~Word();
virtual void updateWord(std::string word);
virtual std::string getWord();
private:
std::string _the_word;
};
#endif /* WORD_H */
Word.h 的 SWIG 界面:
%{
/* Put header files here or function declarations like below */
/*#include "example.h"*/
#include "Word.h"
%}
%include "std_string.i"
/* %include "example.h"*/
%include "Word.h"
并使用了这些编译选项:
swig -python example.i
swig -python -c++ example.i
python setup.py build_ext --inplace
Python:
python
Python 2.7.5 (default, Aug 2 2016, 04:20:16)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
import _example
_example.new_Word()
<Swig Object of type 'Word *' at 0x7f4debcceb70>
_example.new_Word()
swig/python detected a memory leak of type 'Word *', no destructor found.
<Swig Object of type 'Word *' at 0x7f4debcced50>
w = _example.new_Word()
_example.Word_updateWord(w,"beef")
_example.Word_getWord(w)
swig/python detected a memory leak of type 'Word *', no destructor found.
'beef'
_example.Word_updateWord(w,"chicken")
_example.Word_getWord(w)
'chicken'
因此,如果没有相同的函数或构造函数签名,我们就可以将 C++ 类导出为 Python 模块。
然而,这是非常有限的,因为面向对象设计模式大量使用重载/覆盖。
谢谢,
一百万!
解决方案
推荐阅读
- apache-kafka-streams - 延迟 Kafka 处理器从源主题读取
- python - 如何降低循环大量次数的程序的时间复杂度?
- gradle - 从子项目运行 Gradle 根项目任务
- azure - 通过 Oracle12c 的消息未发送到 DLQ Azure ServiceBus 队列
- python - 在 Numpy Ndarray 中查找唯一三元组的计数
- velo - 如何在 Wix Corvid/Code IDE 中附加Child
- python-3.x - 检查反应用户不适用于特定用户?
- angular - 如何在 Angular 8 的 ngx 模式中选择数据?
- go - 如何在带有身份验证标头的浏览器中打开 URL?
- spring - Spring Integration 运行时配置