Home > database >  Calling Functions from within class using CTypes
Calling Functions from within class using CTypes

Time:07-06

I am trying to call a function from within a class which from what I understand, you just call as expected "object.class.function" is this correct, or am I doing something else wrong?

cLibrary.c

#include <stdio.h>
#include "clibrary.h"
 
void Clibrary::prompt()
{
    printf("hello world\n");
}

cLibrary.h

class Clibrary
{
public:
    Clibrary(){};
    ~Clibrary(){};
    static void prompt();
};

Then build it

g   -fPIC -shared -o clibrary.so cLibrary.c

Then test if it has the correct symbol

$ nm -gDC clibrary.so 
                 w __cxa_finalize
                 w __gmon_start__
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U puts
000000000000111a T Clibrary::prompt()

Then call it using CTypes in test.py.

#!/usr/bin/python3
import ctypes

libObject = ctypes.CDLL('./clibrary.so')
libObject.Clibrary.prompt()

Then try to run it

./test.py 
Traceback (most recent call last):
  File "./test.py", line 5, in <module>
    libObject.Clibrary.prompt()
  File "/usr/lib/python3.8/ctypes/__init__.py", line 386, in __getattr__
    func = self.__getitem__(name)
  File "/usr/lib/python3.8/ctypes/__init__.py", line 391, in __getitem__
    func = self._FuncPtr((name_or_ordinal, self))
AttributeError: ./clibrary.so: undefined symbol: Clibrary

NO STACK OVERFLOW MODERATORS: it is not like Calling C function from python using ctypes because it is within a class.

CodePudding user response:

ctypes understands C linkage and a C library normally needs to create extern "C" wrapper functions. In this special case you can force ctypes to load the name-decorated C symbol for the static method, but it isn't recommended.

Here's both demonstrated:

test.cpp

#include <stdio.h>

#ifdef _WIN32
#   define API __declspec(dllexport)  // Windows requires explicit export of functions.
#else
#   define API
#endif

class API Clibrary  // exported to see name decoration, but not needed
{
public:
    Clibrary() {};
    ~Clibrary() {};
    static void prompt() { printf("hello world\n"); }
};

// wrapper function with C linkage
extern "C" API void prompt() { Clibrary::prompt(); }

List of symbols exported from the DLL:

ordinal hint RVA      name

      1    0 00001020 ??0Clibrary@@QEAA@XZ
      2    1 00001030 ??1Clibrary@@QEAA@XZ
      3    2 00001040 ??4Clibrary@@QEAAAEAV0@AEBV0@@Z
      4    3 00001050 ?prompt@Clibrary@@SAXXZ
      5    4 00001000 prompt

test.py

import ctypes

libObject = ctypes.CDLL('./test')

# Hack but works.  Decorated name is not standard and could
# be different using a different compiler.
other = getattr(libObject,'?prompt@Clibrary@@SAXXZ')
other()

libObject.prompt()  # best and portable

Output:

hello world
hello world
  • Related