在尝试导入 Python 库时遇到了令人沮丧的问题,该库本身调用了我用 C++ 编写并编译成 .so 的一些代码
C++代码如下:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <numeric>
#include <cmath>
std::vector<std::string> bigram(std::string initial_str) {
int len = initial_str.size();
std::vector<std::string> tokens;
for (int i = 0; i < len-1; i += 1){
tokens.push_back(initial_str.substr(i, 2));
}
return tokens;
}
std::vector<std::string> vsunion(std::vector<std::string> s1, std::vector<std::string> s2) {
std::vector<std::string> union_str(s1);
union_str.insert(union_str.end(), s2.begin(), s2.end());
std::sort(union_str.begin(), union_str.end());
union_str.erase(std::unique(union_str.begin(), union_str.end()), union_str.end());
return union_str;
}
std::vector<int> ufreq(std::vector<std::string> u, std::vector<std::string> s) {
int len = u.size();
std::vector<int> vfreq;
for (int i = 0; i < len; i += 1){
int freq = std::count(s.begin(), s.end(), u[i]);
vfreq.push_back(freq);
}
return vfreq;
}
float similarity(std::vector<int> f1, std::vector<int> f2) {
float num = std::inner_product(f1.begin(), f1.end(), f2.begin(), 0.0);
float den1 = std::inner_product(f1.begin(), f1.end(), f1.begin(), 0.0);
float den2 = std::inner_product(f2.begin(), f2.end(), f2.begin(), 0.0);
float similarity = num / std::sqrt(den1 * den2);
return similarity;
}
float similarity(std::string string1, std::string string2) {
std::vector<std::string> new_str = bigram(string1);
std::vector<std::string> new_str2 = bigram(string2);
std::vector<std::string> union_str = vsunion(new_str, new_str2);
std::vector<int> freq1 = ufreq(union_str, new_str);
std::vector<int> freq2 = ufreq(union_str, new_str2);
float score = similarity(freq1, freq2);
return score;
}
extern "C" {
float gram(std::string str1, std::string str2)
{
return similarity(str1, str2);
}
}
我使用以下方法编译:
g++ gram.cpp -shared -o gram.so
最后,我尝试导入以下脚本,该脚本在标题“_ZSt28__ throw_bad_array_new_lengthv 无法位于动态链接库中”中抛出错误:
import ctypes
import sys
import os
dir_path = os.path.dirname(os.path.realpath(__file__))
handle = ctypes.CDLL(dir_path + "/gram.so")
handle.My_Function.argtypes = [ctypes.c_wchar_p]
def gram(string1, string2):
return handle.gram(string1, string2)
知道我哪里出了问题吗? 我可以编译一个测试用例而不是“外部”位:
int main() {
float score = similarity("John Smith", "Johnny John Smith");
std::cout << score << " ";
std::cin.get();
}
并作为exe运行,看起来没有问题;
似乎出了点问题handle = ctypes.CDLL(dir_path + "/gram.so")
gram 图书馆的舞台。
最后,我尝试导入以下脚本,该脚本在标题“_ZSt28__ throw_bad_array_new_lengthv 无法位于动态链接库中”中抛出错误:
此错误意味着:运行时可用的
libstdc++.so
版本没有 std::throw_bad_array_new_length
符号,而您的 gram.so
正在使用该符号。
虽然可以用
g++ gram.cpp -shared -o gram.so -fPIC -static-libstdc++ -static-libgcc
解决这个问题,但你真的不应该——它迟早会在你脸上爆炸。
相反,您应该使用
Python
,它已链接到 libstdc++.so.6
适合您的系统。
似乎是某些 GCC/运行时版本和 LIBSTD 动态链接的纯粹 MINGW 问题。
在我的设置中,Dependency Walker 识别出我的 DLL 的分支
LIBSTD6++-.DLL
中缺少的函数:void __throw_bad_array_new_length()
为了解决正式问题,我在 DLL 中添加了以下存根
#include <new>
namespace std
{
__attribute__((visibility("default"))) void __throw_bad_array_new_length()
{ _GLIBCXX_THROW_OR_ABORT(bad_array_new_length()); }
}
这满足了 Dependeby Walker,应用程序运行,尽管调试器仍然存在问题并拒绝加载应用程序。
我的解决方案是切换合适的编译器/运行时版本。