DAS  3.0
Das Analysis System
PluginLoader.h
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPLv3-or-later
2 //
3 // SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
4 // SPDX-FileCopyrightText: Patrick L.S. Connor <patrick.connor@cern.ch>
5 
6 #pragma once
7 
8 // STD
9 #include <algorithm>
10 #include <dlfcn.h>
11 #include <filesystem>
12 #include <iostream>
13 #include <memory>
14 #include <ranges>
15 #include <string>
16 #include <type_traits>
17 #include <vector>
18 
19 // BOOST
20 #include <boost/exception/all.hpp>
21 
22 // Darwin
23 #include "IPlugin.h"
24 #include "Options.h"
25 #include "colours.h"
26 #include "exceptions.h"
27 
28 namespace Darwin::Tools {
29 
36 class PluginLoader {
37 
38  std::filesystem::path file;
39  std::vector<std::unique_ptr<IPlugin>> plugins;
40  void * handle;
41  int steering;
42 
43 public:
44 
53  PluginLoader (const std::filesystem::path& file,
54  int steering = none
55  )
56  try : file(file)
57  , handle(nullptr)
59  {
60  using namespace std;
61 
62  if (steering & verbose)
63  cout << "PluginLoader: Loading plugin from " << file << endl;
64 
66  handle = dlopen(file.c_str(), RTLD_LAZY);
67  if (!handle) {
68  string what = file.string() + " could not be loaded"s;
69  const char * error = dlerror();
70  if (error != nullptr)
71  what += ": "s + error;
72  BOOST_THROW_EXCEPTION( invalid_argument(what) );
73  }
74 
75  typedef vector<unique_ptr<IPlugin>> * create_t();
76  auto CreatePlugin = (create_t *) dlsym(handle, "CreatePlugin");
77  if (!CreatePlugin) {
78  string what = "`CreatePlugin` could not be found"s;
79  const char * error = dlerror();
80  if (error != nullptr)
81  what += ": "s + error;
82  BOOST_THROW_EXCEPTION( runtime_error(what) );
83  }
84  vector<unique_ptr<IPlugin>> * iplugins = CreatePlugin();
85  if (iplugins == nullptr)
86  BOOST_THROW_EXCEPTION( runtime_error("`CreatePlugin` returns a nullptr") );
87  plugins = std::move(*iplugins);
88  ranges::for_each(plugins, [file](unique_ptr<IPlugin>& p) { p->SetPath(file); });
89  }
90  catch (boost::exception& e) {
91  namespace DE = Darwin::Exceptions;
92  BOOST_THROW_EXCEPTION( DE::PluginException(file, e) );
93  }
94 
98  : file(other.file)
99  , plugins(std::move(other.plugins))
100  , handle(std::move(other.handle))
101  {
102  using namespace std;
103 
104  if (steering & verbose)
105  cout << "PluginLoader: Moving plugin from " << file << endl;
106 
107  other.file.clear();
108  other.plugins.clear();
109  other.handle = nullptr;
110  }
111 
114  ~PluginLoader () noexcept
115  {
116  using namespace std;
117 
118  if (steering & verbose)
119  cout << "PluginLoader: Closing plugin from " << file << endl;
120 
121  plugins.clear(); // Delete plugins _before_ closing the handle.
122 
123  if (!handle) return;
124  int code = dlclose(handle);
125  if (code != 0)
126  cerr << orange << "The plugin(s) loaded from " << file
127  << " closed with error " << code << def << '\n';
128  }
129 
132  std::filesystem::path Which () const { return file; }
133 
136  template<Plugin P> auto Get () const
137  {
138  using namespace std;
139  auto convert = [this](IPlugin * plugin) -> P * {
140  auto ptr = dynamic_cast<P*>(plugin);
141  if (ptr == nullptr) {
142  string what = "Invalid plugin type for ";
143  what += file;
144  BOOST_THROW_EXCEPTION( logic_error(what) );
145  }
146  return ptr;
147  };
148  return plugins | views::transform(&unique_ptr<IPlugin>::get)
149  | views::transform(convert);
150  }
151 };
152 
153 } // end of Darwin::Tools namespace
Ntupliser_cfg.cerr
cerr
Definition: Ntupliser_cfg.py:105
Darwin::Exceptions::PluginException
Exception type to throw from plugins.
Definition: exceptions.h:132
exceptions.h
Step::def
static const char * def
Definition: Step.h:36
Darwin::Tools::IPlugin
Dummy, common type for all plugins in Darwin.
Definition: IPlugin.h:27
Ntupliser_cfg.p
p
Definition: Ntupliser_cfg.py:178
Darwin::Tools::none
@ none
default (for simple executables)
Definition: Options.h:28
P
P
Definition: Core-gitclone-lastrun.txt:6
colours.h
Darwin::Tools::plugin
@ plugin
activate -p to run a plugin
Definition: Options.h:35
CreatePlugin
PluginsVec * CreatePlugin()
Definition: BadPlugin.cc:9
Darwin::Tools::PluginLoader::file
std::filesystem::path file
plugin location
Definition: PluginLoader.h:38
Darwin::Tools::PluginLoader::steering
int steering
Definition: PluginLoader.h:41
IPlugin.h
Darwin::Exceptions
Handling of exceptions.
Definition: darwin.h:37
Darwin::Tools::verbose
@ verbose
bit for debug mode (-v is always available)
Definition: Options.h:29
Darwin::Tools::PluginLoader::Which
std::filesystem::path Which() const
Get plugin location.
Definition: PluginLoader.h:132
orange
static const char * orange
Definition: colours.h:6
Darwin::Tools::PluginLoader
Agnostic plugin loader.
Definition: PluginLoader.h:36
Darwin::Tools::PluginLoader::Get
auto Get() const
Access to plugin's raw pointers.
Definition: PluginLoader.h:136
Darwin::Tools::PluginLoader::PluginLoader
PluginLoader(const std::filesystem::path &file, int steering=none)
Standard constructor.
Definition: PluginLoader.h:53
Darwin::Tools::PluginLoader::plugins
std::vector< std::unique_ptr< IPlugin > > plugins
pointers to function return from the function called by dlopen
Definition: PluginLoader.h:39
Darwin::Tools::PluginLoader::~PluginLoader
~PluginLoader() noexcept
Closes the plugin handle.
Definition: PluginLoader.h:114
Darwin::Tools
Classes and functions related to the framework.
Definition: Darwin_dict.cxx:1144
Darwin::Tools::PluginLoader::handle
void * handle
pointer to object return by dlopen()
Definition: PluginLoader.h:40
Options.h
Darwin::Tools::PluginLoader::PluginLoader
PluginLoader(PluginLoader &&other)
Move constructor.
Definition: PluginLoader.h:97