CppADCodeGen  2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
linux_dynamiclib.hpp
1 #ifndef CPPAD_CG_LINUX_DYNAMICLIB_INCLUDED
2 #define CPPAD_CG_LINUX_DYNAMICLIB_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2012 Ciengis
6  * Copyright (C) 2018 Joao Leal
7  *
8  * CppADCodeGen is distributed under multiple licenses:
9  *
10  * - Eclipse Public License Version 1.0 (EPL1), and
11  * - GNU General Public License Version 3 (GPL3).
12  *
13  * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
14  * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
15  * ----------------------------------------------------------------------------
16  * Author: Joao Leal
17  */
18 #if CPPAD_CG_SYSTEM_LINUX
19 
20 #include <typeinfo>
21 #include <dlfcn.h>
22 
23 namespace CppAD {
24 namespace cg {
25 
32 template<class Base>
33 class LinuxDynamicLib : public DynamicLib<Base> {
34 protected:
35  const std::string _dynLibName;
37  void* _dynLibHandle;
38  std::set<LinuxDynamicLibModel<Base>*> _models;
39 public:
40 
41  explicit LinuxDynamicLib(std::string dynLibName,
42  int dlOpenMode = RTLD_NOW) :
43  _dynLibName(std::move(dynLibName)),
44  _dynLibHandle(nullptr) {
45 
46  std::string path;
47  if (_dynLibName[0] == '/') {
48  path = _dynLibName; // absolute path
49  } else if (!(_dynLibName[0] == '.' && _dynLibName[1] == '/') &&
50  !(_dynLibName[0] == '.' && _dynLibName[1] == '.')) {
51  path = "./" + _dynLibName; // relative path
52  } else {
53  path = _dynLibName;
54  }
55 
56  // load the dynamic library
57  _dynLibHandle = dlopen(path.c_str(), dlOpenMode);
58  CPPADCG_ASSERT_KNOWN(_dynLibHandle != nullptr, ("Failed to dynamically load library '" + _dynLibName + "': " + dlerror()).c_str())
59 
60  // validate the dynamic library
61  this->validate();
62  }
63 
64  LinuxDynamicLib(const LinuxDynamicLib&) = delete;
65  LinuxDynamicLib& operator=(const LinuxDynamicLib&) = delete;
66 
67  virtual std::unique_ptr<LinuxDynamicLibModel<Base>> modelLinuxDyn(const std::string& modelName) {
68  std::unique_ptr<LinuxDynamicLibModel<Base>> m;
69  auto it = this->_modelNames.find(modelName);
70  if (it == this->_modelNames.end()) {
71  return m;
72  }
73  m.reset(new LinuxDynamicLibModel<Base> (this, modelName));
74  _models.insert(m.get());
75  return m;
76  }
77 
78  std::unique_ptr<FunctorGenericModel<Base>> modelFunctor(const std::string& modelName) override final {
79  return std::unique_ptr<FunctorGenericModel<Base>>(modelLinuxDyn(modelName).release());
80  }
81 
82  void* loadFunction(const std::string& functionName, bool required = true) override {
83  void* functor = dlsym(_dynLibHandle, functionName.c_str());
84 
85  if (required) {
86  char *err = dlerror();
87  if (err != nullptr)
88  throw CGException("Failed to load function '", functionName, "': ", err);
89  }
90 
91  return functor;
92  }
93 
94  virtual ~LinuxDynamicLib() {
95  for (LinuxDynamicLibModel<Base>* model : _models) {
96  model->modelLibraryClosed();
97  }
98 
99  if (_dynLibHandle != nullptr) {
100  if(this->_onClose != nullptr) {
101  (*this->_onClose)();
102  }
103 
104  dlclose(_dynLibHandle);
105  _dynLibHandle = nullptr;
106  }
107  }
108 
109 protected:
110 
111  virtual void destroyed(LinuxDynamicLibModel<Base>* model) {
112  _models.erase(model);
113  }
114 
115  friend class LinuxDynamicLibModel<Base>;
116 
117 };
118 
119 } // END cg namespace
120 } // END CppAD namespace
121 
122 #endif
123 #endif