1

I have a main program that, in the course of its work, loads a dynamic library, imports an instance of a class from there, and executes its method. The main program has a Test class and two files Test.h Test.cpp.

Test.h:

class Test {
  public:
      virtual void work() = 0;
}
class Test2 : public Test {
  public:

    void work() override;
    virtual void test() = 0;
}

test.cpp:
void Test2::work(){

/*do something*/

}

Accordingly, this code is compiled in the main program. To create a dynamic library (.so/.dll), only the Test.h file is provided. Then the code of the library itself looks like this: lib.cpp:

#include "Test.h"
#include <iostream>
class Test3 : public Test2 {

   public:
     void test() override {
          std::cout<<"I'm test 3"<<std::endl;
      }
}
extern "C" BOOST_SYMBOL_EXPORT Test3 plugin;

For linux, everything builds without problems and subsequently this .so library works correctly, but for .dll on Windows it gives an error: "undefined reference to `vtable' for Test2". That is, it requires me to provide an implementation of the virtual function work (). Is there any way to get around this? I use regular CMake to build. cmake.txt:

add_library(lib SHARED Test.h lib.cpp)
dex
  • 11
  • 1
  • Going to go on a limb and guess you need `dllexport`/`dllimport` – ChrisMM Apr 27 '22 at 14:40
  • @ChrisMM Inserting __declspec( dllimport ) before Test2 and also __declspec( dllexport) before Test3 doesn't solve the problem, it still requires me to implement Test2::work() – dex Apr 27 '22 at 14:44
  • `class Test3 : public Test2 {` probably should be `class BOOST_SYMBOL_EXPORT Test3 : public Test2 {` if `BOOST_SYMBOL_EXPORT` is defined as `__declspec(dllexport)` when building the dll and `__declspec(dllimport)` when using the dll. – drescherjm Apr 27 '22 at 14:48
  • I recommend you test this msdn example: [https://learn.microsoft.com/en-us/cpp/build/walkthrough-creating-and-using-a-dynamic-link-library-cpp?view=msvc-170](https://learn.microsoft.com/en-us/cpp/build/walkthrough-creating-and-using-a-dynamic-link-library-cpp?view=msvc-170) – drescherjm Apr 27 '22 at 14:50
  • This answer is about using a class with dllexport/dllimport: [https://stackoverflow.com/a/28022/487892](https://stackoverflow.com/a/28022/487892) – drescherjm Apr 27 '22 at 14:52
  • @drescherjm I omitted the details with BOOST_SYMBOL_EXPORT when composing the question. In fact, there really is a class BOOST_SYMBOL_EXPORT Test3 : public Test2 .... however it does not solve the problem – dex Apr 27 '22 at 14:55
  • 1
    It's `Test2` that needs to be exported, to allow you to inherit from it. Do yourself a favor and make your base classes which are used across the library boundary an "interface" with no implementation and no non-static data members, only pure virtual functions (like COM does). – Ben Voigt Apr 27 '22 at 15:07
  • @BenVoigt but why does this code work on linux? – dex Apr 27 '22 at 15:28
  • Linux uses a different compiler with different rules. – drescherjm Apr 27 '22 at 15:38
  • @drescherjm and there is no one way to compile this code for windows? – dex Apr 27 '22 at 15:39
  • You have to properly export/import in windows – drescherjm Apr 27 '22 at 15:40
  • 1
    It doesn't work *reliably* on Linux, not anymore. Back in the C++03 days Linux had a single C++ library and single C++ ABI (on almost all platforms), so even if the application and shared object were built at different times with different compiler versions, they'd be compatible. Since C++11 forced ABI-breaking changes, and llvm's libc++ became as popular as the G++ library, compatibility is no longer automatic even on Linux. – Ben Voigt Apr 27 '22 at 15:41
  • On Windows, there has never been any platform-wide C++ ABI, apart from vtable compatibility with COM. So the only way to make a plugin system that doesn't require exact same compiler version and exact same compile options is to stick to pure interface base classes, like COM does (you don't have to go full-blown COM with its complicated factory system and interprocess marshalling). – Ben Voigt Apr 27 '22 at 15:43
  • @BenVoigt But how can I create a clean base interface if, for example, I would like to have access to variables from the main program in the plugin implementation? And these variables are class instances and they are created in the main program – dex Apr 27 '22 at 15:52
  • 1
    @devX: You define an interface with getter (and optionally setter) functions for each of those variables. Implement it in the main program. When creating a plugin object, you pass a pointer to this main-program-access interface to the plugin. In COM, this pattern is called a "Site" eg `IOleClientSite`, `IOleControlSite`, `IOleDocumentSite`, etc. – Ben Voigt Apr 27 '22 at 16:03

0 Answers0