summaryrefslogtreecommitdiffstats
path: root/qmake/qmakelibraryinfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'qmake/qmakelibraryinfo.cpp')
-rw-r--r--qmake/qmakelibraryinfo.cpp273
1 files changed, 273 insertions, 0 deletions
diff --git a/qmake/qmakelibraryinfo.cpp b/qmake/qmakelibraryinfo.cpp
new file mode 100644
index 0000000000..a840036613
--- /dev/null
+++ b/qmake/qmakelibraryinfo.cpp
@@ -0,0 +1,273 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "qmakelibraryinfo.h"
+
+#include <qdir.h>
+#include <qfile.h>
+#include <qglobalstatic.h>
+#include <qsettings.h>
+#include <qscopedpointer.h>
+#include <qstringlist.h>
+#include <private/qlibraryinfo_p.h>
+
+#include <utility>
+
+QT_BEGIN_NAMESPACE
+
+struct QMakeLibrarySettings
+{
+ QMakeLibrarySettings() { load(); }
+ void load();
+
+ bool haveDevicePaths;
+ bool haveEffectiveSourcePaths;
+ bool haveEffectivePaths;
+ bool havePaths;
+};
+Q_GLOBAL_STATIC(QMakeLibrarySettings, qmake_library_settings)
+
+void QMakeLibrarySettings::load()
+{
+ QSettings *settings = QLibraryInfoPrivate::configuration();
+ if (settings) {
+ QStringList children = settings->childGroups();
+ haveDevicePaths = children.contains(QLatin1String("DevicePaths"));
+ haveEffectiveSourcePaths = children.contains(QLatin1String("EffectiveSourcePaths"));
+ haveEffectivePaths =
+ haveEffectiveSourcePaths || children.contains(QLatin1String("EffectivePaths"));
+ // Backwards compat: an existing but empty file is claimed to contain the Paths section.
+ havePaths = (!haveDevicePaths && !haveEffectivePaths
+ && !children.contains(QLatin1String("Platforms")))
+ || children.contains(QLatin1String("Paths"));
+ } else {
+ haveDevicePaths = false;
+ haveEffectiveSourcePaths = false;
+ haveEffectivePaths = false;
+ havePaths = false;
+ }
+}
+
+void QMakeLibraryInfo::reload()
+{
+ QLibraryInfoPrivate::reload();
+ if (qmake_library_settings.exists())
+ qmake_library_settings->load();
+}
+
+bool QMakeLibraryInfo::haveGroup(PathGroup group)
+{
+ QMakeLibrarySettings *ls = qmake_library_settings();
+ return ls
+ && (group == EffectiveSourcePaths ? ls->haveEffectiveSourcePaths
+ : group == EffectivePaths ? ls->haveEffectivePaths
+ : group == DevicePaths ? ls->haveDevicePaths
+ : ls->havePaths);
+}
+
+void QMakeLibraryInfo::sysrootify(QString &path)
+{
+ // Acceptable values for SysrootifyPrefixPath are "true" and "false"
+ if (!QVariant::fromValue(rawLocation(SysrootifyPrefixPath, FinalPaths)).toBool())
+ return;
+
+ const QString sysroot = rawLocation(SysrootPath, FinalPaths);
+ if (sysroot.isEmpty())
+ return;
+
+ if (path.size() > 2 && path.at(1) == QLatin1Char(':')
+ && (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\'))) {
+ path.replace(0, 2, sysroot); // Strip out the drive on Windows targets
+ } else {
+ path.prepend(sysroot);
+ }
+}
+
+QString QMakeLibraryInfo::path(int loc)
+{
+ QString ret = rawLocation(loc, QMakeLibraryInfo::FinalPaths);
+
+ // Automatically prepend the sysroot to target paths
+ if (loc < QMakeLibraryInfo::FirstHostPath)
+ sysrootify(ret);
+
+ return ret;
+}
+
+static QLibraryInfo::LibraryPath hostToTargetPathEnum(int loc)
+{
+ static std::pair<int, QLibraryInfo::LibraryPath> mapping[] = {
+ { QMakeLibraryInfo::HostBinariesPath, QLibraryInfo::BinariesPath },
+ { QMakeLibraryInfo::HostLibraryExecutablesPath, QLibraryInfo::LibraryExecutablesPath },
+ { QMakeLibraryInfo::HostLibrariesPath, QLibraryInfo::LibrariesPath },
+ { QMakeLibraryInfo::HostDataPath, QLibraryInfo::DataPath },
+ { QMakeLibraryInfo::HostPrefixPath, QLibraryInfo::PrefixPath }
+ };
+ for (size_t i = 0; i < sizeof(mapping) / sizeof(mapping[0]); ++i) {
+ if (mapping[i].first == loc)
+ return mapping[i].second;
+ }
+ qFatal("Unhandled host path %d in hostToTargetPathEnum.", loc);
+ Q_UNREACHABLE();
+}
+
+static QLibraryInfoPrivate::LocationInfo defaultLocationInfo(int loc)
+{
+ QLibraryInfoPrivate::LocationInfo result;
+
+ if (loc < QMakeLibraryInfo::FirstHostPath) {
+ result = QLibraryInfoPrivate::locationInfo(static_cast<QLibraryInfo::LibraryPath>(loc));
+ } else if (loc <= QMakeLibraryInfo::LastHostPath) {
+ result = QLibraryInfoPrivate::locationInfo(hostToTargetPathEnum(loc));
+ result.key.prepend(QStringLiteral("Host"));
+ } else if (loc == QMakeLibraryInfo::SysrootPath) {
+ result.key = QStringLiteral("Sysroot");
+ } else if (loc == QMakeLibraryInfo::SysrootifyPrefixPath) {
+ result.key = QStringLiteral("SysrootifyPrefix");
+ } else if (loc == QMakeLibraryInfo::TargetSpecPath) {
+ result.key = QStringLiteral("TargetSpec");
+ } else if (loc == QMakeLibraryInfo::HostSpecPath) {
+ result.key = QStringLiteral("HostSpec");
+ }
+ return result;
+}
+
+static QString libraryInfoPath(QLibraryInfo::LibraryPath location)
+{
+ return QLibraryInfoPrivate::path(location, QLibraryInfoPrivate::UsedFromQtBinDir);
+}
+
+static QString storedPath(int loc)
+{
+ QString result;
+ if (loc < QMakeLibraryInfo::FirstHostPath) {
+ result = libraryInfoPath(static_cast<QLibraryInfo::LibraryPath>(loc));
+ } else if (loc <= QMakeLibraryInfo::LastHostPath) {
+ if (loc == QMakeLibraryInfo::HostDataPath) {
+ // Handle QT_HOST_DATADIR specially. It is not necessarily equal to QT_INSTALL_DATA.
+ result = QT_HOST_DATADIR;
+ } else {
+ result = libraryInfoPath(hostToTargetPathEnum(loc));
+ }
+ } else if (loc == QMakeLibraryInfo::SysrootPath) {
+ // empty result
+ } else if (loc == QMakeLibraryInfo::SysrootifyPrefixPath) {
+ result = QStringLiteral("false");
+ } else if (loc == QMakeLibraryInfo::TargetSpecPath) {
+ result = QT_TARGET_MKSPEC;
+ } else if (loc == QMakeLibraryInfo::HostSpecPath) {
+ result = QT_HOST_MKSPEC;
+ }
+ return result;
+}
+
+QString QMakeLibraryInfo::rawLocation(int loc, QMakeLibraryInfo::PathGroup group)
+{
+ QString ret;
+ bool fromConf = false;
+ // Logic for choosing the right data source: if EffectivePaths are requested
+ // and qt.conf with that section is present, use it, otherwise fall back to
+ // FinalPaths. For FinalPaths, use qt.conf if present and contains not only
+ // [EffectivePaths], otherwise fall back to builtins.
+ // EffectiveSourcePaths falls back to EffectivePaths.
+ // DevicePaths falls back to FinalPaths.
+ PathGroup orig_group = group;
+ if (QMakeLibraryInfo::haveGroup(group)
+ || (group == EffectiveSourcePaths
+ && (group = EffectivePaths, QMakeLibraryInfo::haveGroup(group)))
+ || ((group == EffectivePaths || group == DevicePaths)
+ && (group = FinalPaths, QMakeLibraryInfo::haveGroup(group)))
+ || (group = orig_group, false)) {
+ fromConf = true;
+
+ QLibraryInfoPrivate::LocationInfo locinfo = defaultLocationInfo(loc);
+ if (!locinfo.key.isNull()) {
+ QSettings *config = QLibraryInfoPrivate::configuration();
+ Q_ASSERT(config != nullptr);
+ config->beginGroup(QLatin1String(group == DevicePaths ? "DevicePaths"
+ : group == EffectiveSourcePaths
+ ? "EffectiveSourcePaths"
+ : group == EffectivePaths ? "EffectivePaths"
+ : "Paths"));
+
+ if (locinfo.fallbackKey.isNull()) {
+ ret = config->value(locinfo.key).toString();
+ } else {
+ QVariant v = config->value(locinfo.key);
+ if (!v.isValid())
+ v = config->value(locinfo.fallbackKey);
+ ret = v.toString();
+ }
+
+ if (ret.isEmpty()) {
+ if (loc == HostPrefixPath || loc == TargetSpecPath || loc == HostSpecPath
+ || loc == SysrootifyPrefixPath || loc == QLibraryInfo::PrefixPath) {
+ fromConf = false;
+ } else {
+ ret = locinfo.defaultValue;
+ }
+ // The last case here is SysrootPath, which can be legitimately empty.
+ // All other keys have non-empty fallbacks to start with.
+ }
+
+ // TODO: Might be replaced by common for qmake and qtcore function
+ int startIndex = 0;
+ forever {
+ startIndex = ret.indexOf(QLatin1Char('$'), startIndex);
+ if (startIndex < 0)
+ break;
+ if (ret.size() < startIndex + 3)
+ break;
+ if (ret.at(startIndex + 1) != QLatin1Char('(')) {
+ startIndex++;
+ continue;
+ }
+ int endIndex = ret.indexOf(QLatin1Char(')'), startIndex + 2);
+ if (endIndex < 0)
+ break;
+ auto envVarName =
+ QStringView { ret }.mid(startIndex + 2, endIndex - startIndex - 2);
+ QString value =
+ QString::fromLocal8Bit(qgetenv(envVarName.toLocal8Bit().constData()));
+ ret.replace(startIndex, endIndex - startIndex + 1, value);
+ startIndex += value.size();
+ }
+ config->endGroup();
+
+ ret = QDir::fromNativeSeparators(ret);
+ }
+ }
+
+ if (!fromConf)
+ ret = storedPath(loc);
+
+ // These values aren't actually paths and thus need to be returned verbatim.
+ if (loc == TargetSpecPath || loc == HostSpecPath || loc == SysrootifyPrefixPath)
+ return ret;
+
+ if (!ret.isEmpty() && QDir::isRelativePath(ret)) {
+ QString baseDir;
+ if (loc == HostPrefixPath || loc == QLibraryInfo::PrefixPath || loc == SysrootPath) {
+ // We make the prefix/sysroot path absolute to the executable's directory.
+ // loc == PrefixPath while a sysroot is set would make no sense here.
+ // loc == SysrootPath only makes sense if qmake lives inside the sysroot itself.
+ QSettings *config = QLibraryInfoPrivate::configuration();
+ if (config != nullptr) {
+ baseDir = QFileInfo(config->fileName()).absolutePath();
+ }
+ } else if (loc >= FirstHostPath && loc <= LastHostPath) {
+ // We make any other host path absolute to the host prefix directory.
+ baseDir = rawLocation(HostPrefixPath, group);
+ } else {
+ // we make any other path absolute to the prefix directory
+ baseDir = rawLocation(QLibraryInfo::PrefixPath, group);
+ if (group == EffectivePaths)
+ sysrootify(baseDir);
+ }
+ ret = QDir::cleanPath(baseDir + QLatin1Char('/') + ret);
+ }
+ return ret;
+}
+
+QT_END_NAMESPACE