QPluginLoader: fix loading of plugins with a relative file name
This makes QT_PLUGIN_PATH / QCoreApplication::libraryPaths() actually work, as a search path for plugins, when apps look for a specific plugin by name. To make it possible to write portable code (unlike the current QPluginLoader unittest), let QPluginLoader figure out the extension, too. Change-Id: I895d597d7cb05ded268734bc5f313f32d8d12cb9 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
parent
f6cc1f3aea
commit
418890e074
@ -92,6 +92,8 @@ public:
|
||||
QFunctionPointer resolve(const char *);
|
||||
|
||||
static QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version = QString());
|
||||
static QStringList suffixes_sys(const QString &fullVersion);
|
||||
static QStringList prefixes_sys();
|
||||
|
||||
static QVector<QStaticPlugin> staticPlugins();
|
||||
|
||||
|
@ -80,6 +80,60 @@ static QString qdlerror()
|
||||
return err ? QLatin1Char('(') + QString::fromLocal8Bit(err) + QLatin1Char(')'): QString();
|
||||
}
|
||||
|
||||
QStringList QLibraryPrivate::suffixes_sys(const QString& fullVersion)
|
||||
{
|
||||
QStringList suffixes;
|
||||
#if defined(Q_OS_HPUX)
|
||||
// according to
|
||||
// http://docs.hp.com/en/B2355-90968/linkerdifferencesiapa.htm
|
||||
|
||||
// In PA-RISC (PA-32 and PA-64) shared libraries are suffixed
|
||||
// with .sl. In IPF (32-bit and 64-bit), the shared libraries
|
||||
// are suffixed with .so. For compatibility, the IPF linker
|
||||
// also supports the .sl suffix.
|
||||
|
||||
// But since we don't know if we are built on HPUX or HPUXi,
|
||||
// we support both .sl (and .<version>) and .so suffixes but
|
||||
// .so is preferred.
|
||||
# if defined(__ia64)
|
||||
if (!fullVersion.isEmpty()) {
|
||||
suffixes << QString::fromLatin1(".so.%1").arg(fullVersion);
|
||||
} else {
|
||||
suffixes << QLatin1String(".so");
|
||||
}
|
||||
# endif
|
||||
if (!fullVersion.isEmpty()) {
|
||||
suffixes << QString::fromLatin1(".sl.%1").arg(fullVersion);
|
||||
suffixes << QString::fromLatin1(".%1").arg(fullVersion);
|
||||
} else {
|
||||
suffixes << QLatin1String(".sl");
|
||||
}
|
||||
#elif defined(Q_OS_AIX)
|
||||
suffixes << ".a";
|
||||
|
||||
#else
|
||||
if (!fullVersion.isEmpty()) {
|
||||
suffixes << QString::fromLatin1(".so.%1").arg(fullVersion);
|
||||
} else {
|
||||
suffixes << QLatin1String(".so");
|
||||
}
|
||||
#endif
|
||||
# ifdef Q_OS_MAC
|
||||
if (!fullVersion.isEmpty()) {
|
||||
suffixes << QString::fromLatin1(".%1.bundle").arg(fullVersion);
|
||||
suffixes << QString::fromLatin1(".%1.dylib").arg(fullVersion);
|
||||
} else {
|
||||
suffixes << QLatin1String(".bundle") << QLatin1String(".dylib");
|
||||
}
|
||||
#endif
|
||||
return suffixes;
|
||||
}
|
||||
|
||||
QStringList QLibraryPrivate::prefixes_sys()
|
||||
{
|
||||
return QStringList() << QLatin1String("lib");
|
||||
}
|
||||
|
||||
bool QLibraryPrivate::load_sys()
|
||||
{
|
||||
QString attempt;
|
||||
@ -96,50 +150,8 @@ bool QLibraryPrivate::load_sys()
|
||||
QStringList suffixes;
|
||||
QStringList prefixes;
|
||||
if (pluginState != IsAPlugin) {
|
||||
prefixes << QLatin1String("lib");
|
||||
#if defined(Q_OS_HPUX)
|
||||
// according to
|
||||
// http://docs.hp.com/en/B2355-90968/linkerdifferencesiapa.htm
|
||||
|
||||
// In PA-RISC (PA-32 and PA-64) shared libraries are suffixed
|
||||
// with .sl. In IPF (32-bit and 64-bit), the shared libraries
|
||||
// are suffixed with .so. For compatibility, the IPF linker
|
||||
// also supports the .sl suffix.
|
||||
|
||||
// But since we don't know if we are built on HPUX or HPUXi,
|
||||
// we support both .sl (and .<version>) and .so suffixes but
|
||||
// .so is preferred.
|
||||
# if defined(__ia64)
|
||||
if (!fullVersion.isEmpty()) {
|
||||
suffixes << QString::fromLatin1(".so.%1").arg(fullVersion);
|
||||
} else {
|
||||
suffixes << QLatin1String(".so");
|
||||
}
|
||||
# endif
|
||||
if (!fullVersion.isEmpty()) {
|
||||
suffixes << QString::fromLatin1(".sl.%1").arg(fullVersion);
|
||||
suffixes << QString::fromLatin1(".%1").arg(fullVersion);
|
||||
} else {
|
||||
suffixes << QLatin1String(".sl");
|
||||
}
|
||||
#elif defined(Q_OS_AIX)
|
||||
suffixes << ".a";
|
||||
|
||||
#else
|
||||
if (!fullVersion.isEmpty()) {
|
||||
suffixes << QString::fromLatin1(".so.%1").arg(fullVersion);
|
||||
} else {
|
||||
suffixes << QLatin1String(".so");
|
||||
}
|
||||
#endif
|
||||
# ifdef Q_OS_MAC
|
||||
if (!fullVersion.isEmpty()) {
|
||||
suffixes << QString::fromLatin1(".%1.bundle").arg(fullVersion);
|
||||
suffixes << QString::fromLatin1(".%1.dylib").arg(fullVersion);
|
||||
} else {
|
||||
suffixes << QLatin1String(".bundle") << QLatin1String(".dylib");
|
||||
}
|
||||
#endif
|
||||
prefixes = prefixes_sys();
|
||||
suffixes = suffixes_sys(fullVersion);
|
||||
}
|
||||
int dlFlags = 0;
|
||||
#if defined(QT_HPUX_LD)
|
||||
|
@ -57,6 +57,17 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
extern QString qt_error_string(int code);
|
||||
|
||||
QStringList QLibraryPrivate::suffixes_sys(const QString& fullVersion)
|
||||
{
|
||||
Q_UNUSED(fullVersion);
|
||||
return QStringList() << ".dll";
|
||||
}
|
||||
|
||||
QStringList QLibraryPrivate::prefixes_sys()
|
||||
{
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
bool QLibraryPrivate::load_sys()
|
||||
{
|
||||
//avoid 'Bad Image' message box
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "qplatformdefs.h"
|
||||
|
||||
#include "qplugin.h"
|
||||
#include "qcoreapplication.h"
|
||||
#include "qpluginloader.h"
|
||||
#include <qfileinfo.h>
|
||||
#include "qlibrary_p.h"
|
||||
@ -250,14 +251,52 @@ bool QPluginLoader::isLoaded() const
|
||||
return d && d->pHnd && d->instance;
|
||||
}
|
||||
|
||||
static QString locatePlugin(const QString& fileName)
|
||||
{
|
||||
QStringList prefixes = QLibraryPrivate::prefixes_sys();
|
||||
prefixes.prepend(QString());
|
||||
QStringList suffixes = QLibraryPrivate::suffixes_sys(QString());
|
||||
suffixes.prepend(QString());
|
||||
|
||||
// Split up "subdir/filename"
|
||||
const int slash = fileName.lastIndexOf('/');
|
||||
const QString baseName = fileName.mid(slash + 1);
|
||||
const QString basePath = fileName.left(slash + 1); // keep the '/'
|
||||
|
||||
const bool debug = qt_debug_component();
|
||||
|
||||
QStringList paths = QCoreApplication::libraryPaths();
|
||||
paths.prepend(QStringLiteral("./")); // search in current dir first
|
||||
foreach (const QString &path, paths) {
|
||||
foreach (const QString &prefix, prefixes) {
|
||||
foreach (const QString &suffix, suffixes) {
|
||||
const QString fn = path + QLatin1Char('/') + basePath + prefix + baseName + suffix;
|
||||
if (debug)
|
||||
qDebug() << "Trying..." << fn;
|
||||
if (QFileInfo(fn).isFile())
|
||||
return fn;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (debug)
|
||||
qDebug() << fileName << "not found";
|
||||
return QString();
|
||||
}
|
||||
|
||||
/*!
|
||||
\property QPluginLoader::fileName
|
||||
\brief the file name of the plugin
|
||||
|
||||
To be loadable, the file's suffix must be a valid suffix for a
|
||||
loadable library in accordance with the platform, e.g. \c .so on
|
||||
Unix, \c .dylib on Mac OS X, and \c .dll on Windows. The suffix
|
||||
can be verified with QLibrary::isLibrary().
|
||||
We recommend omitting the file's suffix in the file name, since
|
||||
QPluginLoader will automatically look for the file with the appropriate
|
||||
suffix (see QLibrary::isLibrary()).
|
||||
|
||||
When loading the plugin, QPluginLoader searches in the current directory and
|
||||
in all plugin locations specified by QCoreApplication::libraryPaths(),
|
||||
unless the file name has an absolute path. After loading the plugin
|
||||
successfully, fileName() returns the fully-qualified file name of
|
||||
the plugin, including the full path to the plugin if one was given
|
||||
in the constructor or passed to setFileName().
|
||||
|
||||
If the file name does not exist, it will not be set. This property
|
||||
will then contain an empty string.
|
||||
@ -277,7 +316,12 @@ void QPluginLoader::setFileName(const QString &fileName)
|
||||
did_load = false;
|
||||
}
|
||||
|
||||
QString fn = QFileInfo(fileName).canonicalFilePath();
|
||||
QFileInfo fi(fileName);
|
||||
QString fn;
|
||||
if (fi.isAbsolute())
|
||||
fn = fi.canonicalFilePath();
|
||||
else
|
||||
fn = locatePlugin(fileName);
|
||||
|
||||
d = QLibraryPrivate::findOrCreate(fn);
|
||||
d->loadHints = lh;
|
||||
|
@ -4,6 +4,7 @@ HEADERS = almostplugin.h
|
||||
SOURCES = almostplugin.cpp
|
||||
TARGET = almostplugin
|
||||
DESTDIR = ../bin
|
||||
QT = core
|
||||
*-g++*:QMAKE_LFLAGS -= -Wl,--no-undefined
|
||||
|
||||
# This is testdata for the tst_qpluginloader test.
|
||||
|
@ -2,8 +2,11 @@ TEMPLATE = lib
|
||||
CONFIG += plugin
|
||||
HEADERS = theplugin.h
|
||||
SOURCES = theplugin.cpp
|
||||
TARGET = $$qtLibraryTarget(theplugin)
|
||||
# Use a predictable name for the plugin, no debug extension. Just like most apps do.
|
||||
#TARGET = $$qtLibraryTarget(theplugin)
|
||||
TARGET = theplugin
|
||||
DESTDIR = ../bin
|
||||
QT = core
|
||||
|
||||
# This is testdata for the tst_qpluginloader test.
|
||||
target.path = $$[QT_INSTALL_TESTS]/tst_qpluginloader/bin
|
||||
|
@ -4,6 +4,7 @@ TARGET = ../tst_qpluginloader
|
||||
QT = core testlib
|
||||
SOURCES = ../tst_qpluginloader.cpp
|
||||
HEADERS = ../theplugin/plugininterface.h
|
||||
CONFIG -= app_bundle
|
||||
|
||||
win32 {
|
||||
CONFIG(debug, debug|release) {
|
||||
|
@ -59,7 +59,11 @@
|
||||
# define bundle_VALID true
|
||||
# define dylib_VALID true
|
||||
# define so_VALID true
|
||||
# define SUFFIX ".dylib"
|
||||
//# ifdef QT_NO_DEBUG
|
||||
# define SUFFIX ".dylib"
|
||||
//# else
|
||||
//# define SUFFIX "_debug.dylib"
|
||||
//#endif
|
||||
# define PREFIX "lib"
|
||||
|
||||
#elif defined(Q_OS_HPUX) && !defined(__ia64)
|
||||
@ -79,11 +83,11 @@
|
||||
#elif defined(Q_OS_WIN)
|
||||
# undef dll_VALID
|
||||
# define dll_VALID true
|
||||
# ifdef QT_NO_DEBUG
|
||||
//# ifdef QT_NO_DEBUG
|
||||
# define SUFFIX ".dll"
|
||||
# else
|
||||
# define SUFFIX "d.dll"
|
||||
# endif
|
||||
//# else
|
||||
//# define SUFFIX "d.dll"
|
||||
//# endif
|
||||
# define PREFIX ""
|
||||
|
||||
#else // all other Unix
|
||||
@ -111,6 +115,7 @@ private slots:
|
||||
#if defined (Q_OS_UNIX)
|
||||
void loadGarbage();
|
||||
#endif
|
||||
void relativePath();
|
||||
void reloadPlugin();
|
||||
};
|
||||
|
||||
@ -294,6 +299,20 @@ void tst_QPluginLoader::loadGarbage()
|
||||
}
|
||||
#endif
|
||||
|
||||
void tst_QPluginLoader::relativePath()
|
||||
{
|
||||
// Windows binaries run from release and debug subdirs, so we can't rely on the current dir.
|
||||
const QString binDir = QFINDTESTDATA("bin");
|
||||
QVERIFY(!binDir.isEmpty());
|
||||
QCoreApplication::addLibraryPath(binDir);
|
||||
QPluginLoader loader("theplugin");
|
||||
loader.load(); // not recommended, instance() should do the job.
|
||||
PluginInterface *instance = qobject_cast<PluginInterface*>(loader.instance());
|
||||
QVERIFY(instance);
|
||||
QCOMPARE(instance->pluginName(), QLatin1String("Plugin ok"));
|
||||
QVERIFY(loader.unload());
|
||||
}
|
||||
|
||||
void tst_QPluginLoader::reloadPlugin()
|
||||
{
|
||||
QPluginLoader loader;
|
||||
|
Loading…
x
Reference in New Issue
Block a user