4

I'm working on a cross platform project where I have to load dynamic libraries. I therefore created a very basic platform independent templated wrapper class around dlopen/loadLibrary that act like a factory class and return unique_ptr<T>s of the lib object.

But this is very unpractical in most of the cases, I therefore wondered, how can I design a simple wrapper that can do the following:

  • Load a lib and become a factory on instances of that lib objects for when we have to use multiple instances of the lib object
  • Create a self managed entity (a struct containing a unique ptr on the object and the handle on the lib maybe ?) for when we want to use only one instance of a lib object and not bother with a factory
  • Use the library provided deleter (symbol "destroy") instead of the default one

Does this exist ? If not, what would be the best way to do this ?

My implementation so far:

#pragma once

#include <memory>
#include <iostream>
#if _WIN32
#include <Windows.h>
#else
#include <dlfcn.h> //dlopen
#endif

namespace utils
{

template <class T>
class DynLib
{
  public:
    DynLib() = default;
    ~DynLib()
    {
        if (handle_)
            closeLib(handle_);
    };

  private:
    bool printLibError()
    {
#if _WIN32
        std::cerr << GetLastError() << std::endl;
#else
        std::cerr << dlerror() << std::endl;
#endif
        return false;
    }

    void *openLib(const std::string &libName)
    {
#if _WIN32
        return LoadLibrary((libName + ".dll").c_str());
#else
        return dlopen((libName + ".so").c_str(), RTLD_LAZY);
#endif
    }

    int closeLib(void *libHandle)
    {
#if _WIN32
        return FreeLibrary((HMODULE)libHandle);
#else
        return dlclose(libHandle);
#endif
    }

    void *loadSymbol(void *libHandle, const char *sym)
    {
#if _WIN32
        return (void *)GetProcAddress((HMODULE)libHandle, sym);
#else
        return dlsym(libHandle, sym);
#endif
    }

  public:
    bool open(const std::string &filename, const char *csym = "create", const char *dsym = "destroy")
    {

        if (!(handle_ = openLib(filename)))
            return printLibError();
        if (!(create = (T * (*)()) loadSymbol(handle_, csym)))
            return printLibError();
        if (!(destroy_ = (void (*)(T *))loadSymbol(handle_, dsym)))
            return printLibError();
        return true;
    }

    std::unique_ptr<T> createUnique()
    {
        return (std::unique_ptr<T>(create()));
    }

  private:
    void *handle_{nullptr};
    T *(*create)();
    void (*destroy_)(T *);
};
}
Théo Champion
  • 1,701
  • 1
  • 21
  • 46

1 Answers1

2

Have you considered Boost.DLL library? It provides examples on how implement plugins/factory methods.

Begemoth
  • 64
  • 4