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

Last change on this file since 846 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