Qt 4.8
qlibrary_unix.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qplatformdefs.h"
43 
44 #include <qfile.h>
45 #include "qlibrary_p.h"
46 #include <qcoreapplication.h>
47 #include <private/qfilesystementry_p.h>
48 
49 #ifndef QT_NO_LIBRARY
50 
51 #ifdef Q_OS_MAC
52 # include <private/qcore_mac_p.h>
53 #endif
54 
55 #if defined(QT_AOUT_UNDERSCORE)
56 #include <string.h>
57 #endif
58 
59 #if (defined(Q_OS_VXWORKS) && !defined(VXWORKS_RTP)) || defined (Q_OS_NACL)
60 #define QT_NO_DYNAMIC_LIBRARY
61 #endif
62 
64 
65 #if !defined(QT_HPUX_LD) && !defined(QT_NO_DYNAMIC_LIBRARY)
67 #include <dlfcn.h>
69 #endif
70 
71 static QString qdlerror()
72 {
73 #if defined(QT_NO_DYNAMIC_LIBRARY)
74  const char *err = "This platform does not support dynamic libraries.";
75 #elif !defined(QT_HPUX_LD)
76  const char *err = dlerror();
77 #else
78  const char *err = strerror(errno);
79 #endif
80  return err ? QLatin1Char('(') + QString::fromLocal8Bit(err) + QLatin1Char(')'): QString();
81 }
82 
84 {
85  QString attempt;
86 #if !defined(QT_NO_DYNAMIC_LIBRARY)
87  QFileSystemEntry fsEntry(fileName);
88 
89 #if defined(Q_OS_SYMBIAN)
90  QString path; // In Symbian, always resolve with just the filename
91  QString name;
92 
93  // Replace possible ".qtplugin" suffix with ".dll"
94  if (fsEntry.suffix() == QLatin1String("qtplugin"))
95  name = fsEntry.completeBaseName() + QLatin1String(".dll");
96  else
97  name = fsEntry.fileName();
98 #else
99  QString path = fsEntry.path();
100  QString name = fsEntry.fileName();
101  if (path == QLatin1String(".") && !fileName.startsWith(path))
102  path.clear();
103  else
104  path += QLatin1Char('/');
105 #endif
106 
107  QStringList suffixes;
108  QStringList prefixes;
109  if (pluginState != IsAPlugin) {
110 #if !defined(Q_OS_SYMBIAN)
111  prefixes << QLatin1String("lib");
112 #endif
113 #if defined(Q_OS_HPUX)
114  // according to
115  // http://docs.hp.com/en/B2355-90968/linkerdifferencesiapa.htm
116 
117  // In PA-RISC (PA-32 and PA-64) shared libraries are suffixed
118  // with .sl. In IPF (32-bit and 64-bit), the shared libraries
119  // are suffixed with .so. For compatibility, the IPF linker
120  // also supports the .sl suffix.
121 
122  // But since we don't know if we are built on HPUX or HPUXi,
123  // we support both .sl (and .<version>) and .so suffixes but
124  // .so is preferred.
125 # if defined(__ia64)
126  if (!fullVersion.isEmpty()) {
127  suffixes << QString::fromLatin1(".so.%1").arg(fullVersion);
128  } else {
129  suffixes << QLatin1String(".so");
130  }
131 # endif
132  if (!fullVersion.isEmpty()) {
133  suffixes << QString::fromLatin1(".sl.%1").arg(fullVersion);
134  suffixes << QString::fromLatin1(".%1").arg(fullVersion);
135  } else {
136  suffixes << QLatin1String(".sl");
137  }
138 #elif defined(Q_OS_SYMBIAN)
139  suffixes << QLatin1String(".dll");
140 #else
141 #ifdef Q_OS_AIX
142  suffixes << ".a";
143 #endif // Q_OS_AIX
144  if (!fullVersion.isEmpty()) {
145  suffixes << QString::fromLatin1(".so.%1").arg(fullVersion);
146  } else {
147  suffixes << QLatin1String(".so");
148  }
149 #endif
150 # ifdef Q_OS_MAC
151  if (!fullVersion.isEmpty()) {
152  suffixes << QString::fromLatin1(".%1.bundle").arg(fullVersion);
153  suffixes << QString::fromLatin1(".%1.dylib").arg(fullVersion);
154  } else {
155  suffixes << QLatin1String(".bundle") << QLatin1String(".dylib");
156  }
157 #endif
158  }
159  int dlFlags = 0;
160 #if defined(QT_HPUX_LD)
161  dlFlags = DYNAMIC_PATH | BIND_NONFATAL;
163  dlFlags |= BIND_IMMEDIATE;
164  } else {
165  dlFlags |= BIND_DEFERRED;
166  }
167 #else
168  if (loadHints & QLibrary::ResolveAllSymbolsHint) {
169  dlFlags |= RTLD_NOW;
170  } else {
171  dlFlags |= RTLD_LAZY;
172  }
174  dlFlags |= RTLD_GLOBAL;
175  }
176 #if !defined(Q_OS_CYGWIN)
177  else {
178 #if defined(Q_OS_MAC)
180 #endif
181  dlFlags |= RTLD_LOCAL;
182  }
183 #endif
184 #if defined(Q_OS_AIX) // Not sure if any other platform actually support this thing.
186  dlFlags |= RTLD_MEMBER;
187  }
188 #endif
189 #endif // QT_HPUX_LD
190  // If using the new search heuristics we do:
191  //
192  // If the filename is an absolute path then we want to try that first as it is most likely
193  // what the callee wants. If we have been given a non-absolute path then lets try the
194  // native library name first to avoid unnecessary calls to dlopen().
195  //
196  // otherwise:
197  //
198  // We use the old behaviour which is to always try the specified filename first
200  suffixes.append(QLatin1String(""));
201  prefixes.append(QLatin1String(""));
202  } else {
203  suffixes.prepend(QLatin1String(""));
204  prefixes.prepend(QLatin1String(""));
205  }
206 
207  bool retry = true;
208  for(int prefix = 0; retry && !pHnd && prefix < prefixes.size(); prefix++) {
209  for(int suffix = 0; retry && !pHnd && suffix < suffixes.size(); suffix++) {
210  if (!prefixes.at(prefix).isEmpty() && name.startsWith(prefixes.at(prefix)))
211  continue;
212  if (!suffixes.at(suffix).isEmpty() && name.endsWith(suffixes.at(suffix)))
213  continue;
214  if (loadHints & QLibrary::LoadArchiveMemberHint) {
215  attempt = name;
216  int lparen = attempt.indexOf(QLatin1Char('('));
217  if (lparen == -1)
218  lparen = attempt.count();
219  attempt = path + prefixes.at(prefix) + attempt.insert(lparen, suffixes.at(suffix));
220  } else {
221  attempt = path + prefixes.at(prefix) + name + suffixes.at(suffix);
222  }
223 #if defined(QT_HPUX_LD)
224  pHnd = (void*)shl_load(QFile::encodeName(attempt), dlFlags, 0);
225 #else
226  pHnd = dlopen(QFile::encodeName(attempt), dlFlags);
227 #endif
228 
229 #if defined(Q_OS_SYMBIAN)
230  // Never try again in symbian, dlopen already handles the library search logic,
231  // and there is only one possible suffix.
232  retry = false;
233 #else
234  if (!pHnd && fileName.startsWith(QLatin1Char('/')) && QFile::exists(attempt)) {
235  // We only want to continue if dlopen failed due to that the shared library did not exist.
236  // However, we are only able to apply this check for absolute filenames (since they are
237  // not influenced by the content of LD_LIBRARY_PATH, /etc/ld.so.cache, DT_RPATH etc...)
238  // This is all because dlerror is flawed and cannot tell us the reason why it failed.
239  retry = false;
240  }
241 #endif
242  }
243  }
244 
245 #ifdef Q_OS_MAC
246  if (!pHnd) {
247  QByteArray utf8Bundle = fileName.toUtf8();
248  QCFType<CFURLRef> bundleUrl = CFURLCreateFromFileSystemRepresentation(NULL, reinterpret_cast<const UInt8*>(utf8Bundle.data()), utf8Bundle.length(), true);
249  QCFType<CFBundleRef> bundle = CFBundleCreate(NULL, bundleUrl);
250  if(bundle) {
251  QCFType<CFURLRef> url = CFBundleCopyExecutableURL(bundle);
252  char executableFile[FILENAME_MAX];
253  CFURLGetFileSystemRepresentation(url, true, reinterpret_cast<UInt8*>(executableFile), FILENAME_MAX);
254  attempt = QString::fromUtf8(executableFile);
255  pHnd = dlopen(QFile::encodeName(attempt), dlFlags);
256  }
257  }
258 #endif
259 #endif // QT_NO_DYNAMIC_LIBRARY
260  if (!pHnd) {
261  errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName).arg(qdlerror());
262  }
263  if (pHnd) {
264  qualifiedFileName = attempt;
265  errorString.clear();
266  }
267  return (pHnd != 0);
268 }
269 
271 {
272 #if !defined(QT_NO_DYNAMIC_LIBRARY)
273 # if defined(QT_HPUX_LD)
274  if (shl_unload((shl_t)pHnd)) {
275 # else
276  if (dlclose(pHnd)) {
277 # endif
278  errorString = QLibrary::tr("Cannot unload library %1: %2").arg(fileName).arg(qdlerror());
279  return false;
280  }
281 #endif
282  errorString.clear();
283  return true;
284 }
285 
286 #ifdef Q_OS_MAC
287 Q_CORE_EXPORT void *qt_mac_resolve_sys(void *handle, const char *symbol)
288 {
289  return dlsym(handle, symbol);
290 }
291 #endif
292 
293 void* QLibraryPrivate::resolve_sys(const char* symbol)
294 {
295 #if defined(QT_AOUT_UNDERSCORE)
296  // older a.out systems add an underscore in front of symbols
297  char* undrscr_symbol = new char[strlen(symbol)+2];
298  undrscr_symbol[0] = '_';
299  strcpy(undrscr_symbol+1, symbol);
300  void* address = dlsym(pHnd, undrscr_symbol);
301  delete [] undrscr_symbol;
302 #elif defined(QT_HPUX_LD)
303  void* address = 0;
304  if (shl_findsym((shl_t*)&pHnd, symbol, TYPE_UNDEFINED, &address) < 0)
305  address = 0;
306 #elif defined (QT_NO_DYNAMIC_LIBRARY)
307  void *address = 0;
308 #else
309  void* address = dlsym(pHnd, symbol);
310 #endif
311  if (!address) {
312  errorString = QLibrary::tr("Cannot resolve symbol \"%1\" in %2: %3").arg(
314  } else {
315  errorString.clear();
316  }
317  return address;
318 }
319 
321 
322 #endif // QT_NO_LIBRARY
static QString fromLocal8Bit(const char *, int size=-1)
Returns a QString initialized with the first size characters of the 8-bit string str.
Definition: qstring.cpp:4245
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
static QString fromAscii(const char *, int size=-1)
Returns a QString initialized with the first size characters from the string str. ...
Definition: qstring.cpp:4276
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
QByteArray toUtf8() const Q_REQUIRED_RESULT
Returns a UTF-8 representation of the string as a QByteArray.
Definition: qstring.cpp:4074
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition: qstring.cpp:3734
#define QT_END_INCLUDE_NAMESPACE
This macro is equivalent to QT_BEGIN_NAMESPACE.
Definition: qglobal.h:92
static QString tr(const char *sourceText, const char *comment=0, int n=-1)
Q_CORE_EXPORT void * qt_mac_resolve_sys(void *handle, const char *symbol)
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
bool isAbsolute() const
The QString class provides a Unicode character string.
Definition: qstring.h:83
bool exists() const
Returns true if the file specified by fileName() exists; otherwise returns false. ...
Definition: qfile.cpp:626
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
enum QLibraryPrivate::@42 pluginState
QString fileName
Definition: qlibrary_p.h:83
const char * name
void prepend(const T &t)
Inserts value at the beginning of the list.
Definition: qlist.h:541
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
The QStringList class provides a list of strings.
Definition: qstringlist.h:66
QString fileName() const
static QString fromUtf8(const char *, int size=-1)
Returns a QString initialized with the first size bytes of the UTF-8 string str.
Definition: qstring.cpp:4302
void * resolve_sys(const char *)
int indexOf(QChar c, int from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:2838
int count() const
Definition: qstring.h:103
HINSTANCE pHnd
Definition: qlibrary_p.h:81
int length() const
Same as size().
Definition: qbytearray.h:356
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
QString errorString
Definition: qlibrary_p.h:99
#define Q_CORE_EXPORT
Definition: qglobal.h:1449
void clear()
Clears the contents of the string and makes it empty.
Definition: qstring.h:723
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
QByteArray suffix
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
QString completeBaseName() const
static QString qdlerror()
#define QT_BEGIN_INCLUDE_NAMESPACE
This macro is equivalent to QT_END_NAMESPACE.
Definition: qglobal.h:91
static QByteArray encodeName(const QString &fileName)
By default, this function converts fileName to the local 8-bit encoding determined by the user&#39;s loca...
Definition: qfile.cpp:528
static const MacVersion MacintoshVersion
the version of the Macintosh operating system on which the application is run (Mac only)...
Definition: qglobal.h:1646
QString suffix() const
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition: qstring.cpp:3796
QLibrary::LoadHints loadHints
Definition: qlibrary_p.h:100
QString qualifiedFileName
Definition: qlibrary_p.h:83
QString & insert(int i, QChar c)
Definition: qstring.cpp:1671
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
QString path() const
int errno
QString fullVersion
Definition: qlibrary_p.h:84