name in the constructor, or set it explicitly with setFileName().
When loading the library, QLibrary searches in all the
system-specific library locations (e.g. \c LD_LIBRARY_PATH on
- Unix), unless the file name has an absolute path. If the file
- cannot be found, QLibrary tries the name with different
- platform-specific file suffixes, like ".so" on Unix, ".dylib" on
- the Mac, or ".dll" on Windows. This makes it possible
- to specify shared libraries that are only identified by their
- basename (i.e. without their suffix), so the same code will work
- on different operating systems.
+ Unix), unless the file name has an absolute path.
+
+ If the file name is an absolute path then an attempt is made to
+ load this path first. If the file cannot be found, QLibrary tries
+ the name with different platform-specific file prefixes, like
+ "lib" on Unix and Mac, and suffixes, like ".so" on Unix, ".dylib"
+ on the Mac, or ".dll" on Windows.
+
+ If the file path is not absolute then QLibrary modifies the search
+ order to try the system-specific prefixes and suffixes first,
+ followed by the file path specified.
+
+ This makes it possible to specify shared libraries that are only
+ identified by their basename (i.e. without their suffix), so the
+ same code will work on different operating systems yet still
+ minimise the number of attempts to find the library.
The most important functions are load() to dynamically load the
library file, isLoaded() to check whether loading was successful,
else
path += QLatin1Char('/');
- // The first filename we want to attempt to load is the filename as the callee specified.
- // Thus, the first attempt we do must be with an empty prefix and empty suffix.
- QStringList suffixes(QLatin1String("")), prefixes(QLatin1String(""));
+ QStringList suffixes;
+ QStringList prefixes;
if (pluginState != IsAPlugin) {
prefixes << QLatin1String("lib");
#if defined(Q_OS_HPUX)
}
#endif
#endif // QT_HPUX_LD
+
+ // If the filename is an absolute path then we want to try that first as it is most likely
+ // what the callee wants. If we have been given a non-absolute path then lets try the
+ // native library name first to avoid unnecessary calls to dlopen().
+ if (fsEntry.isAbsolute()) {
+ suffixes.prepend(QString());
+ prefixes.prepend(QString());
+ } else {
+ suffixes.append(QString());
+ prefixes.append(QString());
+ }
+
bool retry = true;
for(int prefix = 0; retry && !pHnd && prefix < prefixes.size(); prefix++) {
for(int suffix = 0; retry && !pHnd && suffix < suffixes.size(); suffix++) {
#include "qdir.h"
#include "qfileinfo.h"
#include "qdir.h"
+#include <private/qfilesystementry_p.h>
#if defined(QT_NO_LIBRARY) && defined(Q_OS_WIN)
#undef QT_NO_LIBRARY
bool QLibraryPrivate::load_sys()
{
-#ifdef Q_OS_WINCE
- QString attempt = QFileInfo(fileName).absoluteFilePath();
-#else
- QString attempt = fileName;
-#endif
-
//avoid 'Bad Image' message box
UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
- pHnd = LoadLibrary((wchar_t*)QDir::toNativeSeparators(attempt).utf16());
- if (pluginState != IsAPlugin) {
+ // We make the following attempts at locating the library:
+ //
+ // WinCE
+ // if (absolute)
+ // fileName
+ // fileName + ".dll"
+ // else
+ // fileName + ".dll"
+ // fileName
+ // QFileInfo(fileName).absoluteFilePath()
+ //
+ // Windows
+ // if (absolute)
+ // fileName
+ // fileName + ".dll"
+ // else
+ // fileName + ".dll"
+ // fileName
+ //
+ // NB If it's a plugin we do not ever try the ".dll" extension
+ QStringList attempts;
+
+ if (pluginState != IsAPlugin)
+ attempts.append(fileName + QLatin1String(".dll"));
+
+ // If the fileName is an absolute path we try that first, otherwise we
+ // use the system-specific suffix first
+ QFileSystemEntry fsEntry(fileName);
+ if (fsEntry.isAbsolute()) {
+ attempts.prepend(fileName);
+ } else {
+ attempts.append(fileName);
#if defined(Q_OS_WINCE)
- if (!pHnd && ::GetLastError() == ERROR_MOD_NOT_FOUND) {
- QString secondAttempt = fileName;
- pHnd = LoadLibrary((wchar_t*)QDir::toNativeSeparators(secondAttempt).utf16());
- }
+ attempts.append(QFileInfo(fileName).absoluteFilePath());
#endif
- if (!pHnd && ::GetLastError() == ERROR_MOD_NOT_FOUND) {
- attempt += QLatin1String(".dll");
- pHnd = LoadLibrary((wchar_t*)QDir::toNativeSeparators(attempt).utf16());
- }
+ }
+
+ Q_FOREACH (const QString &attempt, attempts) {
+ pHnd = LoadLibrary((wchar_t*)QDir::toNativeSeparators(attempt).utf16());
+
+ // If we have a handle or the last error is something other than "unable
+ // to find the module", then bail out
+ if (pHnd || ::GetLastError() != ERROR_MOD_NOT_FOUND)
+ break;
}
SetErrorMode(oldmode);
if (!pHnd) {
errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName).arg(qt_error_string());
- }
- if (pHnd) {
+ } else {
+ // Query the actual name of the library that was loaded
errorString.clear();
wchar_t buffer[MAX_PATH];
::GetModuleFileName(pHnd, buffer, MAX_PATH);
- attempt = QString::fromWCharArray(buffer);
- const QDir dir = QFileInfo(fileName).dir();
- const QString realfilename = attempt.mid(attempt.lastIndexOf(QLatin1Char('\\')) + 1);
+ QString moduleFileName = QString::fromWCharArray(buffer);
+ moduleFileName.remove(0, 1 + moduleFileName.lastIndexOf(QLatin1Char('\\')));
+ const QDir dir(fsEntry.path());
if (dir.path() == QLatin1String("."))
- qualifiedFileName = realfilename;
+ qualifiedFileName = moduleFileName;
else
- qualifiedFileName = dir.filePath(realfilename);
+ qualifiedFileName = dir.filePath(moduleFileName);
}
return (pHnd != 0);
}