0
|
1 |
/****************************************************************************
|
|
2 |
**
|
|
3 |
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
4 |
** All rights reserved.
|
|
5 |
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
6 |
**
|
|
7 |
** This file is part of the QtCore module of the Qt Toolkit.
|
|
8 |
**
|
|
9 |
** $QT_BEGIN_LICENSE:LGPL$
|
|
10 |
** No Commercial Usage
|
|
11 |
** This file contains pre-release code and may not be distributed.
|
|
12 |
** You may use this file in accordance with the terms and conditions
|
|
13 |
** contained in the Technology Preview License Agreement accompanying
|
|
14 |
** this package.
|
|
15 |
**
|
|
16 |
** GNU Lesser General Public License Usage
|
|
17 |
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
18 |
** General Public License version 2.1 as published by the Free Software
|
|
19 |
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
20 |
** packaging of this file. Please review the following information to
|
|
21 |
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
22 |
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
23 |
**
|
|
24 |
** In addition, as a special exception, Nokia gives you certain additional
|
|
25 |
** rights. These rights are described in the Nokia Qt LGPL Exception
|
|
26 |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
27 |
**
|
|
28 |
** If you have questions regarding the use of this file, please contact
|
|
29 |
** Nokia at qt-info@nokia.com.
|
|
30 |
**
|
|
31 |
**
|
|
32 |
**
|
|
33 |
**
|
|
34 |
**
|
|
35 |
**
|
|
36 |
**
|
|
37 |
**
|
|
38 |
** $QT_END_LICENSE$
|
|
39 |
**
|
|
40 |
****************************************************************************/
|
|
41 |
|
|
42 |
#include "qplatformdefs.h"
|
|
43 |
#include "qlibrary.h"
|
|
44 |
|
|
45 |
#ifndef QT_NO_LIBRARY
|
|
46 |
|
|
47 |
#include "qlibrary_p.h"
|
|
48 |
#include <qstringlist.h>
|
|
49 |
#include <qfile.h>
|
|
50 |
#include <qfileinfo.h>
|
|
51 |
#include <qmutex.h>
|
|
52 |
#include <qmap.h>
|
|
53 |
#include <qsettings.h>
|
|
54 |
#include <qdatetime.h>
|
|
55 |
#ifdef Q_OS_MAC
|
|
56 |
# include <private/qcore_mac_p.h>
|
|
57 |
#endif
|
|
58 |
#ifndef NO_ERRNO_H
|
|
59 |
#include <errno.h>
|
|
60 |
#endif // NO_ERROR_H
|
|
61 |
#include <qdebug.h>
|
|
62 |
#include <qvector.h>
|
|
63 |
#include <qdir.h>
|
|
64 |
|
|
65 |
QT_BEGIN_NAMESPACE
|
|
66 |
|
|
67 |
//#define QT_DEBUG_COMPONENT
|
|
68 |
|
|
69 |
#ifdef QT_NO_DEBUG
|
|
70 |
# define QLIBRARY_AS_DEBUG false
|
|
71 |
#else
|
|
72 |
# define QLIBRARY_AS_DEBUG true
|
|
73 |
#endif
|
|
74 |
|
|
75 |
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
|
|
76 |
// We don't use separate debug and release libs on UNIX, so we want
|
|
77 |
// to allow loading plugins, regardless of how they were built.
|
|
78 |
# define QT_NO_DEBUG_PLUGIN_CHECK
|
|
79 |
#endif
|
|
80 |
|
|
81 |
Q_GLOBAL_STATIC(QMutex, qt_library_mutex)
|
|
82 |
|
|
83 |
/*!
|
|
84 |
\class QLibrary
|
|
85 |
\reentrant
|
|
86 |
\brief The QLibrary class loads shared libraries at runtime.
|
|
87 |
|
|
88 |
|
|
89 |
\ingroup plugins
|
|
90 |
|
|
91 |
An instance of a QLibrary object operates on a single shared
|
|
92 |
object file (which we call a "library", but is also known as a
|
|
93 |
"DLL"). A QLibrary provides access to the functionality in the
|
|
94 |
library in a platform independent way. You can either pass a file
|
|
95 |
name in the constructor, or set it explicitly with setFileName().
|
|
96 |
When loading the library, QLibrary searches in all the
|
|
97 |
system-specific library locations (e.g. \c LD_LIBRARY_PATH on
|
|
98 |
Unix), unless the file name has an absolute path. If the file
|
|
99 |
cannot be found, QLibrary tries the name with different
|
|
100 |
platform-specific file suffixes, like ".so" on Unix, ".dylib" on
|
|
101 |
the Mac, or ".dll" on Windows and Symbian. This makes it possible
|
|
102 |
to specify shared libraries that are only identified by their
|
|
103 |
basename (i.e. without their suffix), so the same code will work
|
|
104 |
on different operating systems.
|
|
105 |
|
|
106 |
The most important functions are load() to dynamically load the
|
|
107 |
library file, isLoaded() to check whether loading was successful,
|
|
108 |
and resolve() to resolve a symbol in the library. The resolve()
|
|
109 |
function implicitly tries to load the library if it has not been
|
|
110 |
loaded yet. Multiple instances of QLibrary can be used to access
|
|
111 |
the same physical library. Once loaded, libraries remain in memory
|
|
112 |
until the application terminates. You can attempt to unload a
|
|
113 |
library using unload(), but if other instances of QLibrary are
|
|
114 |
using the same library, the call will fail, and unloading will
|
|
115 |
only happen when every instance has called unload().
|
|
116 |
|
|
117 |
A typical use of QLibrary is to resolve an exported symbol in a
|
|
118 |
library, and to call the C function that this symbol represents.
|
|
119 |
This is called "explicit linking" in contrast to "implicit
|
|
120 |
linking", which is done by the link step in the build process when
|
|
121 |
linking an executable against a library.
|
|
122 |
|
|
123 |
Note: In Symbian resolving symbols using their names is supported
|
|
124 |
only if the library is built as STDDLL. Otherwise ordinals must
|
|
125 |
be used. Also, in Symbian the path of the library is ignored and
|
|
126 |
system default library location is always used.
|
|
127 |
|
|
128 |
The following code snippet loads a library, resolves the symbol
|
|
129 |
"mysymbol", and calls the function if everything succeeded. If
|
|
130 |
something goes wrong, e.g. the library file does not exist or the
|
|
131 |
symbol is not defined, the function pointer will be 0 and won't be
|
|
132 |
called.
|
|
133 |
|
|
134 |
\snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 0
|
|
135 |
|
|
136 |
The symbol must be exported as a C function from the library for
|
|
137 |
resolve() to work. This means that the function must be wrapped in
|
|
138 |
an \c{extern "C"} block if the library is compiled with a C++
|
|
139 |
compiler. On Windows, this also requires the use of a \c dllexport
|
|
140 |
macro; see resolve() for the details of how this is done. For
|
|
141 |
convenience, there is a static resolve() function which you can
|
|
142 |
use if you just want to call a function in a library without
|
|
143 |
explicitly loading the library first:
|
|
144 |
|
|
145 |
\snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 1
|
|
146 |
|
|
147 |
\sa QPluginLoader
|
|
148 |
*/
|
|
149 |
|
|
150 |
/*!
|
|
151 |
\enum QLibrary::LoadHint
|
|
152 |
|
|
153 |
This enum describes the possible hints that can be used to change the way
|
|
154 |
libraries are handled when they are loaded. These values indicate how
|
|
155 |
symbols are resolved when libraries are loaded, and are specified using
|
|
156 |
the setLoadHints() function.
|
|
157 |
|
|
158 |
\value ResolveAllSymbolsHint
|
|
159 |
Causes all symbols in a library to be resolved when it is loaded, not
|
|
160 |
simply when resolve() is called.
|
|
161 |
\value ExportExternalSymbolsHint
|
|
162 |
Exports unresolved and external symbols in the library so that they can be
|
|
163 |
resolved in other dynamically-loaded libraries loaded later.
|
|
164 |
\value LoadArchiveMemberHint
|
|
165 |
Allows the file name of the library to specify a particular object file
|
|
166 |
within an archive file.
|
|
167 |
If this hint is given, the filename of the library consists of
|
|
168 |
a path, which is a reference to an archive file, followed by
|
|
169 |
a reference to the archive member.
|
|
170 |
|
|
171 |
\sa loadHints
|
|
172 |
*/
|
|
173 |
|
|
174 |
|
|
175 |
#ifndef QT_NO_PLUGIN_CHECK
|
|
176 |
struct qt_token_info
|
|
177 |
{
|
|
178 |
qt_token_info(const char *f, const ulong fc)
|
|
179 |
: fields(f), field_count(fc), results(fc), lengths(fc)
|
|
180 |
{
|
|
181 |
results.fill(0);
|
|
182 |
lengths.fill(0);
|
|
183 |
}
|
|
184 |
|
|
185 |
const char *fields;
|
|
186 |
const ulong field_count;
|
|
187 |
|
|
188 |
QVector<const char *> results;
|
|
189 |
QVector<ulong> lengths;
|
|
190 |
};
|
|
191 |
|
|
192 |
/*
|
|
193 |
return values:
|
|
194 |
1 parse ok
|
|
195 |
0 eos
|
|
196 |
-1 parse error
|
|
197 |
*/
|
|
198 |
static int qt_tokenize(const char *s, ulong s_len, ulong *advance,
|
|
199 |
qt_token_info &token_info)
|
|
200 |
{
|
|
201 |
ulong pos = 0, field = 0, fieldlen = 0;
|
|
202 |
char current;
|
|
203 |
int ret = -1;
|
|
204 |
*advance = 0;
|
|
205 |
for (;;) {
|
|
206 |
current = s[pos];
|
|
207 |
|
|
208 |
// next char
|
|
209 |
++pos;
|
|
210 |
++fieldlen;
|
|
211 |
++*advance;
|
|
212 |
|
|
213 |
if (! current || pos == s_len + 1) {
|
|
214 |
// save result
|
|
215 |
token_info.results[(int)field] = s;
|
|
216 |
token_info.lengths[(int)field] = fieldlen - 1;
|
|
217 |
|
|
218 |
// end of string
|
|
219 |
ret = 0;
|
|
220 |
break;
|
|
221 |
}
|
|
222 |
|
|
223 |
if (current == token_info.fields[field]) {
|
|
224 |
// save result
|
|
225 |
token_info.results[(int)field] = s;
|
|
226 |
token_info.lengths[(int)field] = fieldlen - 1;
|
|
227 |
|
|
228 |
// end of field
|
|
229 |
fieldlen = 0;
|
|
230 |
++field;
|
|
231 |
if (field == token_info.field_count - 1) {
|
|
232 |
// parse ok
|
|
233 |
ret = 1;
|
|
234 |
}
|
|
235 |
if (field == token_info.field_count) {
|
|
236 |
// done parsing
|
|
237 |
break;
|
|
238 |
}
|
|
239 |
|
|
240 |
// reset string and its length
|
|
241 |
s = s + pos;
|
|
242 |
s_len -= pos;
|
|
243 |
pos = 0;
|
|
244 |
}
|
|
245 |
}
|
|
246 |
|
|
247 |
return ret;
|
|
248 |
}
|
|
249 |
|
|
250 |
/*
|
|
251 |
returns true if the string s was correctly parsed, false otherwise.
|
|
252 |
*/
|
|
253 |
static bool qt_parse_pattern(const char *s, uint *version, bool *debug, QByteArray *key)
|
|
254 |
{
|
|
255 |
bool ret = true;
|
|
256 |
|
|
257 |
qt_token_info pinfo("=\n", 2);
|
|
258 |
int parse;
|
|
259 |
ulong at = 0, advance, parselen = qstrlen(s);
|
|
260 |
do {
|
|
261 |
parse = qt_tokenize(s + at, parselen, &advance, pinfo);
|
|
262 |
if (parse == -1) {
|
|
263 |
ret = false;
|
|
264 |
break;
|
|
265 |
}
|
|
266 |
|
|
267 |
at += advance;
|
|
268 |
parselen -= advance;
|
|
269 |
|
|
270 |
if (qstrncmp("version", pinfo.results[0], pinfo.lengths[0]) == 0) {
|
|
271 |
// parse version string
|
|
272 |
qt_token_info pinfo2("..-", 3);
|
|
273 |
if (qt_tokenize(pinfo.results[1], pinfo.lengths[1],
|
|
274 |
&advance, pinfo2) != -1) {
|
|
275 |
QByteArray m(pinfo2.results[0], pinfo2.lengths[0]);
|
|
276 |
QByteArray n(pinfo2.results[1], pinfo2.lengths[1]);
|
|
277 |
QByteArray p(pinfo2.results[2], pinfo2.lengths[2]);
|
|
278 |
*version = (m.toUInt() << 16) | (n.toUInt() << 8) | p.toUInt();
|
|
279 |
} else {
|
|
280 |
ret = false;
|
|
281 |
break;
|
|
282 |
}
|
|
283 |
} else if (qstrncmp("debug", pinfo.results[0], pinfo.lengths[0]) == 0) {
|
|
284 |
*debug = qstrncmp("true", pinfo.results[1], pinfo.lengths[1]) == 0;
|
|
285 |
} else if (qstrncmp("buildkey", pinfo.results[0],
|
|
286 |
pinfo.lengths[0]) == 0){
|
|
287 |
// save buildkey
|
|
288 |
*key = QByteArray(pinfo.results[1], pinfo.lengths[1]);
|
|
289 |
}
|
|
290 |
} while (parse == 1 && parselen > 0);
|
|
291 |
|
|
292 |
return ret;
|
|
293 |
}
|
|
294 |
#endif // QT_NO_PLUGIN_CHECK
|
|
295 |
|
|
296 |
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_SYMBIAN) && !defined(QT_NO_PLUGIN_CHECK)
|
|
297 |
|
|
298 |
#if defined(Q_OS_FREEBSD) || defined(Q_OS_LINUX)
|
|
299 |
# define USE_MMAP
|
|
300 |
QT_BEGIN_INCLUDE_NAMESPACE
|
|
301 |
# include <sys/types.h>
|
|
302 |
# include <sys/mman.h>
|
|
303 |
QT_END_INCLUDE_NAMESPACE
|
|
304 |
#endif // Q_OS_FREEBSD || Q_OS_LINUX
|
|
305 |
|
|
306 |
static long qt_find_pattern(const char *s, ulong s_len,
|
|
307 |
const char *pattern, ulong p_len)
|
|
308 |
{
|
|
309 |
/*
|
|
310 |
we search from the end of the file because on the supported
|
|
311 |
systems, the read-only data/text segments are placed at the end
|
|
312 |
of the file. HOWEVER, when building with debugging enabled, all
|
|
313 |
the debug symbols are placed AFTER the data/text segments.
|
|
314 |
|
|
315 |
what does this mean? when building in release mode, the search
|
|
316 |
is fast because the data we are looking for is at the end of the
|
|
317 |
file... when building in debug mode, the search is slower
|
|
318 |
because we have to skip over all the debugging symbols first
|
|
319 |
*/
|
|
320 |
|
|
321 |
if (! s || ! pattern || p_len > s_len) return -1;
|
|
322 |
ulong i, hs = 0, hp = 0, delta = s_len - p_len;
|
|
323 |
|
|
324 |
for (i = 0; i < p_len; ++i) {
|
|
325 |
hs += s[delta + i];
|
|
326 |
hp += pattern[i];
|
|
327 |
}
|
|
328 |
i = delta;
|
|
329 |
for (;;) {
|
|
330 |
if (hs == hp && qstrncmp(s + i, pattern, p_len) == 0)
|
|
331 |
return i;
|
|
332 |
if (i == 0)
|
|
333 |
break;
|
|
334 |
--i;
|
|
335 |
hs -= s[i + p_len];
|
|
336 |
hs += s[i];
|
|
337 |
}
|
|
338 |
|
|
339 |
return -1;
|
|
340 |
}
|
|
341 |
|
|
342 |
/*
|
|
343 |
This opens the specified library, mmaps it into memory, and searches
|
|
344 |
for the QT_PLUGIN_VERIFICATION_DATA. The advantage of this approach is that
|
|
345 |
we can get the verification data without have to actually load the library.
|
|
346 |
This lets us detect mismatches more safely.
|
|
347 |
|
|
348 |
Returns false if version/key information is not present, or if the
|
|
349 |
information could not be read.
|
|
350 |
Returns true if version/key information is present and successfully read.
|
|
351 |
*/
|
|
352 |
static bool qt_unix_query(const QString &library, uint *version, bool *debug, QByteArray *key, QLibraryPrivate *lib = 0)
|
|
353 |
{
|
|
354 |
QFile file(library);
|
|
355 |
if (!file.open(QIODevice::ReadOnly)) {
|
|
356 |
if (lib)
|
|
357 |
lib->errorString = file.errorString();
|
|
358 |
if (qt_debug_component()) {
|
|
359 |
qWarning("%s: %s", (const char*) QFile::encodeName(library),
|
|
360 |
qPrintable(qt_error_string(errno)));
|
|
361 |
}
|
|
362 |
return false;
|
|
363 |
}
|
|
364 |
|
|
365 |
QByteArray data;
|
|
366 |
char *filedata = 0;
|
|
367 |
ulong fdlen = 0;
|
|
368 |
|
|
369 |
# ifdef USE_MMAP
|
|
370 |
char *mapaddr = 0;
|
|
371 |
size_t maplen = file.size();
|
|
372 |
mapaddr = (char *) mmap(mapaddr, maplen, PROT_READ, MAP_PRIVATE, file.handle(), 0);
|
|
373 |
if (mapaddr != MAP_FAILED) {
|
|
374 |
// mmap succeeded
|
|
375 |
filedata = mapaddr;
|
|
376 |
fdlen = maplen;
|
|
377 |
} else {
|
|
378 |
// mmap failed
|
|
379 |
if (qt_debug_component()) {
|
|
380 |
qWarning("mmap: %s", qPrintable(qt_error_string(errno)));
|
|
381 |
}
|
|
382 |
if (lib)
|
|
383 |
lib->errorString = QLibrary::tr("Could not mmap '%1': %2")
|
|
384 |
.arg(library)
|
|
385 |
.arg(qt_error_string());
|
|
386 |
# endif // USE_MMAP
|
|
387 |
// try reading the data into memory instead
|
|
388 |
data = file.readAll();
|
|
389 |
filedata = data.data();
|
|
390 |
fdlen = data.size();
|
|
391 |
# ifdef USE_MMAP
|
|
392 |
}
|
|
393 |
# endif // USE_MMAP
|
|
394 |
|
|
395 |
// verify that the pattern is present in the plugin
|
|
396 |
const char pattern[] = "pattern=QT_PLUGIN_VERIFICATION_DATA";
|
|
397 |
const ulong plen = qstrlen(pattern);
|
|
398 |
long pos = qt_find_pattern(filedata, fdlen, pattern, plen);
|
|
399 |
|
|
400 |
bool ret = false;
|
|
401 |
if (pos >= 0)
|
|
402 |
ret = qt_parse_pattern(filedata + pos, version, debug, key);
|
|
403 |
|
|
404 |
if (!ret && lib)
|
|
405 |
lib->errorString = QLibrary::tr("Plugin verification data mismatch in '%1'").arg(library);
|
|
406 |
# ifdef USE_MMAP
|
|
407 |
if (mapaddr != MAP_FAILED && munmap(mapaddr, maplen) != 0) {
|
|
408 |
if (qt_debug_component())
|
|
409 |
qWarning("munmap: %s", qPrintable(qt_error_string(errno)));
|
|
410 |
if (lib)
|
|
411 |
lib->errorString = QLibrary::tr("Could not unmap '%1': %2")
|
|
412 |
.arg(library)
|
|
413 |
.arg( qt_error_string() );
|
|
414 |
}
|
|
415 |
# endif // USE_MMAP
|
|
416 |
|
|
417 |
file.close();
|
|
418 |
return ret;
|
|
419 |
}
|
|
420 |
|
|
421 |
#endif // Q_OS_UNIX && !Q_OS_MAC && !defined(Q_OS_SYMBIAN) && !defined(QT_NO_PLUGIN_CHECK)
|
|
422 |
|
|
423 |
typedef QMap<QString, QLibraryPrivate*> LibraryMap;
|
|
424 |
|
|
425 |
struct LibraryData {
|
|
426 |
LibraryData() : settings(0) { }
|
|
427 |
~LibraryData() {
|
|
428 |
delete settings;
|
|
429 |
}
|
|
430 |
|
|
431 |
QSettings *settings;
|
|
432 |
LibraryMap libraryMap;
|
|
433 |
};
|
|
434 |
|
|
435 |
Q_GLOBAL_STATIC(LibraryData, libraryData)
|
|
436 |
|
|
437 |
static LibraryMap *libraryMap()
|
|
438 |
{
|
|
439 |
LibraryData *data = libraryData();
|
|
440 |
return data ? &data->libraryMap : 0;
|
|
441 |
}
|
|
442 |
|
|
443 |
QLibraryPrivate::QLibraryPrivate(const QString &canonicalFileName, const QString &version)
|
|
444 |
:pHnd(0), fileName(canonicalFileName), fullVersion(version), instance(0), qt_version(0),
|
|
445 |
libraryRefCount(1), libraryUnloadCount(0), pluginState(MightBeAPlugin)
|
|
446 |
{ libraryMap()->insert(canonicalFileName, this); }
|
|
447 |
|
|
448 |
QLibraryPrivate *QLibraryPrivate::findOrCreate(const QString &fileName, const QString &version)
|
|
449 |
{
|
|
450 |
QMutexLocker locker(qt_library_mutex());
|
|
451 |
if (QLibraryPrivate *lib = libraryMap()->value(fileName)) {
|
|
452 |
lib->libraryRefCount.ref();
|
|
453 |
return lib;
|
|
454 |
}
|
|
455 |
|
|
456 |
return new QLibraryPrivate(fileName, version);
|
|
457 |
}
|
|
458 |
|
|
459 |
QLibraryPrivate::~QLibraryPrivate()
|
|
460 |
{
|
|
461 |
LibraryMap * const map = libraryMap();
|
|
462 |
if (map) {
|
|
463 |
QLibraryPrivate *that = map->take(fileName);
|
|
464 |
Q_ASSERT(this == that);
|
|
465 |
Q_UNUSED(that);
|
|
466 |
}
|
|
467 |
}
|
|
468 |
|
|
469 |
void *QLibraryPrivate::resolve(const char *symbol)
|
|
470 |
{
|
|
471 |
if (!pHnd)
|
|
472 |
return 0;
|
|
473 |
return resolve_sys(symbol);
|
|
474 |
}
|
|
475 |
|
|
476 |
|
|
477 |
bool QLibraryPrivate::load()
|
|
478 |
{
|
|
479 |
libraryUnloadCount.ref();
|
|
480 |
if (pHnd)
|
|
481 |
return true;
|
|
482 |
if (fileName.isEmpty())
|
|
483 |
return false;
|
|
484 |
return load_sys();
|
|
485 |
}
|
|
486 |
|
|
487 |
bool QLibraryPrivate::unload()
|
|
488 |
{
|
|
489 |
if (!pHnd)
|
|
490 |
return false;
|
|
491 |
if (!libraryUnloadCount.deref()) { // only unload if ALL QLibrary instance wanted to
|
|
492 |
if (instance)
|
|
493 |
delete instance();
|
|
494 |
if (unload_sys()) {
|
|
495 |
instance = 0;
|
|
496 |
pHnd = 0;
|
|
497 |
}
|
|
498 |
}
|
|
499 |
|
|
500 |
return (pHnd == 0);
|
|
501 |
}
|
|
502 |
|
|
503 |
void QLibraryPrivate::release()
|
|
504 |
{
|
|
505 |
QMutexLocker locker(qt_library_mutex());
|
|
506 |
if (!libraryRefCount.deref())
|
|
507 |
delete this;
|
|
508 |
}
|
|
509 |
|
|
510 |
bool QLibraryPrivate::loadPlugin()
|
|
511 |
{
|
|
512 |
if (instance) {
|
|
513 |
libraryUnloadCount.ref();
|
|
514 |
return true;
|
|
515 |
}
|
|
516 |
if (load()) {
|
|
517 |
instance = (QtPluginInstanceFunction)resolve("qt_plugin_instance");
|
|
518 |
#if defined(Q_OS_SYMBIAN)
|
|
519 |
if (!instance) {
|
|
520 |
// If resolving with function name failed (i.e. not STDDLL),
|
|
521 |
// try resolving using known ordinal, which for
|
|
522 |
// qt_plugin_instance function is always "2".
|
|
523 |
instance = (QtPluginInstanceFunction)resolve("2");
|
|
524 |
}
|
|
525 |
#endif
|
|
526 |
return instance;
|
|
527 |
}
|
|
528 |
return false;
|
|
529 |
}
|
|
530 |
|
|
531 |
/*!
|
|
532 |
Returns true if \a fileName has a valid suffix for a loadable
|
|
533 |
library; otherwise returns false.
|
|
534 |
|
|
535 |
\table
|
|
536 |
\header \i Platform \i Valid suffixes
|
|
537 |
\row \i Windows \i \c .dll
|
|
538 |
\row \i Unix/Linux \i \c .so
|
|
539 |
\row \i AIX \i \c .a
|
|
540 |
\row \i HP-UX \i \c .sl, \c .so (HP-UXi)
|
|
541 |
\row \i Mac OS X \i \c .dylib, \c .bundle, \c .so
|
|
542 |
\endtable
|
|
543 |
|
|
544 |
Trailing versioning numbers on Unix are ignored.
|
|
545 |
*/
|
|
546 |
bool QLibrary::isLibrary(const QString &fileName)
|
|
547 |
{
|
|
548 |
#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
|
|
549 |
return fileName.endsWith(QLatin1String(".dll"));
|
|
550 |
#elif defined(Q_OS_SYMBIAN)
|
|
551 |
// Plugin stubs are also considered libraries in Symbian.
|
|
552 |
return (fileName.endsWith(QLatin1String(".dll")) ||
|
|
553 |
fileName.endsWith(QLatin1String(".qtplugin")));
|
|
554 |
#else
|
|
555 |
QString completeSuffix = QFileInfo(fileName).completeSuffix();
|
|
556 |
if (completeSuffix.isEmpty())
|
|
557 |
return false;
|
|
558 |
QStringList suffixes = completeSuffix.split(QLatin1Char('.'));
|
|
559 |
# if defined(Q_OS_DARWIN)
|
|
560 |
|
|
561 |
// On Mac, libs look like libmylib.1.0.0.dylib
|
|
562 |
const QString lastSuffix = suffixes.at(suffixes.count() - 1);
|
|
563 |
const QString firstSuffix = suffixes.at(0);
|
|
564 |
|
|
565 |
bool valid = (lastSuffix == QLatin1String("dylib")
|
|
566 |
|| firstSuffix == QLatin1String("so")
|
|
567 |
|| firstSuffix == QLatin1String("bundle"));
|
|
568 |
|
|
569 |
return valid;
|
|
570 |
# else // Generic Unix
|
|
571 |
QStringList validSuffixList;
|
|
572 |
|
|
573 |
# if defined(Q_OS_HPUX)
|
|
574 |
/*
|
|
575 |
See "HP-UX Linker and Libraries User's Guide", section "Link-time Differences between PA-RISC and IPF":
|
|
576 |
"In PA-RISC (PA-32 and PA-64) shared libraries are suffixed with .sl. In IPF (32-bit and 64-bit),
|
|
577 |
the shared libraries are suffixed with .so. For compatibility, the IPF linker also supports the .sl suffix."
|
|
578 |
*/
|
|
579 |
validSuffixList << QLatin1String("sl");
|
|
580 |
# if defined __ia64
|
|
581 |
validSuffixList << QLatin1String("so");
|
|
582 |
# endif
|
|
583 |
# elif defined(Q_OS_AIX)
|
|
584 |
validSuffixList << QLatin1String("a") << QLatin1String("so");
|
|
585 |
# elif defined(Q_OS_UNIX)
|
|
586 |
validSuffixList << QLatin1String("so");
|
|
587 |
# endif
|
|
588 |
|
|
589 |
// Examples of valid library names:
|
|
590 |
// libfoo.so
|
|
591 |
// libfoo.so.0
|
|
592 |
// libfoo.so.0.3
|
|
593 |
// libfoo-0.3.so
|
|
594 |
// libfoo-0.3.so.0.3.0
|
|
595 |
|
|
596 |
int suffix;
|
|
597 |
int suffixPos = -1;
|
|
598 |
for (suffix = 0; suffix < validSuffixList.count() && suffixPos == -1; ++suffix)
|
|
599 |
suffixPos = suffixes.indexOf(validSuffixList.at(suffix));
|
|
600 |
|
|
601 |
bool valid = suffixPos != -1;
|
|
602 |
for (int i = suffixPos + 1; i < suffixes.count() && valid; ++i)
|
|
603 |
if (i != suffixPos)
|
|
604 |
suffixes.at(i).toInt(&valid);
|
|
605 |
return valid;
|
|
606 |
# endif
|
|
607 |
#endif
|
|
608 |
|
|
609 |
}
|
|
610 |
|
|
611 |
bool QLibraryPrivate::isPlugin(QSettings *settings)
|
|
612 |
{
|
|
613 |
errorString.clear();
|
|
614 |
if (pluginState != MightBeAPlugin)
|
|
615 |
return pluginState == IsAPlugin;
|
|
616 |
|
|
617 |
#ifndef QT_NO_PLUGIN_CHECK
|
|
618 |
bool debug = !QLIBRARY_AS_DEBUG;
|
|
619 |
QByteArray key;
|
|
620 |
bool success = false;
|
|
621 |
|
|
622 |
QFileInfo fileinfo(fileName);
|
|
623 |
|
|
624 |
#ifndef QT_NO_DATESTRING
|
|
625 |
lastModified = fileinfo.lastModified().toString(Qt::ISODate);
|
|
626 |
#endif
|
|
627 |
QString regkey = QString::fromLatin1("Qt Plugin Cache %1.%2.%3/%4")
|
|
628 |
.arg((QT_VERSION & 0xff0000) >> 16)
|
|
629 |
.arg((QT_VERSION & 0xff00) >> 8)
|
|
630 |
.arg(QLIBRARY_AS_DEBUG ? QLatin1String("debug") : QLatin1String("false"))
|
|
631 |
.arg(fileName);
|
|
632 |
QStringList reg;
|
|
633 |
#ifndef QT_NO_SETTINGS
|
|
634 |
if (!settings) {
|
|
635 |
settings = libraryData()->settings;
|
|
636 |
if (!settings) {
|
|
637 |
settings = new QSettings(QSettings::UserScope, QLatin1String("Trolltech"));
|
|
638 |
libraryData()->settings = settings;
|
|
639 |
}
|
|
640 |
}
|
|
641 |
reg = settings->value(regkey).toStringList();
|
|
642 |
#endif
|
|
643 |
if (reg.count() == 4 && lastModified == reg.at(3)) {
|
|
644 |
qt_version = reg.at(0).toUInt(0, 16);
|
|
645 |
debug = bool(reg.at(1).toInt());
|
|
646 |
key = reg.at(2).toLatin1();
|
|
647 |
success = qt_version != 0;
|
|
648 |
} else {
|
|
649 |
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_SYMBIAN)
|
|
650 |
if (!pHnd) {
|
|
651 |
// use unix shortcut to avoid loading the library
|
|
652 |
success = qt_unix_query(fileName, &qt_version, &debug, &key, this);
|
|
653 |
} else
|
|
654 |
#endif
|
|
655 |
{
|
|
656 |
bool temporary_load = false;
|
|
657 |
#ifdef Q_OS_WIN
|
|
658 |
HMODULE hTempModule = 0;
|
|
659 |
#endif
|
|
660 |
if (!pHnd) {
|
|
661 |
#ifdef Q_OS_WIN
|
|
662 |
hTempModule = ::LoadLibraryEx((wchar_t*)QDir::toNativeSeparators(fileName).utf16(), 0, DONT_RESOLVE_DLL_REFERENCES);
|
|
663 |
#else
|
|
664 |
# if defined(Q_OS_SYMBIAN)
|
|
665 |
//Guard against accidentally trying to load non-plugin libraries by making sure the stub exists
|
|
666 |
if (fileinfo.exists())
|
|
667 |
# endif
|
|
668 |
temporary_load = load_sys();
|
|
669 |
#endif
|
|
670 |
}
|
|
671 |
# ifdef Q_CC_BOR
|
|
672 |
typedef const char * __stdcall (*QtPluginQueryVerificationDataFunction)();
|
|
673 |
# else
|
|
674 |
typedef const char * (*QtPluginQueryVerificationDataFunction)();
|
|
675 |
# endif
|
|
676 |
#ifdef Q_OS_WIN
|
|
677 |
QtPluginQueryVerificationDataFunction qtPluginQueryVerificationDataFunction = hTempModule
|
|
678 |
? (QtPluginQueryVerificationDataFunction)
|
|
679 |
#ifdef Q_OS_WINCE
|
|
680 |
::GetProcAddress(hTempModule, L"qt_plugin_query_verification_data")
|
|
681 |
#else
|
|
682 |
::GetProcAddress(hTempModule, "qt_plugin_query_verification_data")
|
|
683 |
#endif
|
|
684 |
: (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
|
|
685 |
#else
|
|
686 |
QtPluginQueryVerificationDataFunction qtPluginQueryVerificationDataFunction = NULL;
|
|
687 |
# if defined(Q_OS_SYMBIAN)
|
|
688 |
if (temporary_load) {
|
|
689 |
qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
|
|
690 |
// If resolving with function name failed (i.e. not STDDLL), try resolving using known ordinal
|
|
691 |
if (!qtPluginQueryVerificationDataFunction)
|
|
692 |
qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("1");
|
|
693 |
}
|
|
694 |
# else
|
|
695 |
qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
|
|
696 |
# endif
|
|
697 |
#endif
|
|
698 |
|
|
699 |
if (!qtPluginQueryVerificationDataFunction
|
|
700 |
|| !qt_parse_pattern(qtPluginQueryVerificationDataFunction(), &qt_version, &debug, &key)) {
|
|
701 |
qt_version = 0;
|
|
702 |
key = "unknown";
|
|
703 |
if (temporary_load)
|
|
704 |
unload_sys();
|
|
705 |
} else {
|
|
706 |
success = true;
|
|
707 |
}
|
|
708 |
#ifdef Q_OS_WIN
|
|
709 |
if (hTempModule) {
|
|
710 |
BOOL ok = ::FreeLibrary(hTempModule);
|
|
711 |
if (ok) {
|
|
712 |
hTempModule = 0;
|
|
713 |
}
|
|
714 |
|
|
715 |
}
|
|
716 |
#endif
|
|
717 |
}
|
|
718 |
|
|
719 |
// Qt 4.5 compatibility: stl doesn't affect binary compatibility
|
|
720 |
key.replace(" no-stl", "");
|
|
721 |
|
|
722 |
#ifndef QT_NO_SETTINGS
|
|
723 |
QStringList queried;
|
|
724 |
queried << QString::number(qt_version,16)
|
|
725 |
<< QString::number((int)debug)
|
|
726 |
<< QLatin1String(key)
|
|
727 |
<< lastModified;
|
|
728 |
settings->setValue(regkey, queried);
|
|
729 |
#endif
|
|
730 |
}
|
|
731 |
|
|
732 |
if (!success) {
|
|
733 |
if (errorString.isEmpty()){
|
|
734 |
if (fileName.isEmpty())
|
|
735 |
errorString = QLibrary::tr("The shared library was not found.");
|
|
736 |
else
|
|
737 |
errorString = QLibrary::tr("The file '%1' is not a valid Qt plugin.").arg(fileName);
|
|
738 |
}
|
|
739 |
return false;
|
|
740 |
}
|
|
741 |
|
|
742 |
pluginState = IsNotAPlugin; // be pessimistic
|
|
743 |
|
|
744 |
if ((qt_version > QT_VERSION) || ((QT_VERSION & 0xff0000) > (qt_version & 0xff0000))) {
|
|
745 |
if (qt_debug_component()) {
|
|
746 |
qWarning("In %s:\n"
|
|
747 |
" Plugin uses incompatible Qt library (%d.%d.%d) [%s]",
|
|
748 |
(const char*) QFile::encodeName(fileName),
|
|
749 |
(qt_version&0xff0000) >> 16, (qt_version&0xff00) >> 8, qt_version&0xff,
|
|
750 |
debug ? "debug" : "release");
|
|
751 |
}
|
|
752 |
errorString = QLibrary::tr("The plugin '%1' uses incompatible Qt library. (%2.%3.%4) [%5]")
|
|
753 |
.arg(fileName)
|
|
754 |
.arg((qt_version&0xff0000) >> 16)
|
|
755 |
.arg((qt_version&0xff00) >> 8)
|
|
756 |
.arg(qt_version&0xff)
|
|
757 |
.arg(debug ? QLatin1String("debug") : QLatin1String("release"));
|
|
758 |
} else if (key != QT_BUILD_KEY
|
|
759 |
#ifdef QT_BUILD_KEY_COMPAT
|
|
760 |
// be sure to load plugins using an older but compatible build key
|
|
761 |
&& key != QT_BUILD_KEY_COMPAT
|
|
762 |
#endif
|
|
763 |
) {
|
|
764 |
if (qt_debug_component()) {
|
|
765 |
qWarning("In %s:\n"
|
|
766 |
" Plugin uses incompatible Qt library\n"
|
|
767 |
" expected build key \"%s\", got \"%s\"",
|
|
768 |
(const char*) QFile::encodeName(fileName),
|
|
769 |
QT_BUILD_KEY,
|
|
770 |
key.isEmpty() ? "<null>" : (const char *) key);
|
|
771 |
}
|
|
772 |
errorString = QLibrary::tr("The plugin '%1' uses incompatible Qt library."
|
|
773 |
" Expected build key \"%2\", got \"%3\"")
|
|
774 |
.arg(fileName)
|
|
775 |
.arg(QLatin1String(QT_BUILD_KEY))
|
|
776 |
.arg(key.isEmpty() ? QLatin1String("<null>") : QLatin1String((const char *) key));
|
|
777 |
#ifndef QT_NO_DEBUG_PLUGIN_CHECK
|
|
778 |
} else if(debug != QLIBRARY_AS_DEBUG) {
|
|
779 |
//don't issue a qWarning since we will hopefully find a non-debug? --Sam
|
|
780 |
errorString = QLibrary::tr("The plugin '%1' uses incompatible Qt library."
|
|
781 |
" (Cannot mix debug and release libraries.)").arg(fileName);
|
|
782 |
#endif
|
|
783 |
} else {
|
|
784 |
pluginState = IsAPlugin;
|
|
785 |
}
|
|
786 |
|
|
787 |
return pluginState == IsAPlugin;
|
|
788 |
#else
|
|
789 |
Q_UNUSED(settings);
|
|
790 |
return pluginState == MightBeAPlugin;
|
|
791 |
#endif
|
|
792 |
}
|
|
793 |
|
|
794 |
/*!
|
|
795 |
Loads the library and returns true if the library was loaded
|
|
796 |
successfully; otherwise returns false. Since resolve() always
|
|
797 |
calls this function before resolving any symbols it is not
|
|
798 |
necessary to call it explicitly. In some situations you might want
|
|
799 |
the library loaded in advance, in which case you would use this
|
|
800 |
function.
|
|
801 |
|
|
802 |
\sa unload()
|
|
803 |
*/
|
|
804 |
bool QLibrary::load()
|
|
805 |
{
|
|
806 |
if (!d)
|
|
807 |
return false;
|
|
808 |
if (did_load)
|
|
809 |
return d->pHnd;
|
|
810 |
did_load = true;
|
|
811 |
return d->load();
|
|
812 |
}
|
|
813 |
|
|
814 |
/*!
|
|
815 |
Unloads the library and returns true if the library could be
|
|
816 |
unloaded; otherwise returns false.
|
|
817 |
|
|
818 |
This happens automatically on application termination, so you
|
|
819 |
shouldn't normally need to call this function.
|
|
820 |
|
|
821 |
If other instances of QLibrary are using the same library, the
|
|
822 |
call will fail, and unloading will only happen when every instance
|
|
823 |
has called unload().
|
|
824 |
|
|
825 |
Note that on Mac OS X 10.3 (Panther), dynamic libraries cannot be unloaded.
|
|
826 |
|
|
827 |
\sa resolve(), load()
|
|
828 |
*/
|
|
829 |
bool QLibrary::unload()
|
|
830 |
{
|
|
831 |
if (did_load) {
|
|
832 |
did_load = false;
|
|
833 |
return d->unload();
|
|
834 |
}
|
|
835 |
return false;
|
|
836 |
}
|
|
837 |
|
|
838 |
/*!
|
|
839 |
Returns true if the library is loaded; otherwise returns false.
|
|
840 |
|
|
841 |
\sa load()
|
|
842 |
*/
|
|
843 |
bool QLibrary::isLoaded() const
|
|
844 |
{
|
|
845 |
return d && d->pHnd;
|
|
846 |
}
|
|
847 |
|
|
848 |
|
|
849 |
/*!
|
|
850 |
Constructs a library with the given \a parent.
|
|
851 |
*/
|
|
852 |
QLibrary::QLibrary(QObject *parent)
|
|
853 |
:QObject(parent), d(0), did_load(false)
|
|
854 |
{
|
|
855 |
}
|
|
856 |
|
|
857 |
|
|
858 |
/*!
|
|
859 |
Constructs a library object with the given \a parent that will
|
|
860 |
load the library specified by \a fileName.
|
|
861 |
|
|
862 |
We recommend omitting the file's suffix in \a fileName, since
|
|
863 |
QLibrary will automatically look for the file with the appropriate
|
|
864 |
suffix in accordance with the platform, e.g. ".so" on Unix,
|
|
865 |
".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.)
|
|
866 |
|
|
867 |
Note: In Symbian the path portion of the \a fileName is ignored.
|
|
868 |
*/
|
|
869 |
QLibrary::QLibrary(const QString& fileName, QObject *parent)
|
|
870 |
:QObject(parent), d(0), did_load(false)
|
|
871 |
{
|
|
872 |
setFileName(fileName);
|
|
873 |
}
|
|
874 |
|
|
875 |
|
|
876 |
/*!
|
|
877 |
Constructs a library object with the given \a parent that will
|
|
878 |
load the library specified by \a fileName and major version number \a verNum.
|
|
879 |
Currently, the version number is ignored on Windows and Symbian.
|
|
880 |
|
|
881 |
We recommend omitting the file's suffix in \a fileName, since
|
|
882 |
QLibrary will automatically look for the file with the appropriate
|
|
883 |
suffix in accordance with the platform, e.g. ".so" on Unix,
|
|
884 |
".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.)
|
|
885 |
|
|
886 |
Note: In Symbian the path portion of the \a fileName is ignored.
|
|
887 |
*/
|
|
888 |
QLibrary::QLibrary(const QString& fileName, int verNum, QObject *parent)
|
|
889 |
:QObject(parent), d(0), did_load(false)
|
|
890 |
{
|
|
891 |
setFileNameAndVersion(fileName, verNum);
|
|
892 |
}
|
|
893 |
|
|
894 |
/*!
|
|
895 |
Constructs a library object with the given \a parent that will
|
|
896 |
load the library specified by \a fileName and full version number \a version.
|
|
897 |
Currently, the version number is ignored on Windows and Symbian.
|
|
898 |
|
|
899 |
We recommend omitting the file's suffix in \a fileName, since
|
|
900 |
QLibrary will automatically look for the file with the appropriate
|
|
901 |
suffix in accordance with the platform, e.g. ".so" on Unix,
|
|
902 |
".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.)
|
|
903 |
|
|
904 |
Note: In Symbian the path portion of the \a fileName is ignored.
|
|
905 |
*/
|
|
906 |
QLibrary::QLibrary(const QString& fileName, const QString &version, QObject *parent)
|
|
907 |
:QObject(parent), d(0), did_load(false)
|
|
908 |
{
|
|
909 |
setFileNameAndVersion(fileName, version);
|
|
910 |
}
|
|
911 |
|
|
912 |
/*!
|
|
913 |
Destroys the QLibrary object.
|
|
914 |
|
|
915 |
Unless unload() was called explicitly, the library stays in memory
|
|
916 |
until the application terminates.
|
|
917 |
|
|
918 |
\sa isLoaded(), unload()
|
|
919 |
*/
|
|
920 |
QLibrary::~QLibrary()
|
|
921 |
{
|
|
922 |
if (d)
|
|
923 |
d->release();
|
|
924 |
}
|
|
925 |
|
|
926 |
|
|
927 |
/*!
|
|
928 |
\property QLibrary::fileName
|
|
929 |
\brief the file name of the library
|
|
930 |
|
|
931 |
We recommend omitting the file's suffix in the file name, since
|
|
932 |
QLibrary will automatically look for the file with the appropriate
|
|
933 |
suffix (see isLibrary()).
|
|
934 |
|
|
935 |
When loading the library, QLibrary searches in all system-specific
|
|
936 |
library locations (e.g. \c LD_LIBRARY_PATH on Unix), unless the
|
|
937 |
file name has an absolute path. After loading the library
|
|
938 |
successfully, fileName() returns the fully-qualified file name of
|
|
939 |
the library, including the full path to the library if one was given
|
|
940 |
in the constructor or passed to setFileName().
|
|
941 |
|
|
942 |
For example, after successfully loading the "GL" library on Unix
|
|
943 |
platforms, fileName() will return "libGL.so". If the file name was
|
|
944 |
originally passed as "/usr/lib/libGL", fileName() will return
|
|
945 |
"/usr/lib/libGL.so".
|
|
946 |
|
|
947 |
Note: In Symbian the path portion of the \a fileName is ignored.
|
|
948 |
*/
|
|
949 |
|
|
950 |
void QLibrary::setFileName(const QString &fileName)
|
|
951 |
{
|
|
952 |
QLibrary::LoadHints lh;
|
|
953 |
if (d) {
|
|
954 |
lh = d->loadHints;
|
|
955 |
d->release();
|
|
956 |
d = 0;
|
|
957 |
did_load = false;
|
|
958 |
}
|
|
959 |
d = QLibraryPrivate::findOrCreate(fileName);
|
|
960 |
d->loadHints = lh;
|
|
961 |
}
|
|
962 |
|
|
963 |
QString QLibrary::fileName() const
|
|
964 |
{
|
|
965 |
if (d)
|
|
966 |
return d->qualifiedFileName.isEmpty() ? d->fileName : d->qualifiedFileName;
|
|
967 |
return QString();
|
|
968 |
}
|
|
969 |
|
|
970 |
/*!
|
|
971 |
\fn void QLibrary::setFileNameAndVersion(const QString &fileName, int versionNumber)
|
|
972 |
|
|
973 |
Sets the fileName property and major version number to \a fileName
|
|
974 |
and \a versionNumber respectively.
|
|
975 |
The \a versionNumber is ignored on Windows and Symbian.
|
|
976 |
|
|
977 |
Note: In Symbian the path portion of the \a fileName is ignored.
|
|
978 |
|
|
979 |
\sa setFileName()
|
|
980 |
*/
|
|
981 |
void QLibrary::setFileNameAndVersion(const QString &fileName, int verNum)
|
|
982 |
{
|
|
983 |
QLibrary::LoadHints lh;
|
|
984 |
if (d) {
|
|
985 |
lh = d->loadHints;
|
|
986 |
d->release();
|
|
987 |
d = 0;
|
|
988 |
did_load = false;
|
|
989 |
}
|
|
990 |
d = QLibraryPrivate::findOrCreate(fileName, verNum >= 0 ? QString::number(verNum) : QString());
|
|
991 |
d->loadHints = lh;
|
|
992 |
}
|
|
993 |
|
|
994 |
/*!
|
|
995 |
\since 4.4
|
|
996 |
|
|
997 |
Sets the fileName property and full version number to \a fileName
|
|
998 |
and \a version respectively.
|
|
999 |
The \a version parameter is ignored on Windows and Symbian.
|
|
1000 |
|
|
1001 |
Note: In Symbian the path portion of the \a fileName is ignored.
|
|
1002 |
|
|
1003 |
\sa setFileName()
|
|
1004 |
*/
|
|
1005 |
void QLibrary::setFileNameAndVersion(const QString &fileName, const QString &version)
|
|
1006 |
{
|
|
1007 |
QLibrary::LoadHints lh;
|
|
1008 |
if (d) {
|
|
1009 |
lh = d->loadHints;
|
|
1010 |
d->release();
|
|
1011 |
d = 0;
|
|
1012 |
did_load = false;
|
|
1013 |
}
|
|
1014 |
d = QLibraryPrivate::findOrCreate(fileName, version);
|
|
1015 |
d->loadHints = lh;
|
|
1016 |
}
|
|
1017 |
|
|
1018 |
/*!
|
|
1019 |
Returns the address of the exported symbol \a symbol. The library is
|
|
1020 |
loaded if necessary. The function returns 0 if the symbol could
|
|
1021 |
not be resolved or if the library could not be loaded.
|
|
1022 |
|
|
1023 |
Example:
|
|
1024 |
\snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 2
|
|
1025 |
|
|
1026 |
The symbol must be exported as a C function from the library. This
|
|
1027 |
means that the function must be wrapped in an \c{extern "C"} if
|
|
1028 |
the library is compiled with a C++ compiler. On Windows you must
|
|
1029 |
also explicitly export the function from the DLL using the
|
|
1030 |
\c{__declspec(dllexport)} compiler directive, for example:
|
|
1031 |
|
|
1032 |
\snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 3
|
|
1033 |
|
|
1034 |
with \c MY_EXPORT defined as
|
|
1035 |
|
|
1036 |
\snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 4
|
|
1037 |
|
|
1038 |
Note: In Symbian resolving with symbol names works only if the loaded
|
|
1039 |
library was built as STDDLL. Otherwise, the ordinals must be used.
|
|
1040 |
*/
|
|
1041 |
void *QLibrary::resolve(const char *symbol)
|
|
1042 |
{
|
|
1043 |
if (!load())
|
|
1044 |
return 0;
|
|
1045 |
return d->resolve(symbol);
|
|
1046 |
}
|
|
1047 |
|
|
1048 |
/*!
|
|
1049 |
\overload
|
|
1050 |
|
|
1051 |
Loads the library \a fileName and returns the address of the
|
|
1052 |
exported symbol \a symbol. Note that \a fileName should not
|
|
1053 |
include the platform-specific file suffix; (see \l{fileName}). The
|
|
1054 |
library remains loaded until the application exits.
|
|
1055 |
|
|
1056 |
The function returns 0 if the symbol could not be resolved or if
|
|
1057 |
the library could not be loaded.
|
|
1058 |
|
|
1059 |
Note: In Symbian resolving with symbol names works only if the loaded
|
|
1060 |
library was built as STDDLL. Otherwise, the ordinals must be used.
|
|
1061 |
|
|
1062 |
\sa resolve()
|
|
1063 |
*/
|
|
1064 |
void *QLibrary::resolve(const QString &fileName, const char *symbol)
|
|
1065 |
{
|
|
1066 |
QLibrary library(fileName);
|
|
1067 |
return library.resolve(symbol);
|
|
1068 |
}
|
|
1069 |
|
|
1070 |
/*!
|
|
1071 |
\overload
|
|
1072 |
|
|
1073 |
Loads the library \a fileName with major version number \a verNum and
|
|
1074 |
returns the address of the exported symbol \a symbol.
|
|
1075 |
Note that \a fileName should not include the platform-specific file suffix;
|
|
1076 |
(see \l{fileName}). The library remains loaded until the application exits.
|
|
1077 |
\a verNum is ignored on Windows.
|
|
1078 |
|
|
1079 |
The function returns 0 if the symbol could not be resolved or if
|
|
1080 |
the library could not be loaded.
|
|
1081 |
|
|
1082 |
Note: In Symbian resolving with symbol names works only if the loaded
|
|
1083 |
library was built as STDDLL. Otherwise, the ordinals must be used.
|
|
1084 |
|
|
1085 |
\sa resolve()
|
|
1086 |
*/
|
|
1087 |
void *QLibrary::resolve(const QString &fileName, int verNum, const char *symbol)
|
|
1088 |
{
|
|
1089 |
QLibrary library(fileName, verNum);
|
|
1090 |
return library.resolve(symbol);
|
|
1091 |
}
|
|
1092 |
|
|
1093 |
/*!
|
|
1094 |
\overload
|
|
1095 |
\since 4.4
|
|
1096 |
|
|
1097 |
Loads the library \a fileName with full version number \a version and
|
|
1098 |
returns the address of the exported symbol \a symbol.
|
|
1099 |
Note that \a fileName should not include the platform-specific file suffix;
|
|
1100 |
(see \l{fileName}). The library remains loaded until the application exits.
|
|
1101 |
\a version is ignored on Windows.
|
|
1102 |
|
|
1103 |
The function returns 0 if the symbol could not be resolved or if
|
|
1104 |
the library could not be loaded.
|
|
1105 |
|
|
1106 |
Note: In Symbian resolving with symbol names works only if the loaded
|
|
1107 |
library was built as STDDLL. Otherwise, the ordinals must be used.
|
|
1108 |
|
|
1109 |
\sa resolve()
|
|
1110 |
*/
|
|
1111 |
void *QLibrary::resolve(const QString &fileName, const QString &version, const char *symbol)
|
|
1112 |
{
|
|
1113 |
QLibrary library(fileName, version);
|
|
1114 |
return library.resolve(symbol);
|
|
1115 |
}
|
|
1116 |
|
|
1117 |
/*!
|
|
1118 |
\fn QString QLibrary::library() const
|
|
1119 |
|
|
1120 |
Use fileName() instead.
|
|
1121 |
*/
|
|
1122 |
|
|
1123 |
/*!
|
|
1124 |
\fn void QLibrary::setAutoUnload( bool b )
|
|
1125 |
|
|
1126 |
Use load(), isLoaded(), and unload() as necessary instead.
|
|
1127 |
*/
|
|
1128 |
|
|
1129 |
/*!
|
|
1130 |
\since 4.2
|
|
1131 |
|
|
1132 |
Returns a text string with the description of the last error that occurred.
|
|
1133 |
Currently, errorString will only be set if load(), unload() or resolve() for some reason fails.
|
|
1134 |
*/
|
|
1135 |
QString QLibrary::errorString() const
|
|
1136 |
{
|
|
1137 |
return (!d || d->errorString.isEmpty()) ? tr("Unknown error") : d->errorString;
|
|
1138 |
}
|
|
1139 |
|
|
1140 |
/*!
|
|
1141 |
\property QLibrary::loadHints
|
|
1142 |
\brief Give the load() function some hints on how it should behave.
|
|
1143 |
|
|
1144 |
You can give some hints on how the symbols are resolved. Usually,
|
|
1145 |
the symbols are not resolved at load time, but resolved lazily,
|
|
1146 |
(that is, when resolve() is called). If you set the loadHint to
|
|
1147 |
ResolveAllSymbolsHint, then all symbols will be resolved at load time
|
|
1148 |
if the platform supports it.
|
|
1149 |
|
|
1150 |
Setting ExportExternalSymbolsHint will make the external symbols in the
|
|
1151 |
library available for resolution in subsequent loaded libraries.
|
|
1152 |
|
|
1153 |
If LoadArchiveMemberHint is set, the file name
|
|
1154 |
is composed of two components: A path which is a reference to an
|
|
1155 |
archive file followed by the second component which is the reference to
|
|
1156 |
the archive member. For instance, the fileName \c libGL.a(shr_64.o) will refer
|
|
1157 |
to the library \c shr_64.o in the archive file named \c libGL.a. This
|
|
1158 |
is only supported on the AIX platform.
|
|
1159 |
|
|
1160 |
The interpretation of the load hints is platform dependent, and if
|
|
1161 |
you use it you are probably making some assumptions on which platform
|
|
1162 |
you are compiling for, so use them only if you understand the consequences
|
|
1163 |
of them.
|
|
1164 |
|
|
1165 |
By default, none of these flags are set, so libraries will be loaded with
|
|
1166 |
lazy symbol resolution, and will not export external symbols for resolution
|
|
1167 |
in other dynamically-loaded libraries.
|
|
1168 |
*/
|
|
1169 |
void QLibrary::setLoadHints(LoadHints hints)
|
|
1170 |
{
|
|
1171 |
if (!d) {
|
|
1172 |
d = QLibraryPrivate::findOrCreate(QString()); // ugly, but we need a d-ptr
|
|
1173 |
d->errorString.clear();
|
|
1174 |
}
|
|
1175 |
d->loadHints = hints;
|
|
1176 |
}
|
|
1177 |
|
|
1178 |
QLibrary::LoadHints QLibrary::loadHints() const
|
|
1179 |
{
|
|
1180 |
return d ? d->loadHints : (QLibrary::LoadHints)0;
|
|
1181 |
}
|
|
1182 |
|
|
1183 |
/* Internal, for debugging */
|
|
1184 |
bool qt_debug_component()
|
|
1185 |
{
|
|
1186 |
#if defined(QT_DEBUG_COMPONENT)
|
|
1187 |
return true; //compatibility?
|
|
1188 |
#else
|
|
1189 |
static int debug_env = -1;
|
|
1190 |
if (debug_env == -1)
|
|
1191 |
debug_env = QT_PREPEND_NAMESPACE(qgetenv)("QT_DEBUG_PLUGINS").toInt();
|
|
1192 |
|
|
1193 |
return debug_env != 0;
|
|
1194 |
#endif
|
|
1195 |
}
|
|
1196 |
|
|
1197 |
QT_END_NAMESPACE
|
|
1198 |
|
|
1199 |
#endif // QT_NO_LIBRARY
|