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

Last change on this file since 1040 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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 qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
692# endif
693#endif
694
695 if (!qtPluginQueryVerificationDataFunction
696 || !qt_parse_pattern(qtPluginQueryVerificationDataFunction(), &qt_version, &debug, &key)) {
697 qt_version = 0;
698 key = "unknown";
699 if (temporary_load)
700 unload_sys();
701 } else {
702 success = true;
703 }
704#ifdef Q_OS_WIN
705 if (hTempModule) {
706 BOOL ok = ::FreeLibrary(hTempModule);
707 if (ok) {
708 hTempModule = 0;
709 }
710
711 }
712#endif
713 }
714
715 // Qt 4.5 compatibility: stl doesn't affect binary compatibility
716 key.replace(" no-stl", "");
717
718#ifndef QT_NO_SETTINGS
719 QStringList queried;
720 queried << QString::number(qt_version,16)
721 << QString::number((int)debug)
722 << QLatin1String(key)
723 << lastModified;
724 settings->setValue(regkey, queried);
725#endif
726 }
727
728 if (!success) {
729 if (errorString.isEmpty()){
730 if (fileName.isEmpty())
731 errorString = QLibrary::tr("The shared library was not found.");
732 else
733 errorString = QLibrary::tr("The file '%1' is not a valid Qt plugin.").arg(fileName);
734 }
735 return false;
736 }
737
738 pluginState = IsNotAPlugin; // be pessimistic
739
740 if ((qt_version & 0x00ff00) > (QT_VERSION & 0x00ff00) || (qt_version & 0xff0000) != (QT_VERSION & 0xff0000)) {
741 if (qt_debug_component()) {
742 qWarning("In %s:\n"
743 " Plugin uses incompatible Qt library (%d.%d.%d) [%s]",
744 (const char*) QFile::encodeName(fileName),
745 (qt_version&0xff0000) >> 16, (qt_version&0xff00) >> 8, qt_version&0xff,
746 debug ? "debug" : "release");
747 }
748 errorString = QLibrary::tr("The plugin '%1' uses incompatible Qt library. (%2.%3.%4) [%5]")
749 .arg(fileName)
750 .arg((qt_version&0xff0000) >> 16)
751 .arg((qt_version&0xff00) >> 8)
752 .arg(qt_version&0xff)
753 .arg(debug ? QLatin1String("debug") : QLatin1String("release"));
754 } else if (key != QT_BUILD_KEY
755 // we may have some compatibility keys, try them too:
756#ifdef QT_BUILD_KEY_COMPAT
757 && key != QT_BUILD_KEY_COMPAT
758#endif
759#ifdef QT_BUILD_KEY_COMPAT2
760 && key != QT_BUILD_KEY_COMPAT2
761#endif
762 ) {
763 if (qt_debug_component()) {
764 qWarning("In %s:\n"
765 " Plugin uses incompatible Qt library\n"
766 " expected build key \"%s\", got \"%s\"",
767 (const char*) QFile::encodeName(fileName),
768 QT_BUILD_KEY,
769 key.isEmpty() ? "<null>" : (const char *) key);
770 }
771 errorString = QLibrary::tr("The plugin '%1' uses incompatible Qt library."
772 " Expected build key \"%2\", got \"%3\"")
773 .arg(fileName)
774 .arg(QLatin1String(QT_BUILD_KEY))
775 .arg(key.isEmpty() ? QLatin1String("<null>") : QLatin1String((const char *) key));
776#ifndef QT_NO_DEBUG_PLUGIN_CHECK
777 } else if(debug != QLIBRARY_AS_DEBUG) {
778 //don't issue a qWarning since we will hopefully find a non-debug? --Sam
779 errorString = QLibrary::tr("The plugin '%1' uses incompatible Qt library."
780 " (Cannot mix debug and release libraries.)").arg(fileName);
781#endif
782 } else {
783 pluginState = IsAPlugin;
784 }
785
786 return pluginState == IsAPlugin;
787#else
788 Q_UNUSED(settings);
789 return pluginState == MightBeAPlugin;
790#endif
791}
792
793/*!
794 Loads the library and returns true if the library was loaded
795 successfully; otherwise returns false. Since resolve() always
796 calls this function before resolving any symbols it is not
797 necessary to call it explicitly. In some situations you might want
798 the library loaded in advance, in which case you would use this
799 function.
800
801 \sa unload()
802*/
803bool QLibrary::load()
804{
805 if (!d)
806 return false;
807 if (did_load)
808 return d->pHnd;
809 did_load = true;
810 return d->load();
811}
812
813/*!
814 Unloads the library and returns true if the library could be
815 unloaded; otherwise returns false.
816
817 This happens automatically on application termination, so you
818 shouldn't normally need to call this function.
819
820 If other instances of QLibrary are using the same library, the
821 call will fail, and unloading will only happen when every instance
822 has called unload().
823
824 Note that on Mac OS X 10.3 (Panther), dynamic libraries cannot be unloaded.
825
826 \sa resolve(), load()
827*/
828bool QLibrary::unload()
829{
830 if (did_load) {
831 did_load = false;
832 return d->unload();
833 }
834 return false;
835}
836
837/*!
838 Returns true if the library is loaded; otherwise returns false.
839
840 \sa load()
841 */
842bool QLibrary::isLoaded() const
843{
844 return d && d->pHnd;
845}
846
847
848/*!
849 Constructs a library with the given \a parent.
850 */
851QLibrary::QLibrary(QObject *parent)
852 :QObject(parent), d(0), did_load(false)
853{
854}
855
856
857/*!
858 Constructs a library object with the given \a parent that will
859 load the library specified by \a fileName.
860
861 We recommend omitting the file's suffix in \a fileName, since
862 QLibrary will automatically look for the file with the appropriate
863 suffix in accordance with the platform, e.g. ".so" on Unix,
864 ".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.)
865
866 Note: In Symbian the path portion of the \a fileName is ignored.
867 */
868QLibrary::QLibrary(const QString& fileName, QObject *parent)
869 :QObject(parent), d(0), did_load(false)
870{
871 setFileName(fileName);
872}
873
874
875/*!
876 Constructs a library object with the given \a parent that will
877 load the library specified by \a fileName and major version number \a verNum.
878 Currently, the version number is ignored on Windows and Symbian.
879
880 We recommend omitting the file's suffix in \a fileName, since
881 QLibrary will automatically look for the file with the appropriate
882 suffix in accordance with the platform, e.g. ".so" on Unix,
883 ".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.)
884
885 Note: In Symbian the path portion of the \a fileName is ignored.
886*/
887QLibrary::QLibrary(const QString& fileName, int verNum, QObject *parent)
888 :QObject(parent), d(0), did_load(false)
889{
890 setFileNameAndVersion(fileName, verNum);
891}
892
893/*!
894 Constructs a library object with the given \a parent that will
895 load the library specified by \a fileName and full version number \a version.
896 Currently, the version number is ignored on Windows and Symbian.
897
898 We recommend omitting the file's suffix in \a fileName, since
899 QLibrary will automatically look for the file with the appropriate
900 suffix in accordance with the platform, e.g. ".so" on Unix,
901 ".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.)
902
903 Note: In Symbian the path portion of the \a fileName is ignored.
904 */
905QLibrary::QLibrary(const QString& fileName, const QString &version, QObject *parent)
906 :QObject(parent), d(0), did_load(false)
907{
908 setFileNameAndVersion(fileName, version);
909}
910
911/*!
912 Destroys the QLibrary object.
913
914 Unless unload() was called explicitly, the library stays in memory
915 until the application terminates.
916
917 \sa isLoaded(), unload()
918*/
919QLibrary::~QLibrary()
920{
921 if (d)
922 d->release();
923}
924
925
926/*!
927 \property QLibrary::fileName
928 \brief the file name of the library
929
930 We recommend omitting the file's suffix in the file name, since
931 QLibrary will automatically look for the file with the appropriate
932 suffix (see isLibrary()).
933
934 When loading the library, QLibrary searches in all system-specific
935 library locations (e.g. \c LD_LIBRARY_PATH on Unix), unless the
936 file name has an absolute path. After loading the library
937 successfully, fileName() returns the fully-qualified file name of
938 the library, including the full path to the library if one was given
939 in the constructor or passed to setFileName().
940
941 For example, after successfully loading the "GL" library on Unix
942 platforms, fileName() will return "libGL.so". If the file name was
943 originally passed as "/usr/lib/libGL", fileName() will return
944 "/usr/lib/libGL.so".
945
946 Note: In Symbian the path portion of the \a fileName is ignored.
947*/
948
949void QLibrary::setFileName(const QString &fileName)
950{
951 QLibrary::LoadHints lh;
952 if (d) {
953 lh = d->loadHints;
954 d->release();
955 d = 0;
956 did_load = false;
957 }
958 d = QLibraryPrivate::findOrCreate(fileName);
959 d->loadHints = lh;
960}
961
962QString QLibrary::fileName() const
963{
964 if (d)
965 return d->qualifiedFileName.isEmpty() ? d->fileName : d->qualifiedFileName;
966 return QString();
967}
968
969/*!
970 \fn void QLibrary::setFileNameAndVersion(const QString &fileName, int versionNumber)
971
972 Sets the fileName property and major version number to \a fileName
973 and \a versionNumber respectively.
974 The \a versionNumber is ignored on Windows and Symbian.
975
976 Note: In Symbian the path portion of the \a fileName is ignored.
977
978 \sa setFileName()
979*/
980void QLibrary::setFileNameAndVersion(const QString &fileName, int verNum)
981{
982 QLibrary::LoadHints lh;
983 if (d) {
984 lh = d->loadHints;
985 d->release();
986 d = 0;
987 did_load = false;
988 }
989 d = QLibraryPrivate::findOrCreate(fileName, verNum >= 0 ? QString::number(verNum) : QString());
990 d->loadHints = lh;
991}
992
993/*!
994 \since 4.4
995
996 Sets the fileName property and full version number to \a fileName
997 and \a version respectively.
998 The \a version parameter is ignored on Windows and Symbian.
999
1000 Note: In Symbian the path portion of the \a fileName is ignored.
1001
1002 \sa setFileName()
1003*/
1004void QLibrary::setFileNameAndVersion(const QString &fileName, const QString &version)
1005{
1006 QLibrary::LoadHints lh;
1007 if (d) {
1008 lh = d->loadHints;
1009 d->release();
1010 d = 0;
1011 did_load = false;
1012 }
1013 d = QLibraryPrivate::findOrCreate(fileName, version);
1014 d->loadHints = lh;
1015}
1016
1017/*!
1018 Returns the address of the exported symbol \a symbol. The library is
1019 loaded if necessary. The function returns 0 if the symbol could
1020 not be resolved or if the library could not be loaded.
1021
1022 Example:
1023 \snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 2
1024
1025 The symbol must be exported as a C function from the library. This
1026 means that the function must be wrapped in an \c{extern "C"} if
1027 the library is compiled with a C++ compiler. On Windows you must
1028 also explicitly export the function from the DLL using the
1029 \c{__declspec(dllexport)} compiler directive, for example:
1030
1031 \snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 3
1032
1033 with \c MY_EXPORT defined as
1034
1035 \snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 4
1036
1037 Note: In Symbian resolving with symbol names works only if the loaded
1038 library was built as STDDLL. Otherwise, the ordinals must be used.
1039*/
1040void *QLibrary::resolve(const char *symbol)
1041{
1042 if (!load())
1043 return 0;
1044 return d->resolve(symbol);
1045}
1046
1047/*!
1048 \overload
1049
1050 Loads the library \a fileName and returns the address of the
1051 exported symbol \a symbol. Note that \a fileName should not
1052 include the platform-specific file suffix; (see \l{fileName}). The
1053 library remains loaded until the application exits.
1054
1055 The function returns 0 if the symbol could not be resolved or if
1056 the library could not be loaded.
1057
1058 Note: In Symbian resolving with symbol names works only if the loaded
1059 library was built as STDDLL. Otherwise, the ordinals must be used.
1060
1061 \sa resolve()
1062*/
1063void *QLibrary::resolve(const QString &fileName, const char *symbol)
1064{
1065 QLibrary library(fileName);
1066 return library.resolve(symbol);
1067}
1068
1069/*!
1070 \overload
1071
1072 Loads the library \a fileName with major version number \a verNum and
1073 returns the address of the exported symbol \a symbol.
1074 Note that \a fileName should not include the platform-specific file suffix;
1075 (see \l{fileName}). The library remains loaded until the application exits.
1076 \a verNum is ignored on Windows.
1077
1078 The function returns 0 if the symbol could not be resolved or if
1079 the library could not be loaded.
1080
1081 Note: In Symbian resolving with symbol names works only if the loaded
1082 library was built as STDDLL. Otherwise, the ordinals must be used.
1083
1084 \sa resolve()
1085*/
1086void *QLibrary::resolve(const QString &fileName, int verNum, const char *symbol)
1087{
1088 QLibrary library(fileName, verNum);
1089 return library.resolve(symbol);
1090}
1091
1092/*!
1093 \overload
1094 \since 4.4
1095
1096 Loads the library \a fileName with full version number \a version and
1097 returns the address of the exported symbol \a symbol.
1098 Note that \a fileName should not include the platform-specific file suffix;
1099 (see \l{fileName}). The library remains loaded until the application exits.
1100 \a version is ignored on Windows.
1101
1102 The function returns 0 if the symbol could not be resolved or if
1103 the library could not be loaded.
1104
1105 Note: In Symbian resolving with symbol names works only if the loaded
1106 library was built as STDDLL. Otherwise, the ordinals must be used.
1107
1108 \sa resolve()
1109*/
1110void *QLibrary::resolve(const QString &fileName, const QString &version, const char *symbol)
1111{
1112 QLibrary library(fileName, version);
1113 return library.resolve(symbol);
1114}
1115
1116/*!
1117 \fn QString QLibrary::library() const
1118
1119 Use fileName() instead.
1120*/
1121
1122/*!
1123 \fn void QLibrary::setAutoUnload( bool b )
1124
1125 Use load(), isLoaded(), and unload() as necessary instead.
1126*/
1127
1128/*!
1129 \since 4.2
1130
1131 Returns a text string with the description of the last error that occurred.
1132 Currently, errorString will only be set if load(), unload() or resolve() for some reason fails.
1133*/
1134QString QLibrary::errorString() const
1135{
1136 return (!d || d->errorString.isEmpty()) ? tr("Unknown error") : d->errorString;
1137}
1138
1139/*!
1140 \property QLibrary::loadHints
1141 \brief Give the load() function some hints on how it should behave.
1142
1143 You can give some hints on how the symbols are resolved. Usually,
1144 the symbols are not resolved at load time, but resolved lazily,
1145 (that is, when resolve() is called). If you set the loadHint to
1146 ResolveAllSymbolsHint, then all symbols will be resolved at load time
1147 if the platform supports it.
1148
1149 Setting ExportExternalSymbolsHint will make the external symbols in the
1150 library available for resolution in subsequent loaded libraries.
1151
1152 If LoadArchiveMemberHint is set, the file name
1153 is composed of two components: A path which is a reference to an
1154 archive file followed by the second component which is the reference to
1155 the archive member. For instance, the fileName \c libGL.a(shr_64.o) will refer
1156 to the library \c shr_64.o in the archive file named \c libGL.a. This
1157 is only supported on the AIX platform.
1158
1159 The interpretation of the load hints is platform dependent, and if
1160 you use it you are probably making some assumptions on which platform
1161 you are compiling for, so use them only if you understand the consequences
1162 of them.
1163
1164 By default, none of these flags are set, so libraries will be loaded with
1165 lazy symbol resolution, and will not export external symbols for resolution
1166 in other dynamically-loaded libraries.
1167*/
1168void QLibrary::setLoadHints(LoadHints hints)
1169{
1170 if (!d) {
1171 d = QLibraryPrivate::findOrCreate(QString()); // ugly, but we need a d-ptr
1172 d->errorString.clear();
1173 }
1174 d->loadHints = hints;
1175}
1176
1177QLibrary::LoadHints QLibrary::loadHints() const
1178{
1179 return d ? d->loadHints : (QLibrary::LoadHints)0;
1180}
1181
1182/* Internal, for debugging */
1183bool qt_debug_component()
1184{
1185#if defined(QT_DEBUG_COMPONENT)
1186 return true; //compatibility?
1187#else
1188 static int debug_env = -1;
1189 if (debug_env == -1)
1190 debug_env = QT_PREPEND_NAMESPACE(qgetenv)("QT_DEBUG_PLUGINS").toInt();
1191
1192 return debug_env != 0;
1193#endif
1194}
1195
1196QT_END_NAMESPACE
1197
1198#endif // QT_NO_LIBRARY
Note: See TracBrowser for help on using the repository browser.