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
|
||||
{
|
||||
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 Callback = std::function<void(const std::optional<Data> &)>;
|
||||
|
||||
@@ -133,7 +134,7 @@ inline std::optional<Data> DataFromProcess<Data>::handleProcessFinished(
|
||||
|
||||
std::optional<Data> data;
|
||||
if (params.allowedResults.contains(process->result()))
|
||||
data = params.parser(process->cleanedStdOut());
|
||||
data = params.parser(process->cleanedStdOut(), process->cleanedStdErr());
|
||||
else if (params.errorHandler)
|
||||
params.errorHandler(*process);
|
||||
QMutexLocker<QMutex> cacheLocker(&m_cacheMutex);
|
||||
|
@@ -107,9 +107,9 @@ bool BinaryVersionToolTipEventFilter::eventFilter(QObject *o, QEvent *e)
|
||||
QTC_ASSERT(le, return false);
|
||||
|
||||
const QString binary = le->text();
|
||||
DataFromProcess<QString>::Parameters params(CommandLine(FilePath::fromUserInput(binary),
|
||||
m_arguments),
|
||||
[](const QString &output) { return output; });
|
||||
DataFromProcess<QString>::Parameters params(
|
||||
CommandLine(FilePath::fromUserInput(binary), m_arguments),
|
||||
[](const QString &output, const QString &) { return output; });
|
||||
params.callback = [binary, self = QPointer(this),
|
||||
le = QPointer(le)](const std::optional<QString> &version) {
|
||||
if (!self || !le)
|
||||
|
@@ -41,7 +41,8 @@ static QStringList queryClangTidyChecks(const FilePath &executable,
|
||||
// abseil-duration-division
|
||||
// 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;
|
||||
QTextStream stream(&output);
|
||||
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());
|
||||
if (document.isNull())
|
||||
return {};
|
||||
@@ -130,7 +132,8 @@ ClazyStandaloneInfo::ClazyStandaloneInfo(const FilePath &executablePath)
|
||||
: defaultChecks(queryClangTidyChecks(executablePath, {})) // Yup, behaves as clang-tidy.
|
||||
, 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;
|
||||
QTextStream stream(&output);
|
||||
while (!stream.atEnd()) {
|
||||
@@ -157,7 +160,8 @@ static FilePath queryResourceDir(const FilePath &clangToolPath)
|
||||
// lib/clang/10.0.1
|
||||
// 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;
|
||||
QTextStream stream(&output);
|
||||
const QString path = clangToolPath.parentDir().parentDir()
|
||||
@@ -180,7 +184,7 @@ static FilePath queryResourceDir(const FilePath &clangToolPath)
|
||||
|
||||
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;
|
||||
QTextStream stream(&output);
|
||||
while (!stream.atEnd()) {
|
||||
|
@@ -74,8 +74,8 @@ void GerritParameters::setPortFlagBySshType()
|
||||
{
|
||||
bool isPlink = false;
|
||||
if (!ssh.isEmpty()) {
|
||||
DataFromProcess<QString>::Parameters params({ssh, {"-V"}},
|
||||
[](const QString &output) { return output; });
|
||||
DataFromProcess<QString>::Parameters
|
||||
params({ssh, {"-V"}}, [](const QString &output, const QString &) { return output; });
|
||||
using namespace std::chrono_literals;
|
||||
params.timeout = 1s;
|
||||
if (const auto version = DataFromProcess<QString>::getData(params))
|
||||
|
@@ -390,6 +390,10 @@ GccToolchain::GccToolchain(Id typeId, SubType subType)
|
||||
setTypeDisplayName(Tr::tr("Clang"));
|
||||
syncAutodetectedWithParentToolchains();
|
||||
}
|
||||
|
||||
setVersionFlagsAndParser({"-dumpversion"}, [](const QString &output, const QString &) {
|
||||
return QVersionNumber::fromString(output.trimmed());
|
||||
});
|
||||
}
|
||||
|
||||
GccToolchain::~GccToolchain()
|
||||
|
@@ -852,6 +852,17 @@ MsvcToolchain::MsvcToolchain(Utils::Id typeId)
|
||||
setTypeDisplayName(Tr::tr("MSVC"));
|
||||
addToAvailableMsvcToolchains(this);
|
||||
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)
|
||||
@@ -1677,6 +1688,19 @@ ClangClToolchain::ClangClToolchain()
|
||||
{
|
||||
setDisplayName("clang-cl");
|
||||
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
|
||||
@@ -2251,7 +2275,7 @@ ClangClInfo ClangClInfo::getInfo(const FilePath &filePath)
|
||||
{
|
||||
QTC_ASSERT(!filePath.isEmpty(), return {});
|
||||
|
||||
static const auto parser = [](const QString &stdOut) {
|
||||
static const auto parser = [](const QString &stdOut, const QString &) {
|
||||
ClangClInfo info;
|
||||
const QRegularExpressionMatch versionMatch
|
||||
= QRegularExpression("clang version (\\d+(\\.\\d+)+)").match(stdOut);
|
||||
|
@@ -144,7 +144,7 @@ public:
|
||||
|
||||
const QList<MsvcToolchain *> &msvcToolchains() const;
|
||||
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,
|
||||
const Utils::Environment &env) const override;
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include "task.h"
|
||||
|
||||
#include <utils/async.h>
|
||||
#include <utils/datafromprocess.h>
|
||||
#include <utils/pathchooser.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
@@ -77,6 +78,11 @@ public:
|
||||
|
||||
Toolchain::MacrosCache m_predefinedMacrosCache;
|
||||
Toolchain::HeaderPathsCache m_headerPathsCache;
|
||||
|
||||
QStringList m_versionFlags;
|
||||
Toolchain::VersionParser m_versionParser;
|
||||
std::optional<QVersionNumber> m_version;
|
||||
|
||||
std::optional<bool> m_isValid;
|
||||
bool m_hasError = false;
|
||||
};
|
||||
@@ -353,6 +359,24 @@ void Toolchain::setTargetAbi(const Abi &abi)
|
||||
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)
|
||||
{
|
||||
d->m_targetAbi = abi;
|
||||
@@ -375,6 +399,7 @@ void Toolchain::setCompilerCommand(const FilePath &command)
|
||||
if (command == d->m_compilerCommand)
|
||||
return;
|
||||
d->m_compilerCommand = command;
|
||||
clearVersion();
|
||||
toolChainUpdated();
|
||||
}
|
||||
|
||||
@@ -393,6 +418,17 @@ void Toolchain::setTypeDisplayName(const QString &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.
|
||||
|
||||
|
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QSet>
|
||||
#include <QVersionNumber>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
@@ -99,6 +100,8 @@ public:
|
||||
Abi targetAbi() const;
|
||||
void setTargetAbi(const Abi &abi);
|
||||
|
||||
QVersionNumber version() const;
|
||||
|
||||
virtual ProjectExplorer::Abis supportedAbis() const;
|
||||
virtual QString originalTargetTriple() const { return {}; }
|
||||
virtual QStringList extraCodeModelFlags() const { return {}; }
|
||||
@@ -179,6 +182,11 @@ protected:
|
||||
|
||||
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 setTargetAbiKey(const Utils::Key &abiKey);
|
||||
|
||||
@@ -211,6 +219,7 @@ private:
|
||||
|
||||
friend class Internal::ToolchainSettingsAccessor;
|
||||
friend class ToolchainFactory;
|
||||
friend class Internal::ToolchainPrivate;
|
||||
};
|
||||
|
||||
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
|
||||
// and ABI.
|
||||
// For toolchains with the same priority, gives precedence to icecc and ccache
|
||||
// and otherwise simply chooses the one with the shortest path.
|
||||
// For toolchains with the same priority, gives precedence to icecc and ccache,
|
||||
// prefers the higher version and otherwise simply chooses the one with the shortest path.
|
||||
bool ToolchainManager::isBetterToolchain(
|
||||
const ToolchainBundle &bundle1, const ToolchainBundle &bundle2)
|
||||
{
|
||||
@@ -346,18 +346,20 @@ bool ToolchainManager::isBetterToolchain(
|
||||
if (priority1 < priority2)
|
||||
return false;
|
||||
|
||||
const QString path1 = bundle1.get(&Toolchain::compilerCommand).path();
|
||||
const QString path2 = bundle2.get(&Toolchain::compilerCommand).path();
|
||||
const FilePath path1 = bundle1.get(&Toolchain::compilerCommand);
|
||||
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 b2IsIcecc = path2.contains("icecc");
|
||||
const bool b1IsIcecc = pathString1.contains("icecc");
|
||||
const bool b2IsIcecc = pathString2.contains("icecc");
|
||||
if (b1IsIcecc)
|
||||
return !b2IsIcecc;
|
||||
if (b2IsIcecc)
|
||||
return false;
|
||||
|
||||
const bool b1IsCCache = path1.contains("ccache");
|
||||
const bool b2IsCcache = path2.contains("ccache");
|
||||
const bool b1IsCCache = pathString1.contains("ccache");
|
||||
const bool b2IsCcache = pathString2.contains("ccache");
|
||||
if (b1IsCCache)
|
||||
return !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
|
||||
|
Reference in New Issue
Block a user