0

I have a my_class.h:

// my_class.h

namespace N
{
    class my_class
    {
    public:
        void hello_world();
    };
}

with a my_class.cpp file.

// my_class.cpp

extern "C" {
    #include "my_class.h"
}
#include <iostream>

using namespace N;
using namespace std;

void my_class::hello_world()
{
    cout << "Hello, World!" << endl;
}

I want to create a shared object my_class.so file to use it in python. Therefore, I am using the g++ compiler.

g++ -fPIC -shared -o my_class.so my_class.cpp

Using the shared object in python my_class.so

import ctypes

my_class = ctypes.cdll.LoadLibrary('./my_class.so')
my_class.hello_world

I get the following error message:

Exception has occurred: AttributeError
./my_class.so: undefined symbol: hello_world

I do not know how to interpret this.
Note:

  • my_class.hello_world() results the same error
3
  • Why are you including a c++ header inside extern C? You are using C linkage with C++ code, so it wont work Commented Oct 7, 2021 at 15:31
  • Do you mean that I need to remove the extern "C" wrapper in my_class.cpp? It is still not working even without it. Commented Oct 8, 2021 at 12:56
  • I do not know how python handles mangled names. However, extern C definitely shouldn’t be there Commented Oct 8, 2021 at 20:22

1 Answer 1

2

Much to talk about, but I'll try to be brief:

  1. extern "C" is going to make those symbols available in the C-syntax. (You do want this)
  2. C-syntax does not support classes or namespaces.
  3. the python dynamic library loader is grabbing ALL the symbols - not just your class. (It seems there is some confusion there with the naming scheme)

To Fix: Simply eliminate your class and namespaces (or add a C-API pass-through).

my_class.h

extern "C" {
   void hello_world();
}

my_class.cpp

#include "my_class.h"
#include <iostream>

void hello_world()
{
        std::cout<<"Hello, World" << std::endl;
}

After you build, use nm or objdump to verify that the symbol hello_world is defined and not mangled. Example:

>> nm my_class.so | grep hello
0000000000000935 T hello_world

And your python code will need an open close parenthesis to tell it to execute the function:

import ctypes

my_class = ctypes.cdll.LoadLibrary('./my_class.so')
my_class.hello_world()
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! But I did not get the usage of extern "C" {...} in this context. Why do I need it in the header file and why do I need it at all?
If it worked without the extern "C", then the python package ctypes might be smart enough to search for the mangled version as well. C++ mangles it's symbols, C does not. For example, run nm on a binary with a hello_world() function compiled as cpp. You should see something like "_Z11hello_worldv". This is the actual name written to the binary file for future lookups. to ensure the mangling doesn't happen, you can use 'extern "C"'.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.