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

Last change on this file since 467 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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