LIMA
Libre Multilingual Analyzer — C++ API
Loading...
Searching...
No Matches
DynamicLibrariesManager.cpp
Go to the documentation of this file.
1// Copyright 2002-2019 CEA LIST
2// SPDX-FileCopyrightText: 2022 CEA LIST <gael.de-chalendar@cea.fr>
3//
4// SPDX-License-Identifier: MIT
5
12#include "common/LimaCommon.h"
13
14#include <boost/filesystem.hpp>
15
16#ifdef WIN32
17#include <windows.h>
18#include <tlhelp32.h>
19#include <tchar.h>
20#elif __APPLE__
21//
22#else
23#include <link.h>
24#endif
25
26#include <iostream>
27#include <QtGlobal>
28#include <QString>
29#include <QStringList>
30#include <QRegularExpression>
31using namespace std;
32
33namespace Lima {
34namespace Common {
35
37{
40
41 bool isSomethingSimilarLoaded(const std::string& libName) const;
42
43 std::map<std::string, std::shared_ptr< QLibrary > > m_handles;
44 // at load time, will try to load the libraries
45 // from these paths before the default ones
46 std::vector<std::string> m_supplementarySearchPath;
47};
48
49DynamicLibrariesManagerPrivate::DynamicLibrariesManagerPrivate() :
50 m_handles(),
51 m_supplementarySearchPath()
52{
53}
54
55bool DynamicLibrariesManagerPrivate::isSomethingSimilarLoaded(const std::string& libName) const
56{
57 bool alreadyLoaded = false;
58
59#ifdef WIN32
60 HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
61 MODULEENTRY32 me32;
62
63 hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
64 if (hModuleSnap == INVALID_HANDLE_VALUE)
65 throw LimaException("CreateToolhelp32Snapshoot returned INVALID_HANDLE_VALUE.");
66
67 me32.dwSize = sizeof(MODULEENTRY32);
68
69 if (!Module32First(hModuleSnap, &me32))
70 {
71 CloseHandle(hModuleSnap);
72 throw LimaException("Module32First failed.");
73 }
74
75 do
76 {
77 //std::cerr << me32.szModule << std::endl;
78 std::string s(me32.szModule);
79 if (s.size() == 0)
80 return false;
81
82 boost::filesystem::path p(me32.szModule);
83 std::string fn = p.filename().string();
84 if (fn.find(libName, 0) == 0) // [plugin-name]
85 {
86 //std::cerr << "An attempt to load same lib twice detected" << std::endl;
87 return true;
88 }
89
90 } while (Module32Next(hModuleSnap, &me32));
91
92 CloseHandle(hModuleSnap);
93#elif __APPLE__
94//
95#else
96 std::pair<bool&, const std::string&> data(alreadyLoaded, libName);
97
98 dl_iterate_phdr([](dl_phdr_info *info, size_t size, void* data) -> int {
99 LIMA_UNUSED(size);
100
101 if (data == nullptr)
102 throw LimaException("Callback passed to dl_iterate_phdr unexpectedly got NULL in \"data\" argument.");
103
104 auto& d = *((std::pair<bool&, const std::string&>*)data);
105
106 //std::cerr << info->dlpi_name << std::endl;
107
108 if (info == nullptr || info->dlpi_name == nullptr)
109 throw LimaException("Callback passed to dl_iterate_phdr unexpectedly got NULL in \"info\" argument.");
110
111 std::string s(info->dlpi_name);
112 if (s.size() == 0)
113 return 0;
114
115 boost::filesystem::path p(info->dlpi_name);
116 std::string fn = p.filename().string();
117 if (fn.find(d.second, 0) == 3) // lib[plugin-name]
118 {
119 d.first = true;
120 return 1;
121 }
122
123 return 0;
124 }, &data);
125#endif
126
127 return alreadyLoaded;
128}
129
130DynamicLibrariesManager::DynamicLibrariesManager() :
131 m_d(new DynamicLibrariesManagerPrivate())
132{
133}
134
138
139bool DynamicLibrariesManager::isLoaded(const std::string& libName)
140{
141 m_d->isSomethingSimilarLoaded(libName);
142 auto it = m_d->m_handles.find(libName);
143 return (it != m_d->m_handles.end());
144}
145
146bool DynamicLibrariesManager::loadLibrary(const std::string& libName)
147{
149 LDEBUG << "DynamicLibrariesManager::loadLibrary() -- libName=" << libName;
150
151 if (m_d->isSomethingSimilarLoaded(libName))
152 {
153 LTRACE << "DynamicLibrariesManager::loadLibrary trying to reload dynamic library " << libName;
154 LTRACE << "DynamicLibrariesManager::loadLibrary this is not an error, silently ignoring.";
155 return true;
156 }
157
158 auto it = m_d->m_handles.find(libName);
159 if (it != m_d->m_handles.end())
160 {
161 LTRACE << "DynamicLibrariesManager::loadLibrary trying to reload dynamic library." << libName;
162 LTRACE << "DynamicLibrariesManager::loadLibrary this is not an error, silently ignoring.";
163 return true;
164 }
165
166 std::shared_ptr< QLibrary > libhandle;
167 std::vector< std::pair< std::string, std::string> > triedPaths;
168 // try supplementary search path
169 for (const auto& path: m_d->m_supplementarySearchPath)
170 {
171 LDEBUG << "Trying supplementary " << (path+"/"+libName).c_str();
172 libhandle = std::make_shared<QLibrary>((path+"/"+libName).c_str());
173
174 libhandle->setLoadHints(QLibrary::ResolveAllSymbolsHint
175 | QLibrary::ExportExternalSymbolsHint);
176 if (libhandle->load())
177 {
178 m_d->m_handles.insert(std::make_pair(libName,libhandle));
179 LDEBUG << "the library " << libName.c_str()
180 << " was loaded from supplementary search path";
181 LDEBUG << "the library fully-qualified name: " << libhandle->fileName();
182 return true;
183 }
184 else
185 {
187 LDEBUG << "DynamicLibrariesManager::loadLibrary() -- "
188 << "Failed to open supplementary lib " << libhandle->errorString();
189 triedPaths.emplace_back( path, libhandle->errorString().toStdString() );
190 libhandle.reset();
191
192 }
193 }
194 // now try system default search path
195 if (!libhandle)
196 {
197 LDEBUG << "Trying " << libName;
198 libhandle = std::make_shared<QLibrary>( libName.c_str() );
199 libhandle->setLoadHints(QLibrary::ResolveAllSymbolsHint
200 | QLibrary::ExportExternalSymbolsHint);
201 if (libhandle->load())
202 {
203 m_d->m_handles.insert(std::make_pair(libName,libhandle));
204 LDEBUG << "the library " << libName
205 << " was loaded from system default search path";
206 LDEBUG << "the library fully-qualified name: " << libhandle->fileName();
207 return true;
208 }
209 else
210 {
212 for (const auto& pathErr: triedPaths)
213 {
214 LERROR << "Failed to load library " << libName << "from " << pathErr.first << " due to " << pathErr.second;
215 }
216 LERROR << "Failed to load library " << libName << "also from system paths";
217 LERROR << "DynamicLibrariesManager::loadLibrary() -- "
218 << "Failed to open system lib " << libhandle->errorString();
219 return false;
220 }
221 }
222 else
223 {
224 m_d->m_handles[libName] = libhandle;
225 LDEBUG << "the library " << libName << " was loaded";
226 return true;
227 }
228}
229
230void DynamicLibrariesManager::addSearchPath(const std::string& searchPath)
231{
232 if( std::find(
233 m_d->m_supplementarySearchPath.begin(),
234 m_d->m_supplementarySearchPath.end(), searchPath)
235 != m_d->m_supplementarySearchPath.end())
236 {
237 return;
238 }
239#ifdef DEBUG_CD
241 LINFO << "adding search path '" << searchPath.c_str() << "'";
242// std::cerr << "adding search path '" <<searchPath.c_str() << "'" << std::endl;
243#endif
244 m_d->m_supplementarySearchPath.push_back(searchPath);
245}
246
248{
249#ifdef DEBUG_CD
251#endif
252
253#ifdef WIN32
254#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
255 auto list = searchPathes.replace("\\","/").split(QRegularExpression("[;]"),
256 QString::SkipEmptyParts);
257#else
258 auto list = searchPathes.replace("\\","/").split(QRegularExpression("[;]"),
259 Qt::SkipEmptyParts);
260#endif
261#else
262#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
263 auto list = searchPathes.replace("\\","/").split(QRegularExpression("[:;]"),
264 QString::SkipEmptyParts);
265#else
266 auto list = searchPathes.replace("\\","/").split(QRegularExpression("[:;]"),
267 Qt::SkipEmptyParts);
268#endif
269#endif
270
271 for(const auto& searchPath: list)
272 {
273#ifdef DEBUG_CD
274 LINFO << "DynamicLibrariesManager::addSearchPathes() adding:" << searchPath;
275#endif
276 this->addSearchPath(searchPath.toStdString());
277 }
278}
279
280
281} // end namespace
282} // end namespace
handle dynamic library opening (wrapper around QLibrary)
#define LTRACE
Definition LimaCommon.h:156
#define LIMA_UNUSED(x)
Definition LimaCommon.h:224
#define LDEBUG
Definition LimaCommon.h:157
#define LINFO
Definition LimaCommon.h:158
#define LERROR
Definition LimaCommon.h:161
#define ABSTRACTFACTORYPATTERNLOGINIT
Definition LimaCommon.h:198
bool loadLibrary(const std::string &libName)
void addSearchPath(const std::string &searchPath)
bool isLoaded(const std::string &libName)
The main LIMA exception class.
Definition LimaCommon.h:262
NAUTITIA.
STL namespace.