summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qcoreapplication.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@theqtcompany.com>2015-03-09 13:45:44 +0100
committerUlf Hermann <ulf.hermann@theqtcompany.com>2015-07-20 15:57:07 +0000
commitee0fd8700724848e73c228d973bf72e246077d07 (patch)
tree9ebf56c9e242be2823b1d6d3bcaa668eb40ea72c /src/corelib/kernel/qcoreapplication.cpp
parent49fee77ccc68424758823dd2579e731e4ef4073f (diff)
Selectively update library paths when creating QCoreApplication
We force a recreation of the library paths with added information on construction of QCoreApplication. This way we can find plugins in the application directory which only becomes known when QCoreApplication is created. When the user changes the library path we create a new list of the manually modified library paths and recalculate it from the delta of original vs. modified paths when QCoreApplication is created. The upsides of this approach vs. keeping an explicit delta are: * We don't need to introduce a separate data structure to hold the added/removed status for delta items or the information that the whole list got replaced. * The lists never get larger than the the real library paths. An explicit delta would have to record all modifications. * I don't think the delta replay algorithm we would have to do anyway could be made much more compact than the one this change introduces. Of course, if the user actually changes anything, the list is duplicated. Considering that this is a rarely used function and that we would have to save some extra information anyway, I think we can live with this. Task-number: QTBUG-38598 Change-Id: I3bfbbd1be62dd5804dcc7ac808b053428a4e3149 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/kernel/qcoreapplication.cpp')
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp117
1 files changed, 98 insertions, 19 deletions
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index 9ad7970807..6ce42fe59b 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -325,12 +325,14 @@ struct QCoreApplicationData {
QCoreApplicationData() Q_DECL_NOTHROW {
#ifndef QT_NO_LIBRARY
app_libpaths = 0;
+ manual_libpaths = 0;
#endif
applicationNameSet = false;
}
~QCoreApplicationData() {
#ifndef QT_NO_LIBRARY
delete app_libpaths;
+ delete manual_libpaths;
#endif
#ifndef QT_NO_QOBJECT
// cleanup the QAdoptedThread created for the main() thread
@@ -376,6 +378,7 @@ struct QCoreApplicationData {
#ifndef QT_NO_LIBRARY
QStringList *app_libpaths;
+ QStringList *manual_libpaths;
#endif
};
@@ -767,6 +770,38 @@ void QCoreApplication::init()
QLoggingRegistry::instance()->init();
+#ifndef QT_NO_LIBRARY
+ // Reset the lib paths, so that they will be recomputed, taking the availability of argv[0]
+ // into account. If necessary, recompute right away and replay the manual changes on top of the
+ // new lib paths.
+ QStringList *appPaths = coreappdata()->app_libpaths;
+ QStringList *manualPaths = coreappdata()->manual_libpaths;
+ if (appPaths) {
+ coreappdata()->app_libpaths = 0;
+ if (manualPaths) {
+ // Replay the delta. As paths can only be prepended to the front or removed from
+ // anywhere in the list, we can just linearly scan the lists and find the items that
+ // have been removed. Once the original list is exhausted we know all the remaining
+ // items have been added.
+ coreappdata()->manual_libpaths = 0;
+ QStringList newPaths(libraryPaths());
+ for (int i = manualPaths->length(), j = appPaths->length(); i > 0 || j > 0; qt_noop()) {
+ if (--j < 0) {
+ newPaths.prepend((*manualPaths)[--i]);
+ } else if (--i < 0) {
+ newPaths.removeAll((*appPaths)[j]);
+ } else if ((*manualPaths)[i] != (*appPaths)[j]) {
+ newPaths.removeAll((*appPaths)[j]);
+ ++i; // try again with next item.
+ }
+ }
+ delete manualPaths;
+ coreappdata()->manual_libpaths = new QStringList(newPaths);
+ }
+ delete appPaths;
+ }
+#endif
+
#ifndef QT_NO_QOBJECT
// use the event dispatcher created by the app programmer (if any)
if (!QCoreApplicationPrivate::eventDispatcher)
@@ -785,11 +820,6 @@ void QCoreApplication::init()
d->eventDispatcherReady();
#endif
-#ifndef QT_NO_LIBRARY
- if (coreappdata()->app_libpaths)
- d->appendApplicationPathToLibraryPaths();
-#endif
-
#ifdef QT_EVAL
extern void qt_core_eval_init(QCoreApplicationPrivate::Type);
qt_core_eval_init(d->application_type);
@@ -844,6 +874,8 @@ QCoreApplication::~QCoreApplication()
#ifndef QT_NO_LIBRARY
delete coreappdata()->app_libpaths;
coreappdata()->app_libpaths = 0;
+ delete coreappdata()->manual_libpaths;
+ coreappdata()->manual_libpaths = 0;
#endif
}
@@ -2503,6 +2535,10 @@ Q_GLOBAL_STATIC_WITH_ARGS(QMutex, libraryPathMutex, (QMutex::Recursive))
QStringList QCoreApplication::libraryPaths()
{
QMutexLocker locker(libraryPathMutex());
+
+ if (coreappdata()->manual_libpaths)
+ return *(coreappdata()->manual_libpaths);
+
if (!coreappdata()->app_libpaths) {
QStringList *app_libpaths = coreappdata()->app_libpaths = new QStringList;
QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath);
@@ -2545,14 +2581,25 @@ QStringList QCoreApplication::libraryPaths()
\a paths. All existing paths will be deleted and the path list
will consist of the paths given in \a paths.
+ The library paths are reset to the default when an instance of
+ QCoreApplication is destructed.
+
\sa libraryPaths(), addLibraryPath(), removeLibraryPath(), QLibrary
*/
void QCoreApplication::setLibraryPaths(const QStringList &paths)
{
QMutexLocker locker(libraryPathMutex());
+
+ // setLibraryPaths() is considered a "remove everything and then add some new ones" operation.
+ // When the application is constructed it should still amend the paths. So we keep the originals
+ // around, and even create them if they don't exist, yet.
if (!coreappdata()->app_libpaths)
- coreappdata()->app_libpaths = new QStringList;
- *(coreappdata()->app_libpaths) = paths;
+ libraryPaths();
+
+ if (!coreappdata()->manual_libpaths)
+ coreappdata()->manual_libpaths = new QStringList;
+ *(coreappdata()->manual_libpaths) = paths;
+
locker.unlock();
QFactoryLoader::refreshAll();
}
@@ -2567,6 +2614,9 @@ void QCoreApplication::setLibraryPaths(const QStringList &paths)
is \c INSTALL/plugins, where \c INSTALL is the directory where Qt was
installed.
+ The library paths are reset to the default when an instance of
+ QCoreApplication is destructed.
+
\sa removeLibraryPath(), libraryPaths(), setLibraryPaths()
*/
void QCoreApplication::addLibraryPath(const QString &path)
@@ -2574,24 +2624,38 @@ void QCoreApplication::addLibraryPath(const QString &path)
if (path.isEmpty())
return;
+ QString canonicalPath = QDir(path).canonicalPath();
+ if (canonicalPath.isEmpty())
+ return;
+
QMutexLocker locker(libraryPathMutex());
- // make sure that library paths is initialized
- libraryPaths();
+ QStringList *libpaths = coreappdata()->manual_libpaths;
+ if (libpaths) {
+ if (libpaths->contains(canonicalPath))
+ return;
+ } else {
+ // make sure that library paths are initialized
+ libraryPaths();
+ QStringList *app_libpaths = coreappdata()->app_libpaths;
+ if (app_libpaths->contains(canonicalPath))
+ return;
- QString canonicalPath = QDir(path).canonicalPath();
- if (!canonicalPath.isEmpty()
- && !coreappdata()->app_libpaths->contains(canonicalPath)) {
- coreappdata()->app_libpaths->prepend(canonicalPath);
- locker.unlock();
- QFactoryLoader::refreshAll();
+ libpaths = coreappdata()->manual_libpaths = new QStringList(*app_libpaths);
}
+
+ libpaths->prepend(canonicalPath);
+ locker.unlock();
+ QFactoryLoader::refreshAll();
}
/*!
Removes \a path from the library path list. If \a path is empty or not
in the path list, the list is not changed.
+ The library paths are reset to the default when an instance of
+ QCoreApplication is destructed.
+
\sa addLibraryPath(), libraryPaths(), setLibraryPaths()
*/
void QCoreApplication::removeLibraryPath(const QString &path)
@@ -2599,13 +2663,28 @@ void QCoreApplication::removeLibraryPath(const QString &path)
if (path.isEmpty())
return;
+ QString canonicalPath = QDir(path).canonicalPath();
+ if (canonicalPath.isEmpty())
+ return;
+
QMutexLocker locker(libraryPathMutex());
- // make sure that library paths is initialized
- libraryPaths();
+ QStringList *libpaths = coreappdata()->manual_libpaths;
+ if (libpaths) {
+ if (libpaths->removeAll(canonicalPath) == 0)
+ return;
+ } else {
+ // make sure that library paths is initialized
+ libraryPaths();
+ QStringList *app_libpaths = coreappdata()->app_libpaths;
+ if (!app_libpaths->contains(canonicalPath))
+ return;
- QString canonicalPath = QDir(path).canonicalPath();
- coreappdata()->app_libpaths->removeAll(canonicalPath);
+ libpaths = coreappdata()->manual_libpaths = new QStringList(*app_libpaths);
+ libpaths->removeAll(canonicalPath);
+ }
+
+ locker.unlock();
QFactoryLoader::refreshAll();
}