#pragma once #include #if defined(LINUX) || defined(EMSCRIPTEN) #include #define EXPORT virtual #define LIBRARY_SUFFIX ".so" #define HANDLE_TYPE void* #endif #if WINDOWS #define NOMINMAX #define NOGDI #define WIN32_LEAN_AND_MEAN #include #define EXPORT virtual __declspec(dllexport) #define LIBRARY_SUFFIX ".dll" #define HANDLE_TYPE HMODULE #endif #define FACTORY(x) extern "C" x* create_object() { return new x; } #include template class Module { public: Module(const std::string& path) { #ifdef LINUX handle = dlopen((path + LIBRARY_SUFFIX).c_str(), RTLD_LAZY); if(!handle) { std::cerr << dlerror() << std::endl; return; } create = reinterpret_cast(dlsym(handle, "create_object")); const char* err = dlerror(); if(err) { std::cerr << err << std::endl; return; } #endif #if WINDOWS handle = LoadLibrary((path + LIBRARY_SUFFIX).c_str()); if(!handle) { std::cerr << "Failed to load library " << path + LIBRARY_SUFFIX << std::endl; } create = reinterpret_cast(GetProcAddress(handle, "create_object")); #endif } ~Module() { #ifdef LINUX if(handle && create) dlclose(handle); #endif #ifdef WINDOWS if(handle && create) FreeLibrary(handle); #endif } bool IsValid() { return handle != nullptr; } T* construct() { return create(); } private: T* (*create)(); HANDLE_TYPE handle = nullptr; };