From ef2912334cc71588d4af6d68a715f95ef684b0b9 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Thu, 16 May 2024 16:34:50 +0200 Subject: [PATCH] QLibraryInfo: Introduce paths QLibraryInfo::path only allows a single value, however, at least for QmlImportsPath we would benefit from having more than one to ease deployment (note that this is unrelated to Qml2ImportsPath which was necessary to support QML 1 and 2 in a single Qt install). Users inside Qt will ported in follow-up patches where it makes sense. [ChangeLog][QLibraryInfo] qt.conf now allows providing mutliple paths, and QLibraryInfo has a new paths method to fetch all of them. Task-number: QTBUG-124009 Change-Id: I78b3bcfa94c8d975dbd789f6826cda4fc5e60403 Reviewed-by: Alexandru Croitor --- src/corelib/global/qlibraryinfo.cpp | 117 +++++++++++------- src/corelib/global/qlibraryinfo.h | 1 + src/corelib/global/qlibraryinfo_p.h | 1 + .../global/qlibraryinfo/CMakeLists.txt | 8 +- .../corelib/global/qlibraryinfo/list.qt.conf | 2 + .../global/qlibraryinfo/tst_qlibraryinfo.cpp | 19 +++ 6 files changed, 104 insertions(+), 44 deletions(-) create mode 100644 tests/auto/corelib/global/qlibraryinfo/list.qt.conf diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp index a71387287ff..4d0ce966970 100644 --- a/src/corelib/global/qlibraryinfo.cpp +++ b/src/corelib/global/qlibraryinfo.cpp @@ -516,12 +516,27 @@ QLibraryInfoPrivate::LocationInfo QLibraryInfoPrivate::locationInfo(QLibraryInfo /*! \since 6.0 Returns the path specified by \a p. + + If there is more than one path listed in qt.conf, it will + only return the first one. + \sa paths */ QString QLibraryInfo::path(LibraryPath p) { return QLibraryInfoPrivate::path(p); } +/*! + \since 6.8 + Returns all paths specificied by \a p. + + \sa path + */ +QStringList QLibraryInfo::paths(LibraryPath p) +{ + return QLibraryInfoPrivate::paths(p); +} + static QString normalizePath(QString ret) { @@ -573,6 +588,64 @@ static QVariant libraryPathToValue(QLibraryInfo::LibraryPath loc) } #endif // settings +QStringList QLibraryInfoPrivate::paths(QLibraryInfo::LibraryPath p, + QLibraryInfoPrivate::UsageMode usageMode) +{ + const QLibraryInfo::LibraryPath loc = p; + QList ret; + bool fromConf = false; +#if QT_CONFIG(settings) + if (havePaths()) { + fromConf = true; + + QVariant value = libraryPathToValue(loc); + if (value.isValid()) { + + if (auto *asList = get_if>(&value)) + ret = std::move(*asList); + else + ret = QList({ std::move(value).toString()}); + for (qsizetype i = 0, end = ret.size(); i < end; ++i) + ret[i] = normalizePath(ret[i]); + } + } +#endif // settings + + if (!fromConf) { + QString noConfResult; + if (loc == QLibraryInfo::PrefixPath) { + noConfResult = getPrefix(usageMode); + } else if (int(loc) <= qt_configure_strs.count()) { + noConfResult = QString::fromLocal8Bit(qt_configure_strs.viewAt(loc - 1)); +#ifndef Q_OS_WIN // On Windows we use the registry + } else if (loc == QLibraryInfo::SettingsPath) { + // Use of volatile is a hack to discourage compilers from calling + // strlen(), in the inlined fromLocal8Bit(const char *)'s body, at + // compile-time, as Qt installers binary-patch the path, replacing + // the dummy path seen at compile-time, typically changing length. + const char *volatile path = QT_CONFIGURE_SETTINGS_PATH; + noConfResult = QString::fromLocal8Bit(path); +#endif + } + if (!noConfResult.isEmpty()) + ret.push_back(std::move(noConfResult)); + } + if (ret.isEmpty()) + return ret; + + QString baseDir; + if (loc == QLibraryInfo::PrefixPath) { + baseDir = prefixFromAppDirHelper(); + } else { + // we make any other path absolute to the prefix directory + baseDir = QLibraryInfoPrivate::path(QLibraryInfo::PrefixPath, usageMode); + } + for (qsizetype i = 0, end = ret.size(); i < end; ++i) + if (QDir::isRelativePath(ret[i])) + ret[i] = QDir::cleanPath(baseDir + u'/' + std::move(ret[i])); + return ret; +} + /* Returns the path specified by \a p. @@ -581,49 +654,7 @@ static QVariant libraryPathToValue(QLibraryInfo::LibraryPath loc) */ QString QLibraryInfoPrivate::path(QLibraryInfo::LibraryPath p, UsageMode usageMode) { - const QLibraryInfo::LibraryPath loc = p; - QString ret; - bool fromConf = false; -#if QT_CONFIG(settings) - if (havePaths()) { - fromConf = true; - - QVariant value = libraryPathToValue(loc); - if (value.isValid()) { - ret = std::move(value).toString(); - ret = normalizePath(std::move(ret)); - } - } -#endif // settings - - if (!fromConf) { - if (loc == QLibraryInfo::PrefixPath) { - ret = getPrefix(usageMode); - } else if (int(loc) <= qt_configure_strs.count()) { - ret = QString::fromLocal8Bit(qt_configure_strs.viewAt(loc - 1)); -#ifndef Q_OS_WIN // On Windows we use the registry - } else if (loc == QLibraryInfo::SettingsPath) { - // Use of volatile is a hack to discourage compilers from calling - // strlen(), in the inlined fromLocal8Bit(const char *)'s body, at - // compile-time, as Qt installers binary-patch the path, replacing - // the dummy path seen at compile-time, typically changing length. - const char *volatile path = QT_CONFIGURE_SETTINGS_PATH; - ret = QString::fromLocal8Bit(path); -#endif - } - } - - if (!ret.isEmpty() && QDir::isRelativePath(ret)) { - QString baseDir; - if (loc == QLibraryInfo::PrefixPath) { - baseDir = prefixFromAppDirHelper(); - } else { - // we make any other path absolute to the prefix directory - baseDir = path(QLibraryInfo::PrefixPath, usageMode); - } - ret = QDir::cleanPath(baseDir + u'/' + ret); - } - return ret; + return paths(p, usageMode).value(0, QString()); } /*! diff --git a/src/corelib/global/qlibraryinfo.h b/src/corelib/global/qlibraryinfo.h index d4e8f8b0506..6cac6c83b03 100644 --- a/src/corelib/global/qlibraryinfo.h +++ b/src/corelib/global/qlibraryinfo.h @@ -42,6 +42,7 @@ public: SettingsPath = 100 }; static QString path(LibraryPath p); + static QStringList paths(LibraryPath p); #if QT_DEPRECATED_SINCE(6, 0) using LibraryLocation = LibraryPath; QT_DEPRECATED_VERSION_X_6_0("Use path()") diff --git a/src/corelib/global/qlibraryinfo_p.h b/src/corelib/global/qlibraryinfo_p.h index 4b471b932e5..b9ca6b4d18d 100644 --- a/src/corelib/global/qlibraryinfo_p.h +++ b/src/corelib/global/qlibraryinfo_p.h @@ -50,6 +50,7 @@ public: }; static QString path(QLibraryInfo::LibraryPath p, UsageMode usageMode = RegularUsage); + static QList paths(QLibraryInfo::LibraryPath p, UsageMode usageMode = RegularUsage); }; QT_END_NAMESPACE diff --git a/tests/auto/corelib/global/qlibraryinfo/CMakeLists.txt b/tests/auto/corelib/global/qlibraryinfo/CMakeLists.txt index 18642c6838c..33198dd3f04 100644 --- a/tests/auto/corelib/global/qlibraryinfo/CMakeLists.txt +++ b/tests/auto/corelib/global/qlibraryinfo/CMakeLists.txt @@ -14,4 +14,10 @@ qt_internal_add_test(tst_qlibraryinfo SOURCES tst_qlibraryinfo.cpp ) -qt_add_resources(tst_qlibraryinfo "qtconffiles" PREFIX "/" FILES empty.qt.conf partial.qt.conf) +qt_add_resources(tst_qlibraryinfo "qtconffiles" + PREFIX "/" + FILES + empty.qt.conf + partial.qt.conf + list.qt.conf +) diff --git a/tests/auto/corelib/global/qlibraryinfo/list.qt.conf b/tests/auto/corelib/global/qlibraryinfo/list.qt.conf new file mode 100644 index 00000000000..9271b414ca3 --- /dev/null +++ b/tests/auto/corelib/global/qlibraryinfo/list.qt.conf @@ -0,0 +1,2 @@ +[Paths] +Documentation = "/path/to/mydoc","/path/to/anotherdoc","relativePath" diff --git a/tests/auto/corelib/global/qlibraryinfo/tst_qlibraryinfo.cpp b/tests/auto/corelib/global/qlibraryinfo/tst_qlibraryinfo.cpp index 1224652bf19..63b5cddcb02 100644 --- a/tests/auto/corelib/global/qlibraryinfo/tst_qlibraryinfo.cpp +++ b/tests/auto/corelib/global/qlibraryinfo/tst_qlibraryinfo.cpp @@ -15,6 +15,7 @@ private slots: void cleanup(); void path_data(); void path(); + void paths(); }; void tst_QLibraryInfo::initTestCase() @@ -59,6 +60,24 @@ void tst_QLibraryInfo::path() QString value = QLibraryInfo::path(path); QCOMPARE(value, expected); + // check consistency with paths + auto values = QLibraryInfo::paths(path); + QVERIFY(!values.isEmpty()); + QCOMPARE(values.first(), expected); +} + +void tst_QLibraryInfo::paths() +{ + QString qtConfPath(u":/list.qt.conf"); + QLibraryInfoPrivate::setQtconfManualPath(&qtConfPath); + QLibraryInfoPrivate::reload(); + + QList values = QLibraryInfo::paths(QLibraryInfo::DocumentationPath); + QCOMPARE(values.length(), 3); + QCOMPARE(values[0], "/path/to/mydoc"); + QCOMPARE(values[1], "/path/to/anotherdoc"); + QString baseDir = QCoreApplication::applicationDirPath(); + QCOMPARE(values[2], baseDir + "/relativePath"); } QTEST_GUILESS_MAIN(tst_QLibraryInfo)