如何编译多个 C++ 文件以将它们与 Python ctypes 一起使用?

Posted

技术标签:

【中文标题】如何编译多个 C++ 文件以将它们与 Python ctypes 一起使用?【英文标题】:How can I compile multiple C++ files to use them with Python ctypes? 【发布时间】:2020-02-12 17:27:01 【问题描述】:

我在 Windows 上编译多个 C++ 有点问题。 我在 C++ 中实现了四个类,用于使用 gmp 进行密码学。我想用 ctypes 从 Python 调用它们。 我用extern关键字写了一个cpp文件:

#include "integer.h"
#include "modular_number.h"
#include "padic_number.h"
#include "rational_number.h"

extern "C" 
    __declspec(dllexport) ModNum* newModNum(const char * n, const char * p)  return new ModNum(Integer(n), Integer(p)); 
    __declspec(dllexport) const char* getModValue(const ModNum& mod) return mod.getValue().getValue(); 

    __declspec(dllexport) RationalNum* newRationalNum(const char* mpq)  return new RationalNum(mpq); 
    __declspec(dllexport) const char* getRationalValue(const RationalNum& rat) return rat.getValue(); 

    __declspec(dllexport) PadicNum* newPadicNum(const char* n, const char* base)  return new PadicNum(Integer(n), Integer(base)); 
    __declspec(dllexport) const char* getPadicValue(const PadicNum& padic) return padic.getValue().getValue(); 

我编译了我的文件:

mingw32-g++ -fexceptions -g -fexpensive-optimizations -flto -O3 -Weffc++ -Wextra -Wall -std=c++14 -fPIC -Og -IC:\MinGW\include -flto -s -lgmp -lmpfr -lpthread -c -fPIC *.cpp -I"C:\Program Files\Python38-32\include" -I"C:\Program Files\Python38-32\libs"

mingw32-g++.exe -shared -Wl,-dll -o numeric.dll *.o -lgmp -lmpfr -lgmpxx -static

但是当我在 Python 中使用这些命令时:

import ctypes;
x = ctypes.DLL("./numeric.dll");

变量x不具备以下功能:newModNumgetModValue等... 谁能告诉我我做错了什么?我没有错误,我不明白。 我的其他文件是带有头文件和实现的普通 C++ 文件。

提前致谢,祝您有美好的一天!

【问题讨论】:

您是否引用过它们一次(例如,x.newModNum)? ctypes 在首次使用时加载一个函数。 dumpbin /exports numeric.dll 可以向您展示真正导出的内容。假设您可以找到 dumpbin.exe。如果您有 Visual Studio 并使用 Visual Studio 命令提示符,它通常可用。 另一个添加到您的盒子的工具是dependencywalker (dependencywalker.com),它在过去的 DLL 和导出方面帮助了我很多。顺便说一句:您应该提供minimal reproducible example。在您的情况下,您将能够从问题空间中消除 GMP 和“多重”,从而降低剩余的复杂性。 @Ulrich 谢谢你的提示,我会看到的。 @tdelaney 不,我没有提到它们,因为我认为 ctypes 会寻找 extern 关键字。我看到了很多例子,我没有注意到其他人提到他们的功能要导出。就像在这篇文章中一样***.com/questions/145270/calling-c-c-from-python。 @G.F - ctypes 按需加载。例如,在您引用的问题***.com/a/145649/642070 的一个答案中,第一个self.obj = lib.Foo_new() 加载Foo_new。你可以放一个x.newModNum; newModNum in dir(x) 来检查。顺便说一句,您可能希望在使用它们之前向您的函数添加 argtypesrestype 类型提示,这也是加载它们的第一个引用。 【参考方案1】:

ctypes 函数在首次使用时被导入。以libc为例:

>>> import ctypes
>>> libc = ctypes.CDLL("libc.so.06")
>>> "printf" in dir(libc)
False
>>> libc.printf
<_FuncPtr object at 0x7f6512c23430>
>>> "printf" in dir(libc)
True

ctypes 假定所有参数和返回值为int。您应该提供类型提示,也可以方便地导入函数。

import ctypes
x = ctypes.DLL("./numeric.dll")
x.newModNum.argtypes = [ctypes.c_char_p, ctypes.c_char_p] # <-- also imports
x.newModNum.rettype = ctypes.c_void_p

并从行尾删除分号。它会导致 Python 程序员出现危险的血压峰值。

【讨论】:

O.o 我写了分号吗?我没有意识到它o.O无论如何感谢您的帮助!现在我不能尝试,因为我没有代码。我明天早上试试,如果有什么问题我会写的。 好的,它工作,但正如你所说,它不返回一个对象,而是一个整数。所以我不能使用它......有没有办法调用C++函数来使用它的对象,比如python对象而不实现PyObject?我必须为每个操作实现一个函数吗? 最后,我为每个算术运算实现了一个extern函数。现在我可以利用 C++ 的速度来执行此操作。无论如何,非常感谢您的帮助!非常珍贵!

以上是关于如何编译多个 C++ 文件以将它们与 Python ctypes 一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

如何将一个事件拆分为多个事件以将它们发送到多路复用扇出流

编译 C++ 源代码以将 .off 文件转换为 Android OpenGL ES 可读的 XML 的问题

如何使用 Python 中的 DLL 文件?

如何配置 mex 以将编译器标志传递给 nvcc

多个目标文件中的 C++ 模板和编译

如何提高以同步方式处理多个 Arraylist 请求的性能,以将它们创建为没有重复的最终列表