1 #pragma once
2 
3 #include <dlfcn.h>
4 
5 #include <stdexcept>
6 #include <string>
7 
8 namespace mous {
9 
10 using FnPluginType = PluginType (*)(void);
11 using FnPluginInfo = const PluginInfo* (*)(void);
12 using FnCreateObject = void* (*)(void);
13 using FnFreeObject = void (*)(void*);
14 
15 class Plugin::Impl
16 {
17   public:
18     void* lib = nullptr;
19     FnPluginType GetPluginType = nullptr;
20     FnPluginInfo GetPluginInfo = nullptr;
21     FnCreateObject CreateObject = nullptr;
22     FnFreeObject FreeObject = nullptr;
23     PluginType type = PluginType::None;
24 
Impl(const std::string & path)25     explicit Impl(const std::string& path)
26     {
27         std::string what;
28 
29         lib = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
30         if (!lib) {
31             goto RaiseException;
32         }
33 
34         GetPluginType = reinterpret_cast<FnPluginType>(dlsym(lib, StrGetPluginType));
35         if (!GetPluginType) {
36             goto CleanupAndRaise;
37         }
38 
39         GetPluginInfo = reinterpret_cast<FnPluginInfo>(dlsym(lib, StrGetPluginInfo));
40         if (!GetPluginInfo) {
41             goto CleanupAndRaise;
42         }
43 
44         CreateObject = reinterpret_cast<FnCreateObject>(dlsym(lib, StrCreateObject));
45         if (!CreateObject) {
46             goto CleanupAndRaise;
47         }
48 
49         FreeObject = reinterpret_cast<FnFreeObject>(dlsym(lib, StrFreeObject));
50         if (!CreateObject) {
51             goto CleanupAndRaise;
52         }
53 
54         type = GetPluginType();
55         return;
56 
57     RaiseException:
58         what = dlerror();
59         throw std::runtime_error(what);
60 
61     CleanupAndRaise:
62         what = dlerror();
63         dlclose(lib);
64         throw std::runtime_error(what);
65     }
66 
~Impl()67     ~Impl() { dlclose(lib); }
68 };
69 }
70