forked from qt-creator/qt-creator
ProjectExplorer: Expose toolchain versions
... and use them as a possible criterion when comparing toolchains. Change-Id: I6053cc5915edd1e146405410ff82ee660fd84c53 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -31,7 +31,8 @@ public:
|
|||||||
class Parameters
|
class Parameters
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using OutputParser = std::function<std::optional<Data>(const QString &)>;
|
using OutputParser = std::function<
|
||||||
|
std::optional<Data>(const QString & /* stdOut */, const QString & /* stdErr */)>;
|
||||||
using ErrorHandler = std::function<void(const Process &)>;
|
using ErrorHandler = std::function<void(const Process &)>;
|
||||||
using Callback = std::function<void(const std::optional<Data> &)>;
|
using Callback = std::function<void(const std::optional<Data> &)>;
|
||||||
|
|
||||||
@@ -133,7 +134,7 @@ inline std::optional<Data> DataFromProcess<Data>::handleProcessFinished(
|
|||||||
|
|
||||||
std::optional<Data> data;
|
std::optional<Data> data;
|
||||||
if (params.allowedResults.contains(process->result()))
|
if (params.allowedResults.contains(process->result()))
|
||||||
data = params.parser(process->cleanedStdOut());
|
data = params.parser(process->cleanedStdOut(), process->cleanedStdErr());
|
||||||
else if (params.errorHandler)
|
else if (params.errorHandler)
|
||||||
params.errorHandler(*process);
|
params.errorHandler(*process);
|
||||||
QMutexLocker<QMutex> cacheLocker(&m_cacheMutex);
|
QMutexLocker<QMutex> cacheLocker(&m_cacheMutex);
|
||||||
|
@@ -107,9 +107,9 @@ bool BinaryVersionToolTipEventFilter::eventFilter(QObject *o, QEvent *e)
|
|||||||
QTC_ASSERT(le, return false);
|
QTC_ASSERT(le, return false);
|
||||||
|
|
||||||
const QString binary = le->text();
|
const QString binary = le->text();
|
||||||
DataFromProcess<QString>::Parameters params(CommandLine(FilePath::fromUserInput(binary),
|
DataFromProcess<QString>::Parameters params(
|
||||||
m_arguments),
|
CommandLine(FilePath::fromUserInput(binary), m_arguments),
|
||||||
[](const QString &output) { return output; });
|
[](const QString &output, const QString &) { return output; });
|
||||||
params.callback = [binary, self = QPointer(this),
|
params.callback = [binary, self = QPointer(this),
|
||||||
le = QPointer(le)](const std::optional<QString> &version) {
|
le = QPointer(le)](const std::optional<QString> &version) {
|
||||||
if (!self || !le)
|
if (!self || !le)
|
||||||
|
@@ -41,7 +41,8 @@ static QStringList queryClangTidyChecks(const FilePath &executable,
|
|||||||
// abseil-duration-division
|
// abseil-duration-division
|
||||||
// abseil-duration-factory-float
|
// abseil-duration-factory-float
|
||||||
// ...
|
// ...
|
||||||
static const auto parser = [](const QString &stdOut) -> std::optional<QStringList> {
|
static const auto parser = [](const QString &stdOut,
|
||||||
|
const QString &) -> std::optional<QStringList> {
|
||||||
QString output = stdOut;
|
QString output = stdOut;
|
||||||
QTextStream stream(&output);
|
QTextStream stream(&output);
|
||||||
QString line = stream.readLine();
|
QString line = stream.readLine();
|
||||||
@@ -85,7 +86,8 @@ static ClazyChecks querySupportedClazyChecks(const FilePath &executablePath)
|
|||||||
// ...
|
// ...
|
||||||
// ]
|
// ]
|
||||||
// }
|
// }
|
||||||
static const auto parser = [](const QString &jsonOutput) -> std::optional<ClazyChecks> {
|
static const auto parser = [](const QString &jsonOutput,
|
||||||
|
const QString &) -> std::optional<ClazyChecks> {
|
||||||
const QJsonDocument document = QJsonDocument::fromJson(jsonOutput.toUtf8());
|
const QJsonDocument document = QJsonDocument::fromJson(jsonOutput.toUtf8());
|
||||||
if (document.isNull())
|
if (document.isNull())
|
||||||
return {};
|
return {};
|
||||||
@@ -130,7 +132,8 @@ ClazyStandaloneInfo::ClazyStandaloneInfo(const FilePath &executablePath)
|
|||||||
: defaultChecks(queryClangTidyChecks(executablePath, {})) // Yup, behaves as clang-tidy.
|
: defaultChecks(queryClangTidyChecks(executablePath, {})) // Yup, behaves as clang-tidy.
|
||||||
, supportedChecks(querySupportedClazyChecks(executablePath))
|
, supportedChecks(querySupportedClazyChecks(executablePath))
|
||||||
{
|
{
|
||||||
static const auto parser = [](const QString &stdOut) -> std::optional<QVersionNumber> {
|
static const auto parser = [](const QString &stdOut,
|
||||||
|
const QString &) -> std::optional<QVersionNumber> {
|
||||||
QString output = stdOut;
|
QString output = stdOut;
|
||||||
QTextStream stream(&output);
|
QTextStream stream(&output);
|
||||||
while (!stream.atEnd()) {
|
while (!stream.atEnd()) {
|
||||||
@@ -157,7 +160,8 @@ static FilePath queryResourceDir(const FilePath &clangToolPath)
|
|||||||
// lib/clang/10.0.1
|
// lib/clang/10.0.1
|
||||||
// Error while trying to load a compilation database:
|
// Error while trying to load a compilation database:
|
||||||
// ...
|
// ...
|
||||||
const auto parser = [&clangToolPath](const QString &stdOut) -> std::optional<FilePath> {
|
const auto parser =
|
||||||
|
[&clangToolPath](const QString &stdOut, const QString &) -> std::optional<FilePath> {
|
||||||
QString output = stdOut;
|
QString output = stdOut;
|
||||||
QTextStream stream(&output);
|
QTextStream stream(&output);
|
||||||
const QString path = clangToolPath.parentDir().parentDir()
|
const QString path = clangToolPath.parentDir().parentDir()
|
||||||
@@ -180,7 +184,7 @@ static FilePath queryResourceDir(const FilePath &clangToolPath)
|
|||||||
|
|
||||||
QString queryVersion(const FilePath &clangToolPath, QueryFailMode failMode)
|
QString queryVersion(const FilePath &clangToolPath, QueryFailMode failMode)
|
||||||
{
|
{
|
||||||
static const auto parser = [](const QString &stdOut) -> std::optional<QString> {
|
static const auto parser = [](const QString &stdOut, const QString &) -> std::optional<QString> {
|
||||||
QString output = stdOut;
|
QString output = stdOut;
|
||||||
QTextStream stream(&output);
|
QTextStream stream(&output);
|
||||||
while (!stream.atEnd()) {
|
while (!stream.atEnd()) {
|
||||||
|
@@ -74,8 +74,8 @@ void GerritParameters::setPortFlagBySshType()
|
|||||||
{
|
{
|
||||||
bool isPlink = false;
|
bool isPlink = false;
|
||||||
if (!ssh.isEmpty()) {
|
if (!ssh.isEmpty()) {
|
||||||
DataFromProcess<QString>::Parameters params({ssh, {"-V"}},
|
DataFromProcess<QString>::Parameters
|
||||||
[](const QString &output) { return output; });
|
params({ssh, {"-V"}}, [](const QString &output, const QString &) { return output; });
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
params.timeout = 1s;
|
params.timeout = 1s;
|
||||||
if (const auto version = DataFromProcess<QString>::getData(params))
|
if (const auto version = DataFromProcess<QString>::getData(params))
|
||||||
|
@@ -390,6 +390,10 @@ GccToolchain::GccToolchain(Id typeId, SubType subType)
|
|||||||
setTypeDisplayName(Tr::tr("Clang"));
|
setTypeDisplayName(Tr::tr("Clang"));
|
||||||
syncAutodetectedWithParentToolchains();
|
syncAutodetectedWithParentToolchains();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setVersionFlagsAndParser({"-dumpversion"}, [](const QString &output, const QString &) {
|
||||||
|
return QVersionNumber::fromString(output.trimmed());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
GccToolchain::~GccToolchain()
|
GccToolchain::~GccToolchain()
|
||||||
|
@@ -852,6 +852,17 @@ MsvcToolchain::MsvcToolchain(Utils::Id typeId)
|
|||||||
setTypeDisplayName(Tr::tr("MSVC"));
|
setTypeDisplayName(Tr::tr("MSVC"));
|
||||||
addToAvailableMsvcToolchains(this);
|
addToAvailableMsvcToolchains(this);
|
||||||
setTargetAbiKey(KEY_ROOT "SupportedAbi");
|
setTargetAbiKey(KEY_ROOT "SupportedAbi");
|
||||||
|
setVersionFlagsAndParser({}, [](const QString &, const QString &stdErr) -> QVersionNumber {
|
||||||
|
const QString markerString = " Version ";
|
||||||
|
const int markerIndex = stdErr.indexOf(markerString);
|
||||||
|
if (markerIndex == -1)
|
||||||
|
return {};
|
||||||
|
const int versionOffset = markerIndex + markerString.size();
|
||||||
|
const int spaceIndex = stdErr.indexOf(' ', versionOffset);
|
||||||
|
if (spaceIndex == -1)
|
||||||
|
return {};
|
||||||
|
return QVersionNumber::fromString(stdErr.mid(versionOffset, spaceIndex - versionOffset));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MsvcToolchain::inferWarningsForLevel(int warningLevel, WarningFlags &flags)
|
void MsvcToolchain::inferWarningsForLevel(int warningLevel, WarningFlags &flags)
|
||||||
@@ -1677,6 +1688,19 @@ ClangClToolchain::ClangClToolchain()
|
|||||||
{
|
{
|
||||||
setDisplayName("clang-cl");
|
setDisplayName("clang-cl");
|
||||||
setTypeDisplayName(Tr::tr("Clang"));
|
setTypeDisplayName(Tr::tr("Clang"));
|
||||||
|
setVersionFlagsAndParser(
|
||||||
|
{"--version"}, [](const QString &output, const QString &) -> QVersionNumber {
|
||||||
|
const QString marker = "clang version ";
|
||||||
|
const int markerIndex = output.indexOf(marker);
|
||||||
|
if (markerIndex == -1)
|
||||||
|
return {};
|
||||||
|
const int versionOffset = markerIndex + marker.size();
|
||||||
|
const int newlineIndex = output.indexOf('\n', versionOffset);
|
||||||
|
if (newlineIndex == -1)
|
||||||
|
return {};
|
||||||
|
return QVersionNumber::fromString(
|
||||||
|
output.mid(versionOffset, newlineIndex - versionOffset).trimmed());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClangClToolchain::isValid() const
|
bool ClangClToolchain::isValid() const
|
||||||
@@ -2251,7 +2275,7 @@ ClangClInfo ClangClInfo::getInfo(const FilePath &filePath)
|
|||||||
{
|
{
|
||||||
QTC_ASSERT(!filePath.isEmpty(), return {});
|
QTC_ASSERT(!filePath.isEmpty(), return {});
|
||||||
|
|
||||||
static const auto parser = [](const QString &stdOut) {
|
static const auto parser = [](const QString &stdOut, const QString &) {
|
||||||
ClangClInfo info;
|
ClangClInfo info;
|
||||||
const QRegularExpressionMatch versionMatch
|
const QRegularExpressionMatch versionMatch
|
||||||
= QRegularExpression("clang version (\\d+(\\.\\d+)+)").match(stdOut);
|
= QRegularExpression("clang version (\\d+(\\.\\d+)+)").match(stdOut);
|
||||||
|
@@ -144,7 +144,7 @@ public:
|
|||||||
|
|
||||||
const QList<MsvcToolchain *> &msvcToolchains() const;
|
const QList<MsvcToolchain *> &msvcToolchains() const;
|
||||||
Utils::FilePath clangPath() const { return m_clangPath; }
|
Utils::FilePath clangPath() const { return m_clangPath; }
|
||||||
void setClangPath(const Utils::FilePath &path) { m_clangPath = path; }
|
void setClangPath(const Utils::FilePath &path) { m_clangPath = path; clearVersion(); }
|
||||||
|
|
||||||
Macros msvcPredefinedMacros(const QStringList &cxxflags,
|
Macros msvcPredefinedMacros(const QStringList &cxxflags,
|
||||||
const Utils::Environment &env) const override;
|
const Utils::Environment &env) const override;
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
#include "task.h"
|
#include "task.h"
|
||||||
|
|
||||||
#include <utils/async.h>
|
#include <utils/async.h>
|
||||||
|
#include <utils/datafromprocess.h>
|
||||||
#include <utils/pathchooser.h>
|
#include <utils/pathchooser.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
@@ -77,6 +78,11 @@ public:
|
|||||||
|
|
||||||
Toolchain::MacrosCache m_predefinedMacrosCache;
|
Toolchain::MacrosCache m_predefinedMacrosCache;
|
||||||
Toolchain::HeaderPathsCache m_headerPathsCache;
|
Toolchain::HeaderPathsCache m_headerPathsCache;
|
||||||
|
|
||||||
|
QStringList m_versionFlags;
|
||||||
|
Toolchain::VersionParser m_versionParser;
|
||||||
|
std::optional<QVersionNumber> m_version;
|
||||||
|
|
||||||
std::optional<bool> m_isValid;
|
std::optional<bool> m_isValid;
|
||||||
bool m_hasError = false;
|
bool m_hasError = false;
|
||||||
};
|
};
|
||||||
@@ -353,6 +359,24 @@ void Toolchain::setTargetAbi(const Abi &abi)
|
|||||||
toolChainUpdated();
|
toolChainUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVersionNumber Toolchain::version() const
|
||||||
|
{
|
||||||
|
if (d->m_version)
|
||||||
|
return *d->m_version;
|
||||||
|
|
||||||
|
if (!d->m_versionParser || compilerCommand().isEmpty())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
using DFP = DataFromProcess<QVersionNumber>;
|
||||||
|
DFP::Parameters params({compilerCommand(), d->m_versionFlags}, d->m_versionParser);
|
||||||
|
params.environment.setupEnglishOutput();
|
||||||
|
params.environment.set("VSLANG", "1033");
|
||||||
|
d->m_version = DFP::getData(params);
|
||||||
|
if (!d->m_version)
|
||||||
|
d->m_version.emplace();
|
||||||
|
return *d->m_version;
|
||||||
|
}
|
||||||
|
|
||||||
void Toolchain::setTargetAbiNoSignal(const Abi &abi)
|
void Toolchain::setTargetAbiNoSignal(const Abi &abi)
|
||||||
{
|
{
|
||||||
d->m_targetAbi = abi;
|
d->m_targetAbi = abi;
|
||||||
@@ -375,6 +399,7 @@ void Toolchain::setCompilerCommand(const FilePath &command)
|
|||||||
if (command == d->m_compilerCommand)
|
if (command == d->m_compilerCommand)
|
||||||
return;
|
return;
|
||||||
d->m_compilerCommand = command;
|
d->m_compilerCommand = command;
|
||||||
|
clearVersion();
|
||||||
toolChainUpdated();
|
toolChainUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,6 +418,17 @@ void Toolchain::setTypeDisplayName(const QString &typeName)
|
|||||||
d->m_typeDisplayName = typeName;
|
d->m_typeDisplayName = typeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Toolchain::setVersionFlagsAndParser(const QStringList &flags, const VersionParser &parser)
|
||||||
|
{
|
||||||
|
d->m_versionFlags = flags;
|
||||||
|
d->m_versionParser = parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toolchain::clearVersion()
|
||||||
|
{
|
||||||
|
d->m_version.reset();
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Used by the tool chain manager to load user-generated tool chains.
|
Used by the tool chain manager to load user-generated tool chains.
|
||||||
|
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
#include <QVersionNumber>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -99,6 +100,8 @@ public:
|
|||||||
Abi targetAbi() const;
|
Abi targetAbi() const;
|
||||||
void setTargetAbi(const Abi &abi);
|
void setTargetAbi(const Abi &abi);
|
||||||
|
|
||||||
|
QVersionNumber version() const;
|
||||||
|
|
||||||
virtual ProjectExplorer::Abis supportedAbis() const;
|
virtual ProjectExplorer::Abis supportedAbis() const;
|
||||||
virtual QString originalTargetTriple() const { return {}; }
|
virtual QString originalTargetTriple() const { return {}; }
|
||||||
virtual QStringList extraCodeModelFlags() const { return {}; }
|
virtual QStringList extraCodeModelFlags() const { return {}; }
|
||||||
@@ -179,6 +182,11 @@ protected:
|
|||||||
|
|
||||||
void setTypeDisplayName(const QString &typeName);
|
void setTypeDisplayName(const QString &typeName);
|
||||||
|
|
||||||
|
using VersionParser
|
||||||
|
= std::function<QVersionNumber(const QString & /* stdOut */, const QString & /* stdErr */)>;
|
||||||
|
void setVersionFlagsAndParser(const QStringList &flags, const VersionParser &parser);
|
||||||
|
void clearVersion();
|
||||||
|
|
||||||
void setTargetAbiNoSignal(const Abi &abi);
|
void setTargetAbiNoSignal(const Abi &abi);
|
||||||
void setTargetAbiKey(const Utils::Key &abiKey);
|
void setTargetAbiKey(const Utils::Key &abiKey);
|
||||||
|
|
||||||
@@ -211,6 +219,7 @@ private:
|
|||||||
|
|
||||||
friend class Internal::ToolchainSettingsAccessor;
|
friend class Internal::ToolchainSettingsAccessor;
|
||||||
friend class ToolchainFactory;
|
friend class ToolchainFactory;
|
||||||
|
friend class Internal::ToolchainPrivate;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Toolchains = QList<Toolchain *>;
|
using Toolchains = QList<Toolchain *>;
|
||||||
|
@@ -334,8 +334,8 @@ void ToolchainManager::addBadToolchain(const Utils::FilePath &toolchain)
|
|||||||
|
|
||||||
// Use as a tie-breaker for toolchains that match the strong requirements like toolchain type
|
// Use as a tie-breaker for toolchains that match the strong requirements like toolchain type
|
||||||
// and ABI.
|
// and ABI.
|
||||||
// For toolchains with the same priority, gives precedence to icecc and ccache
|
// For toolchains with the same priority, gives precedence to icecc and ccache,
|
||||||
// and otherwise simply chooses the one with the shortest path.
|
// prefers the higher version and otherwise simply chooses the one with the shortest path.
|
||||||
bool ToolchainManager::isBetterToolchain(
|
bool ToolchainManager::isBetterToolchain(
|
||||||
const ToolchainBundle &bundle1, const ToolchainBundle &bundle2)
|
const ToolchainBundle &bundle1, const ToolchainBundle &bundle2)
|
||||||
{
|
{
|
||||||
@@ -346,18 +346,20 @@ bool ToolchainManager::isBetterToolchain(
|
|||||||
if (priority1 < priority2)
|
if (priority1 < priority2)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const QString path1 = bundle1.get(&Toolchain::compilerCommand).path();
|
const FilePath path1 = bundle1.get(&Toolchain::compilerCommand);
|
||||||
const QString path2 = bundle2.get(&Toolchain::compilerCommand).path();
|
const FilePath path2 = bundle2.get(&Toolchain::compilerCommand);
|
||||||
|
const QString pathString1 = path1.path();
|
||||||
|
const QString pathString2 = path2.path();
|
||||||
|
|
||||||
const bool b1IsIcecc = path1.contains("icecc");
|
const bool b1IsIcecc = pathString1.contains("icecc");
|
||||||
const bool b2IsIcecc = path2.contains("icecc");
|
const bool b2IsIcecc = pathString2.contains("icecc");
|
||||||
if (b1IsIcecc)
|
if (b1IsIcecc)
|
||||||
return !b2IsIcecc;
|
return !b2IsIcecc;
|
||||||
if (b2IsIcecc)
|
if (b2IsIcecc)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const bool b1IsCCache = path1.contains("ccache");
|
const bool b1IsCCache = pathString1.contains("ccache");
|
||||||
const bool b2IsCcache = path2.contains("ccache");
|
const bool b2IsCcache = pathString2.contains("ccache");
|
||||||
if (b1IsCCache)
|
if (b1IsCCache)
|
||||||
return !b2IsCcache;
|
return !b2IsCcache;
|
||||||
if (b2IsCcache)
|
if (b2IsCcache)
|
||||||
@@ -383,7 +385,18 @@ bool ToolchainManager::isBetterToolchain(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return path1.size() < path2.size();
|
if (!path1.needsDevice() && !path2.needsDevice()) {
|
||||||
|
const QVersionNumber v1 = bundle1.get(&Toolchain::version);
|
||||||
|
const QVersionNumber v2 = bundle2.get(&Toolchain::version);
|
||||||
|
if (!v1.isNull() && !v2.isNull()) {
|
||||||
|
if (v1 > v2)
|
||||||
|
return true;
|
||||||
|
if (v1 < v2)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pathString1.size() < pathString2.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ProjectExplorer
|
} // namespace ProjectExplorer
|
||||||
|
Reference in New Issue
Block a user