diff options
author | Ulf Hermann <ulf.hermann@theqtcompany.com> | 2015-03-09 13:45:44 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@theqtcompany.com> | 2015-07-20 15:57:07 +0000 |
commit | ee0fd8700724848e73c228d973bf72e246077d07 (patch) | |
tree | 9ebf56c9e242be2823b1d6d3bcaa668eb40ea72c /src/corelib/kernel/qcoreapplication.cpp | |
parent | 49fee77ccc68424758823dd2579e731e4ef4073f (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.cpp | 117 |
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(); } |