source: trunk/src/corelib/plugin/qlibrary.cpp@ 1151

Last change on this file since 1151 was 1151, checked in by Dmitry A. Kuminov, 12 years ago

core: Don't hide plugin load error message by the resolve entry failure.

When the DLL can't be loaded, it makes no sense to try to resolve any entry points.

File size: 38.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
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
65QT_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
81Q_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
176struct 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*/
198static 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*/
253static 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
298static long qt_find_pattern(const char *s, ulong s_len,
299 const char *pattern, ulong p_len)
300{
301 /*
302 we search from the end of the file because on the supported
303 systems, the read-only data/text segments are placed at the end
304 of the file. HOWEVER, when building with debugging enabled, all
305 the debug symbols are placed AFTER the data/text segments.
306
307 what does this mean? when building in release mode, the search
308 is fast because the data we are looking for is at the end of the
309 file... when building in debug mode, the search is slower
310 because we have to skip over all the debugging symbols first
311 */
312
313 if (! s || ! pattern || p_len > s_len) return -1;
314 ulong i, hs = 0, hp = 0, delta = s_len - p_len;
315
316 for (i = 0; i < p_len; ++i) {
317 hs += s[delta + i];
318 hp += pattern[i];
319 }
320 i = delta;
321 for (;;) {
322 if (hs == hp && qstrncmp(s + i, pattern, p_len) == 0)
323 return i;
324 if (i == 0)
325 break;
326 --i;
327 hs -= s[i + p_len];
328 hs += s[i];
329 }
330
331 return -1;
332}
333
334/*
335 This opens the specified library, mmaps it into memory, and searches
336 for the QT_PLUGIN_VERIFICATION_DATA. The advantage of this approach is that
337 we can get the verification data without have to actually load the library.
338 This lets us detect mismatches more safely.
339
340 Returns false if version/key information is not present, or if the
341 information could not be read.
342 Returns true if version/key information is present and successfully read.
343*/
344static bool qt_unix_query(const QString &library, uint *version, bool *debug, QByteArray *key, QLibraryPrivate *lib = 0)
345{
346 QFile file(library);
347 if (!file.open(QIODevice::ReadOnly)) {
348 if (lib)
349 lib->errorString = file.errorString();
350 if (qt_debug_component()) {
351 qWarning("%s: %s", (const char*) QFile::encodeName(library),
352 qPrintable(qt_error_string(errno)));
353 }
354 return false;
355 }
356
357 QByteArray data;
358 const char *filedata = 0;
359 ulong fdlen = file.size();
360 filedata = (char *) file.map(0, fdlen);
361 if (filedata == 0) {
362 // try reading the data into memory instead
363 data = file.readAll();
364 filedata = data.constData();
365 fdlen = data.size();
366 }
367
368 // verify that the pattern is present in the plugin
369 const char pattern[] = "pattern=QT_PLUGIN_VERIFICATION_DATA";
370 const ulong plen = qstrlen(pattern);
371 long pos = qt_find_pattern(filedata, fdlen, pattern, plen);
372
373 bool ret = false;
374 if (pos >= 0)
375 ret = qt_parse_pattern(filedata + pos, version, debug, key);
376
377 if (!ret && lib)
378 lib->errorString = QLibrary::tr("Plugin verification data mismatch in '%1'").arg(library);
379 file.close();
380 return ret;
381}
382
383#endif // Q_OS_UNIX && !Q_OS_MAC && !defined(Q_OS_SYMBIAN) && !defined(QT_NO_PLUGIN_CHECK)
384
385typedef QMap<QString, QLibraryPrivate*> LibraryMap;
386
387struct LibraryData {
388 LibraryData() : settings(0) { }
389 ~LibraryData() {
390 delete settings;
391 }
392
393 QSettings *settings;
394 LibraryMap libraryMap;
395};
396
397Q_GLOBAL_STATIC(LibraryData, libraryData)
398
399static LibraryMap *libraryMap()
400{
401 LibraryData *data = libraryData();
402 return data ? &data->libraryMap : 0;
403}
404
405QLibraryPrivate::QLibraryPrivate(const QString &canonicalFileName, const QString &version)
406 :pHnd(0), fileName(canonicalFileName), fullVersion(version), instance(0), qt_version(0),
407 libraryRefCount(1), libraryUnloadCount(0), pluginState(MightBeAPlugin)
408{ libraryMap()->insert(canonicalFileName, this); }
409
410QLibraryPrivate *QLibraryPrivate::findOrCreate(const QString &fileName, const QString &version)
411{
412 QMutexLocker locker(qt_library_mutex());
413 if (QLibraryPrivate *lib = libraryMap()->value(fileName)) {
414 lib->libraryRefCount.ref();
415 return lib;
416 }
417
418 return new QLibraryPrivate(fileName, version);
419}
420
421QLibraryPrivate::~QLibraryPrivate()
422{
423 LibraryMap * const map = libraryMap();
424 if (map) {
425 QLibraryPrivate *that = map->take(fileName);
426 Q_ASSERT(this == that);
427 Q_UNUSED(that);
428 }
429}
430
431void *QLibraryPrivate::resolve(const char *symbol)
432{
433 if (!pHnd)
434 return 0;
435 return resolve_sys(symbol);
436}
437
438
439bool QLibraryPrivate::load()
440{
441 libraryUnloadCount.ref();
442 if (pHnd)
443 return true;
444 if (fileName.isEmpty())
445 return false;
446 return load_sys();
447}
448
449bool QLibraryPrivate::unload()
450{
451 if (!pHnd)
452 return false;
453 if (!libraryUnloadCount.deref()) { // only unload if ALL QLibrary instance wanted to
454 if (instance)
455 delete instance();
456 if (unload_sys()) {
457 instance = 0;
458 pHnd = 0;
459 }
460 }
461
462 return (pHnd == 0);
463}
464
465void QLibraryPrivate::release()
466{
467 QMutexLocker locker(qt_library_mutex());
468 if (!libraryRefCount.deref())
469 delete this;
470}
471
472bool QLibraryPrivate::loadPlugin()
473{
474 if (instance) {
475 libraryUnloadCount.ref();
476 return true;
477 }
478 if (load()) {
479 instance = (QtPluginInstanceFunction)resolve("qt_plugin_instance");
480#if defined(Q_OS_SYMBIAN)
481 if (!instance) {
482 // If resolving with function name failed (i.e. not STDDLL),
483 // try resolving using known ordinal, which for
484 // qt_plugin_instance function is always "2".
485 instance = (QtPluginInstanceFunction)resolve("2");
486 }
487#endif
488 return instance;
489 }
490 return false;
491}
492
493/*!
494 Returns true if \a fileName has a valid suffix for a loadable
495 library; otherwise returns false.
496
497 \table
498 \header \i Platform \i Valid suffixes
499 \row \i Windows, OS/2 \i \c .dll
500 \row \i Unix/Linux \i \c .so
501 \row \i AIX \i \c .a
502 \row \i HP-UX \i \c .sl, \c .so (HP-UXi)
503 \row \i Mac OS X \i \c .dylib, \c .bundle, \c .so
504 \row \i Symbian \i \c .dll
505 \endtable
506
507 Trailing versioning numbers on Unix are ignored.
508 */
509bool QLibrary::isLibrary(const QString &fileName)
510{
511#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined(Q_OS_OS2)
512 return fileName.endsWith(QLatin1String(".dll"), Qt::CaseInsensitive);
513#elif defined(Q_OS_SYMBIAN)
514 // Plugin stubs are also considered libraries in Symbian.
515 return (fileName.endsWith(QLatin1String(".dll")) ||
516 fileName.endsWith(QLatin1String(".qtplugin")));
517#else
518 QString completeSuffix = QFileInfo(fileName).completeSuffix();
519 if (completeSuffix.isEmpty())
520 return false;
521 QStringList suffixes = completeSuffix.split(QLatin1Char('.'));
522# if defined(Q_OS_DARWIN)
523
524 // On Mac, libs look like libmylib.1.0.0.dylib
525 const QString lastSuffix = suffixes.at(suffixes.count() - 1);
526 const QString firstSuffix = suffixes.at(0);
527
528 bool valid = (lastSuffix == QLatin1String("dylib")
529 || firstSuffix == QLatin1String("so")
530 || firstSuffix == QLatin1String("bundle"));
531
532 return valid;
533# else // Generic Unix
534 QStringList validSuffixList;
535
536# if defined(Q_OS_HPUX)
537/*
538 See "HP-UX Linker and Libraries User's Guide", section "Link-time Differences between PA-RISC and IPF":
539 "In PA-RISC (PA-32 and PA-64) shared libraries are suffixed with .sl. In IPF (32-bit and 64-bit),
540 the shared libraries are suffixed with .so. For compatibility, the IPF linker also supports the .sl suffix."
541 */
542 validSuffixList << QLatin1String("sl");
543# if defined __ia64
544 validSuffixList << QLatin1String("so");
545# endif
546# elif defined(Q_OS_AIX)
547 validSuffixList << QLatin1String("a") << QLatin1String("so");
548# elif defined(Q_OS_UNIX)
549 validSuffixList << QLatin1String("so");
550# endif
551
552 // Examples of valid library names:
553 // libfoo.so
554 // libfoo.so.0
555 // libfoo.so.0.3
556 // libfoo-0.3.so
557 // libfoo-0.3.so.0.3.0
558
559 int suffix;
560 int suffixPos = -1;
561 for (suffix = 0; suffix < validSuffixList.count() && suffixPos == -1; ++suffix)
562 suffixPos = suffixes.indexOf(validSuffixList.at(suffix));
563
564 bool valid = suffixPos != -1;
565 for (int i = suffixPos + 1; i < suffixes.count() && valid; ++i)
566 if (i != suffixPos)
567 suffixes.at(i).toInt(&valid);
568 return valid;
569# endif
570#endif
571
572}
573
574bool QLibraryPrivate::isPlugin(QSettings *settings)
575{
576 errorString.clear();
577 if (pluginState != MightBeAPlugin)
578 return pluginState == IsAPlugin;
579
580#ifndef QT_NO_PLUGIN_CHECK
581 bool debug = !QLIBRARY_AS_DEBUG;
582 QByteArray key;
583 bool success = false;
584
585#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
586 if (fileName.endsWith(QLatin1String(".debug"))) {
587 // refuse to load a file that ends in .debug
588 // these are the debug symbols from the libraries
589 // the problem is that they are valid shared library files
590 // and dlopen is known to crash while opening them
591
592 // pretend we didn't see the file
593 errorString = QLibrary::tr("The shared library was not found.");
594 pluginState = IsNotAPlugin;
595 return false;
596 }
597#endif
598
599 QFileInfo fileinfo(fileName);
600
601#ifndef QT_NO_DATESTRING
602 lastModified = fileinfo.lastModified().toString(Qt::ISODate);
603#endif
604 QString regkey = QString::fromLatin1("Qt Plugin Cache %1.%2.%3/%4")
605 .arg((QT_VERSION & 0xff0000) >> 16)
606 .arg((QT_VERSION & 0xff00) >> 8)
607 .arg(QLIBRARY_AS_DEBUG ? QLatin1String("debug") : QLatin1String("false"))
608 .arg(fileName);
609#ifdef Q_WS_MAC
610 // On Mac, add the application arch to the reg key in order to
611 // cache plugin information separately for each arch. This prevents
612 // Qt from wrongly caching plugin load failures when the archs
613 // don't match.
614#if defined(__x86_64__)
615 regkey += QLatin1String("-x86_64");
616#elif defined(__i386__)
617 regkey += QLatin1String("-i386");
618#elif defined(__ppc64__)
619 regkey += QLatin1String("-ppc64");
620#elif defined(__ppc__)
621 regkey += QLatin1String("-ppc");
622#endif
623#endif // Q_WS_MAC
624
625 QStringList reg;
626#ifndef QT_NO_SETTINGS
627 if (!settings) {
628 settings = libraryData()->settings;
629 if (!settings) {
630 settings = new QSettings(QSettings::UserScope, QLatin1String("Trolltech"));
631 libraryData()->settings = settings;
632 }
633 }
634 reg = settings->value(regkey).toStringList();
635#endif
636 if (reg.count() == 4 && lastModified == reg.at(3)) {
637 qt_version = reg.at(0).toUInt(0, 16);
638 debug = bool(reg.at(1).toInt());
639 key = reg.at(2).toLatin1();
640 success = qt_version != 0;
641 } else {
642#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_SYMBIAN)
643 if (!pHnd) {
644 // use unix shortcut to avoid loading the library
645 success = qt_unix_query(fileName, &qt_version, &debug, &key, this);
646 } else
647#endif
648 {
649 bool temporary_load = false;
650#ifdef Q_OS_WIN
651 HMODULE hTempModule = 0;
652#endif
653 if (!pHnd) {
654#ifdef Q_OS_WIN
655 //avoid 'Bad Image' message box
656 UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
657 hTempModule = ::LoadLibraryEx((wchar_t*)QDir::toNativeSeparators(fileName).utf16(), 0, DONT_RESOLVE_DLL_REFERENCES);
658 SetErrorMode(oldmode);
659#else
660# if defined(Q_OS_SYMBIAN)
661 //Guard against accidentally trying to load non-plugin libraries by making sure the stub exists
662 if (fileinfo.exists())
663# endif
664 temporary_load = load_sys();
665#endif
666 }
667# ifdef Q_CC_BOR
668 typedef const char * __stdcall (*QtPluginQueryVerificationDataFunction)();
669# else
670 typedef const char * (*QtPluginQueryVerificationDataFunction)();
671# endif
672#ifdef Q_OS_WIN
673 QtPluginQueryVerificationDataFunction qtPluginQueryVerificationDataFunction = hTempModule
674 ? (QtPluginQueryVerificationDataFunction)
675#ifdef Q_OS_WINCE
676 ::GetProcAddress(hTempModule, L"qt_plugin_query_verification_data")
677#else
678 ::GetProcAddress(hTempModule, "qt_plugin_query_verification_data")
679#endif
680 : (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
681#else
682 QtPluginQueryVerificationDataFunction qtPluginQueryVerificationDataFunction = NULL;
683# if defined(Q_OS_SYMBIAN)
684 if (temporary_load) {
685 qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
686 // If resolving with function name failed (i.e. not STDDLL), try resolving using known ordinal
687 if (!qtPluginQueryVerificationDataFunction)
688 qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("1");
689 }
690# else
691 if (pHnd)
692 qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
693# endif
694#endif
695
696 if (!qtPluginQueryVerificationDataFunction
697 || !qt_parse_pattern(qtPluginQueryVerificationDataFunction(), &qt_version, &debug, &key)) {
698 qt_version = 0;
699 key = "unknown";
700 if (temporary_load)
701 unload_sys();
702 } else {
703 success = true;
704 }
705#ifdef Q_OS_WIN
706 if (hTempModule) {
707 BOOL ok = ::FreeLibrary(hTempModule);
708 if (ok) {
709 hTempModule = 0;
710 }
711
712 }
713#endif
714 }
715
716 // Qt 4.5 compatibility: stl doesn't affect binary compatibility
717 key.replace(" no-stl", "");
718
719#ifndef QT_NO_SETTINGS
720 QStringList queried;
721 queried << QString::number(qt_version,16)
722 << QString::number((int)debug)
723 << QLatin1String(key)
724 << lastModified;
725 settings->setValue(regkey, queried);
726#endif
727 }
728
729 if (!success) {
730 if (errorString.isEmpty()){
731 if (fileName.isEmpty())
732 errorString = QLibrary::tr("The shared library was not found.");
733 else
734 errorString = QLibrary::tr("The file '%1' is not a valid Qt plugin.").arg(fileName);
735 }
736 return false;
737 }
738
739 pluginState = IsNotAPlugin; // be pessimistic
740
741 if ((qt_version & 0x00ff00) > (QT_VERSION & 0x00ff00) || (qt_version & 0xff0000) != (QT_VERSION & 0xff0000)) {
742 if (qt_debug_component()) {
743 qWarning("In %s:\n"
744 " Plugin uses incompatible Qt library (%d.%d.%d) [%s]",
745 (const char*) QFile::encodeName(fileName),
746 (qt_version&0xff0000) >> 16, (qt_version&0xff00) >> 8, qt_version&0xff,
747 debug ? "debug" : "release");
748 }
749 errorString = QLibrary::tr("The plugin '%1' uses incompatible Qt library. (%2.%3.%4) [%5]")
750 .arg(fileName)
751 .arg((qt_version&0xff0000) >> 16)
752 .arg((qt_version&0xff00) >> 8)
753 .arg(qt_version&0xff)
754 .arg(debug ? QLatin1String("debug") : QLatin1String("release"));
755 } else if (key != QT_BUILD_KEY
756 // we may have some compatibility keys, try them too:
757#ifdef QT_BUILD_KEY_COMPAT
758 && key != QT_BUILD_KEY_COMPAT
759#endif
760#ifdef QT_BUILD_KEY_COMPAT2
761 && key != QT_BUILD_KEY_COMPAT2
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*/
804bool 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*/
829bool 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 */
843bool QLibrary::isLoaded() const
844{
845 return d && d->pHnd;
846}
847
848
849/*!
850 Constructs a library with the given \a parent.
851 */
852QLibrary::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 */
869QLibrary::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*/
888QLibrary::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 */
906QLibrary::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*/
920QLibrary::~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
950void 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
963QString 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*/
981void 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*/
1005void 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*/
1041void *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*/
1064void *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*/
1087void *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*/
1111void *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*/
1135QString 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*/
1169void 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
1178QLibrary::LoadHints QLibrary::loadHints() const
1179{
1180 return d ? d->loadHints : (QLibrary::LoadHints)0;
1181}
1182
1183/* Internal, for debugging */
1184bool 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
1197QT_END_NAMESPACE
1198
1199#endif // QT_NO_LIBRARY
Note: See TracBrowser for help on using the repository browser.