从单个.cpp构建共享对象

Building a shared object from a single .cpp

本文关键字:共享 对象 构建 cpp 单个      更新时间:2023-10-16

我正在尝试从一组简单函数的cpp文件构建共享对象库。 我想使用ctypes与python交互。

假设我有cpp文件:

#include "print.h"
#include <vector>
#include <iostream>
#include <dlfcn.h>
void print_array(const std::vector<std::vector<float>> &A){
for(size_t i = 0; i < A.size(); i++) {
for(size_t j = 0; j < A[0].size(); j++) {
std::cout << A[i][j] << "n";
}
}
}

和头文件

#ifndef ADD_H
#define ADD_H
#include <vector>
void print_array(const std::vector<std::vector<float>> &A);
#endif

我试图建造

g++ -fpic -c print.cpp -o print.o
g++ -shared -o print.so print.o

然后在蟒蛇中

from cytpes import cdll
print_lib = cdll.LoadLibrary("print.so")

print_lib.print_array()

收益 率

AttributeError: ./print.so: undefined symbol: print_array

nm -D print.so

给出输出

0000000000201060 B __bss_start
U __cxa_atexit
w __cxa_finalize
0000000000201060 D _edata
0000000000201068 B _end
0000000000000c14 T _fini
w __gmon_start__
0000000000000898 T _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
0000000000000a50 T _Z11print_arrayRKSt6vectorIS_IfSaIfEESaIS1_EE
0000000000000bcc W _ZNKSt6vectorIfSaIfEE4sizeEv
0000000000000bf2 W _ZNKSt6vectorIfSaIfEEixEm
0000000000000b6a W _ZNKSt6vectorIS_IfSaIfEESaIS1_EE4sizeEv
0000000000000ba2 W _ZNKSt6vectorIS_IfSaIfEESaIS1_EEixEm
U _ZNSolsEf
U _ZNSt8ios_base4InitC1Ev
U _ZNSt8ios_base4InitD1Ev
U _ZSt4cout
U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc

我在编译步骤中根本上做错了什么?

您正在调用C++函数,而ctypes期望 C 函数链接:

  • 正如您所注意到的,C 函数具有不同的(即无(名称重整
  • C 函数不能有C++参数(std 对象,如 std::vector、引用等(

要解决您的问题,请在标头中声明一个干净的 C 样式 API,如果您打算在 C++ 中实现函数并使用 g++ 作为编译器/链接器,则必须在头文件中的函数声明之前添加一个extern "C"声明,或者作为声明周围的块:

extern "C" void print_array(...);

这将防止C++名称重整。

在接口函数中使用向量和其他C++类型会导致 ABI 问题,即"它不起作用",即使所有内容的链接和编译看起来都很干净。

将 C 函数与 ctypes支持的数据类型一起使用(请参阅有关 ctypes 的 Python 文档(作为接口,随意在 C++ 中实现,但然后将 C 函数声明包装在extern "C"块中以防止名称重整。

请参考 ctypes 的文档,了解如何正确使用结构、联合、引用等作为函数参数,因为有许多陷阱和问题需要考虑。