Search code examples
pythonc++ctypesgmp

How can I compile multiple C++ files to use them with Python ctypes?


I have a little problem with the compilation of multiple C++ on Windows. I implemented four classes in C++ for cryptography with gmp. I want to call them from Python with ctypes. I wrote a cpp file with the extern keyword:

#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(); }
}

I compiled my files with:

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

But when I use these commands in Python:

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

The variable x does not have the functions: newModNum, getModValue, etc... Could anyone tell me what I'm doing wrong? I get no error and I do not understand. My other files are common C ++ files with header and implementation.

Thanks in advance and have a nice day!


Solution

  • ctypes functions are imported on first use. Using libc as an example:

    >>> 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 assumes all parameters and the return value are int. You should give type hints which also conveniently import the functions.

    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
    

    And remove the semicolons from the end of lines. It causes dangerous blood pressure spikes in python programmers.