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 <alexandru.croitor@qt.io>
This commit is contained in:
Fabian Kosmale 2024-05-16 16:34:50 +02:00
parent f65d11ecbf
commit ef2912334c
6 changed files with 104 additions and 44 deletions

View File

@ -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<QString> ret;
bool fromConf = false;
#if QT_CONFIG(settings)
if (havePaths()) {
fromConf = true;
QVariant value = libraryPathToValue(loc);
if (value.isValid()) {
if (auto *asList = get_if<QList<QString>>(&value))
ret = std::move(*asList);
else
ret = QList<QString>({ 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());
}
/*!

View File

@ -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()")

View File

@ -50,6 +50,7 @@ public:
};
static QString path(QLibraryInfo::LibraryPath p, UsageMode usageMode = RegularUsage);
static QList<QString> paths(QLibraryInfo::LibraryPath p, UsageMode usageMode = RegularUsage);
};
QT_END_NAMESPACE

View File

@ -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
)

View File

@ -0,0 +1,2 @@
[Paths]
Documentation = "/path/to/mydoc","/path/to/anotherdoc","relativePath"

View File

@ -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<QString> 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)