【发布时间】: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不具备以下功能:newModNum、getModValue等...
谁能告诉我我做错了什么?我没有错误,我不明白。
我的其他文件是带有头文件和实现的普通 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关键字。我看到了很多例子,我没有注意到其他人提到他们的功能要导出。就像在这篇文章中一样stackoverflow.com/questions/145270/calling-c-c-from-python。 -
@G.F -
ctypes按需加载。例如,在您引用的问题stackoverflow.com/a/145649/642070 的一个答案中,第一个self.obj = lib.Foo_new()加载Foo_new。你可以放一个x.newModNum; newModNum in dir(x)来检查。顺便说一句,您可能希望在使用它们之前向您的函数添加argtypes和restype类型提示,这也是加载它们的第一个引用。