0

I need to use cppyy to call functions from a 3rd-party C++ library in Python. To start I wrote a simple C++ function and tried to load it in Python:

test.hpp

class Test {
    public:
        void test();
};

test.cpp

#include <iostream>
#include "test.hpp"

void Test::test() {
    std::cout << "Hello World!" << std::endl;
}

I then create test.dll with the following command line (I'm on Windows now, but the final project should run on a Jetson Nano with Ubuntu 20.04):

g++ -shared test.hpp test.cpp -o testlib.dll

test.py

import cppyy

cppyy.include('test.hpp')
cppyy.load_library('testlib.dll')

from cppyy.gbl import Test

t = Test()
t.test()

This code crashes on the last line t.test() with the following error:

IncrementalExecutor::executeFunction: symbol '?Y@X@@QEAAXXZ' unresolved while linking symbol '__cf_8'!
You are probably missing the definition of public: void __cdecl X::Y(void) __ptr64
Maybe you need to load the corresponding shared library?

I tried to look for solutions online but didn't find much, the only thing I tried was something about adding __declspec(dllexport) in the class definition but that didn't help, and I never really worked with C++ before and couldn't understand most of the rest, so any help would be appreciated.

Thank you in advance.

1 Answers1

0

This is purely a Windows issue: it by default keeps symbols non-visible outside shared libraries and you need to explicitly export them. Other platforms, such as Linux, do the opposite: by default visible, and you need to declare symbols hidden if that's desired. MSVC can generate export files for you to make all symbols visible by default (and cmake offers an easy utility), but I'm not sure whether gcc on Windows supports this.

(You write that this is for a 3rd-party C++ library? If is is the case that you can not modify the source, then that's the best option. If you only have binaries, then they must be already supporting the symbols, or those libraries are unusable even from C++.)

Using __declspec(dllexport) is indeed possible, but requires a bit of care: if the header is seen by the compiler building the shared library, then it's to be dllexport. When seen by Cling, it's to be dllimport. Something like:

#ifdef _WIN32
#ifdef __CLING__
#define MY_PROJECT_EXTERN extern __declspec(dllimport)
#else
#define MY_PROJECT_EXTERN extern __declspec(dllexport)
#endif
#else
#define MY_PROJECT_EXTERN extern
#endif

although the more common thing to do is to invert the logic. That is, use #ifdef MY_PROJECT_INTERNAL or some such instead of #ifdef __CLING__, and define MY_PROHECT_INTERNAL when building the shared library on Windows. Point being that this is a general issue for any other C++ project using the header files and libraries of your project, not something specific to Cling. (And because it is a general issue, I suspect that the 3rd party library already provided something like it, if it is intended to be used on Windows.)

Wim Lavrijsen
  • 3,453
  • 1
  • 9
  • 21
  • Hey, thanks for the reply. First of all I'm really glad this is not a problem on Linux. Secondly, I checked the source code of the library I want to use and they indeed have something similar to what you described here. I then tried to put the code you gave at the top of the tess.hpp file and then add ```MY_PROJECT_EXTERN``` before the class name and in the test.cpp file function declaration (I also had to remove the ```;``` and the ```extern```, otherwise the linking failed). However I still got the same error as before when running test.py. Did I use it incorrectly? – Natanel Birarov Jul 25 '22 at 07:25
  • Sorry about the ';'. I've removed it above. Also, if this is used on a class, then the macro should be defined to nothing (not `extern`) on Linux/Mac. But otherwise, this should have worked. Can you verify that in test.cpp `dllexport` is indeed seen, and in Cling `dllimport`? (E.g. place `#error msg` in the code path to show which is being taken.) – Wim Lavrijsen Jul 25 '22 at 20:12