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

Last change on this file since 570 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

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