forked from qt-creator/qt-creator
ProjectExplorer: (Re-)start using strings for mkspecs
Even if this is part of a directory name it is naturally closer to a "string" id than a file path. Change-Id: If66f930526744379ce86e2b18bd9eac7fabfe773 Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -123,10 +123,9 @@ bool AndroidToolChain::fromMap(const QVariantMap &data)
|
||||
return isValid();
|
||||
}
|
||||
|
||||
FileNameList AndroidToolChain::suggestedMkspecList() const
|
||||
QStringList AndroidToolChain::suggestedMkspecList() const
|
||||
{
|
||||
return FileNameList() << FileName::fromLatin1("android-g++")
|
||||
<< FileName::fromLatin1("android-clang");
|
||||
return {"android-g++", "android-clang"};
|
||||
}
|
||||
|
||||
FileName AndroidToolChain::makeCommand(const Environment &env) const
|
||||
|
@@ -44,7 +44,7 @@ public:
|
||||
|
||||
Utils::FileName suggestedDebugger() const override;
|
||||
Utils::FileName suggestedGdbServer() const;
|
||||
Utils::FileNameList suggestedMkspecList() const override;
|
||||
QStringList suggestedMkspecList() const override;
|
||||
Utils::FileName makeCommand(const Utils::Environment &environment) const override;
|
||||
bool fromMap(const QVariantMap &data) override;
|
||||
|
||||
|
@@ -192,7 +192,7 @@ void CustomToolChain::addToEnvironment(Environment &env) const
|
||||
}
|
||||
}
|
||||
|
||||
FileNameList CustomToolChain::suggestedMkspecList() const
|
||||
QStringList CustomToolChain::suggestedMkspecList() const
|
||||
{
|
||||
return m_mkspecs;
|
||||
}
|
||||
@@ -270,10 +270,7 @@ const QStringList &CustomToolChain::cxx11Flags() const
|
||||
|
||||
void CustomToolChain::setMkspecs(const QString &specs)
|
||||
{
|
||||
Utils::FileNameList tmp
|
||||
= Utils::transform(specs.split(QLatin1Char(',')),
|
||||
[](QString fn) { return FileName::fromString(fn); });
|
||||
|
||||
const QStringList tmp = specs.split(',');
|
||||
if (tmp == m_mkspecs)
|
||||
return;
|
||||
m_mkspecs = tmp;
|
||||
@@ -282,11 +279,7 @@ void CustomToolChain::setMkspecs(const QString &specs)
|
||||
|
||||
QString CustomToolChain::mkspecs() const
|
||||
{
|
||||
QString list;
|
||||
for (const FileName &spec : m_mkspecs)
|
||||
list.append(spec.toString() + QLatin1Char(','));
|
||||
list.chop(1);
|
||||
return list;
|
||||
return m_mkspecs.join(',');
|
||||
}
|
||||
|
||||
QVariantMap CustomToolChain::toMap() const
|
||||
|
@@ -82,7 +82,7 @@ public:
|
||||
HeaderPaths builtInHeaderPaths(const QStringList &cxxFlags,
|
||||
const Utils::FileName &) const override;
|
||||
void addToEnvironment(Utils::Environment &env) const override;
|
||||
Utils::FileNameList suggestedMkspecList() const override;
|
||||
QStringList suggestedMkspecList() const override;
|
||||
IOutputParser *outputParser() const override;
|
||||
QStringList headerPathsList() const;
|
||||
void setHeaderPaths(const QStringList &list);
|
||||
@@ -121,7 +121,7 @@ private:
|
||||
Macros m_predefinedMacros;
|
||||
HeaderPaths m_builtInHeaderPaths;
|
||||
QStringList m_cxx11Flags;
|
||||
Utils::FileNameList m_mkspecs;
|
||||
QStringList m_mkspecs;
|
||||
|
||||
Core::Id m_outputParserId;
|
||||
CustomParserSettings m_customParserSettings;
|
||||
|
@@ -654,43 +654,42 @@ void GccToolChain::addToEnvironment(Environment &env) const
|
||||
addCommandPathToEnvironment(m_compilerCommand, env);
|
||||
}
|
||||
|
||||
FileNameList GccToolChain::suggestedMkspecList() const
|
||||
QStringList GccToolChain::suggestedMkspecList() const
|
||||
{
|
||||
Abi abi = targetAbi();
|
||||
Abi host = Abi::hostAbi();
|
||||
const Abi abi = targetAbi();
|
||||
const Abi host = Abi::hostAbi();
|
||||
|
||||
// Cross compile: Leave the mkspec alone!
|
||||
if (abi.architecture() != host.architecture()
|
||||
|| abi.os() != host.os()
|
||||
|| abi.osFlavor() != host.osFlavor()) // Note: This can fail:-(
|
||||
return FileNameList();
|
||||
return {};
|
||||
|
||||
if (abi.os() == Abi::DarwinOS) {
|
||||
QString v = version();
|
||||
// prefer versioned g++ on macOS. This is required to enable building for older macOS versions
|
||||
if (v.startsWith("4.0") && m_compilerCommand.endsWith("-4.0"))
|
||||
return FileNameList() << FileName::fromLatin1("macx-g++40");
|
||||
return {"macx-g++40"};
|
||||
if (v.startsWith("4.2") && m_compilerCommand.endsWith("-4.2"))
|
||||
return FileNameList() << FileName::fromLatin1("macx-g++42");
|
||||
return FileNameList() << FileName::fromLatin1("macx-g++");
|
||||
return {"macx-g++42"};
|
||||
return {"macx-g++"};
|
||||
}
|
||||
|
||||
if (abi.os() == Abi::LinuxOS) {
|
||||
if (abi.osFlavor() != Abi::GenericFlavor)
|
||||
return FileNameList(); // most likely not a desktop, so leave the mkspec alone.
|
||||
return {}; // most likely not a desktop, so leave the mkspec alone.
|
||||
if (abi.wordWidth() == host.wordWidth()) {
|
||||
// no need to explicitly set the word width, but provide that mkspec anyway to make sure
|
||||
// that the correct compiler is picked if a mkspec with a wordwidth is given.
|
||||
return FileNameList() << FileName::fromLatin1("linux-g++")
|
||||
<< FileName::fromString(QString::fromLatin1("linux-g++-") + QString::number(m_targetAbi.wordWidth()));
|
||||
return {"linux-g++", "linux-g++-" + QString::number(m_targetAbi.wordWidth())};
|
||||
}
|
||||
return FileNameList() << FileName::fromString(QString::fromLatin1("linux-g++-") + QString::number(m_targetAbi.wordWidth()));
|
||||
return {"linux-g++-" + QString::number(m_targetAbi.wordWidth())};
|
||||
}
|
||||
|
||||
if (abi.os() == Abi::BsdOS && abi.osFlavor() == Abi::FreeBsdFlavor)
|
||||
return FileNameList() << FileName::fromLatin1("freebsd-g++");
|
||||
return {"freebsd-g++"};
|
||||
|
||||
return FileNameList();
|
||||
return {};
|
||||
}
|
||||
|
||||
FileName GccToolChain::makeCommand(const Environment &environment) const
|
||||
@@ -1326,23 +1325,16 @@ WarningFlags ClangToolChain::warningFlags(const QStringList &cflags) const
|
||||
return flags;
|
||||
}
|
||||
|
||||
FileNameList ClangToolChain::suggestedMkspecList() const
|
||||
QStringList ClangToolChain::suggestedMkspecList() const
|
||||
{
|
||||
Abi abi = targetAbi();
|
||||
if (abi.os() == Abi::DarwinOS) {
|
||||
return FileNameList()
|
||||
<< FileName::fromLatin1("macx-clang")
|
||||
<< FileName::fromLatin1("macx-clang-32")
|
||||
<< FileName::fromLatin1("unsupported/macx-clang")
|
||||
<< FileName::fromLatin1("macx-ios-clang");
|
||||
} else if (abi.os() == Abi::LinuxOS) {
|
||||
return FileNameList()
|
||||
<< FileName::fromLatin1("linux-clang")
|
||||
<< FileName::fromLatin1("unsupported/linux-clang");
|
||||
} else if (abi.os() == Abi::WindowsOS) {
|
||||
return FileNameList() << FileName::fromLatin1("win32-clang-g++");
|
||||
}
|
||||
return FileNameList(); // Note: Not supported by Qt yet, so default to the mkspec the Qt was build with
|
||||
const Abi abi = targetAbi();
|
||||
if (abi.os() == Abi::DarwinOS)
|
||||
return {"macx-clang", "macx-clang-32", "unsupported/macx-clang", "macx-ios-clang"};
|
||||
if (abi.os() == Abi::LinuxOS)
|
||||
return {"linux-clang", "unsupported/linux-clang"};
|
||||
if (abi.os() == Abi::WindowsOS)
|
||||
return {"win32-clang-g++"};
|
||||
return {}; // Note: Not supported by Qt yet, so default to the mkspec the Qt was build with
|
||||
}
|
||||
|
||||
void ClangToolChain::addToEnvironment(Environment &env) const
|
||||
@@ -1609,21 +1601,16 @@ QString MingwToolChain::typeDisplayName() const
|
||||
return MingwToolChainFactory::tr("MinGW");
|
||||
}
|
||||
|
||||
FileNameList MingwToolChain::suggestedMkspecList() const
|
||||
QStringList MingwToolChain::suggestedMkspecList() const
|
||||
{
|
||||
if (HostOsInfo::isWindowsHost())
|
||||
return FileNameList() << FileName::fromLatin1("win32-g++");
|
||||
return {"win32-g++"};
|
||||
if (HostOsInfo::isLinuxHost()) {
|
||||
if (version().startsWith("4.6."))
|
||||
return FileNameList()
|
||||
<< FileName::fromLatin1("win32-g++-4.6-cross")
|
||||
<< FileName::fromLatin1("unsupported/win32-g++-4.6-cross");
|
||||
else
|
||||
return FileNameList()
|
||||
<< FileName::fromLatin1("win32-g++-cross")
|
||||
<< FileName::fromLatin1("unsupported/win32-g++-cross");
|
||||
return {"win32-g++-4.6-cross", "unsupported/win32-g++-4.6-cross"};
|
||||
return {"win32-g++-cross", "unsupported/win32-g++-cross"};
|
||||
}
|
||||
return FileNameList();
|
||||
return {};
|
||||
}
|
||||
|
||||
FileName MingwToolChain::makeCommand(const Environment &environment) const
|
||||
@@ -1720,10 +1707,9 @@ IOutputParser *LinuxIccToolChain::outputParser() const
|
||||
return new LinuxIccParser;
|
||||
}
|
||||
|
||||
FileNameList LinuxIccToolChain::suggestedMkspecList() const
|
||||
QStringList LinuxIccToolChain::suggestedMkspecList() const
|
||||
{
|
||||
return FileNameList()
|
||||
<< FileName::fromString(QString::fromLatin1("linux-icc-") + QString::number(targetAbi().wordWidth()));
|
||||
return {QString("linux-icc-%1").arg(targetAbi().wordWidth())};
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
@@ -89,7 +89,7 @@ public:
|
||||
|
||||
void addToEnvironment(Utils::Environment &env) const override;
|
||||
Utils::FileName makeCommand(const Utils::Environment &environment) const override;
|
||||
Utils::FileNameList suggestedMkspecList() const override;
|
||||
QStringList suggestedMkspecList() const override;
|
||||
IOutputParser *outputParser() const override;
|
||||
|
||||
QVariantMap toMap() const override;
|
||||
@@ -222,7 +222,7 @@ public:
|
||||
|
||||
IOutputParser *outputParser() const override;
|
||||
|
||||
Utils::FileNameList suggestedMkspecList() const override;
|
||||
QStringList suggestedMkspecList() const override;
|
||||
void addToEnvironment(Utils::Environment &env) const override;
|
||||
|
||||
QString originalTargetTriple() const override;
|
||||
@@ -259,7 +259,7 @@ public:
|
||||
QString typeDisplayName() const override;
|
||||
Utils::FileName makeCommand(const Utils::Environment &environment) const override;
|
||||
|
||||
Utils::FileNameList suggestedMkspecList() const override;
|
||||
QStringList suggestedMkspecList() const override;
|
||||
|
||||
private:
|
||||
MingwToolChain();
|
||||
@@ -280,7 +280,7 @@ public:
|
||||
Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const override;
|
||||
IOutputParser *outputParser() const override;
|
||||
|
||||
Utils::FileNameList suggestedMkspecList() const override;
|
||||
QStringList suggestedMkspecList() const override;
|
||||
|
||||
private:
|
||||
LinuxIccToolChain();
|
||||
|
@@ -945,53 +945,52 @@ QString MsvcToolChain::typeDisplayName() const
|
||||
return MsvcToolChainFactory::tr("MSVC");
|
||||
}
|
||||
|
||||
Utils::FileNameList MsvcToolChain::suggestedMkspecList() const
|
||||
QStringList MsvcToolChain::suggestedMkspecList() const
|
||||
{
|
||||
Utils::FileNameList result;
|
||||
result << Utils::FileName::fromLatin1("win32-msvc"); // Common MSVC mkspec introduced in 5.8.1
|
||||
QStringList result = {"win32-msvc"}; // Common MSVC mkspec introduced in 5.8.1
|
||||
switch (m_abi.osFlavor()) {
|
||||
case Abi::WindowsMsvc2005Flavor:
|
||||
result << Utils::FileName::fromLatin1("win32-msvc2005");
|
||||
result << "win32-msvc2005";
|
||||
break;
|
||||
case Abi::WindowsMsvc2008Flavor:
|
||||
result << Utils::FileName::fromLatin1("win32-msvc2008");
|
||||
result << "win32-msvc2008";
|
||||
break;
|
||||
case Abi::WindowsMsvc2010Flavor:
|
||||
result << Utils::FileName::fromLatin1("win32-msvc2010");
|
||||
result << "win32-msvc2010";
|
||||
break;
|
||||
case Abi::WindowsMsvc2012Flavor:
|
||||
result << Utils::FileName::fromLatin1("win32-msvc2012")
|
||||
<< Utils::FileName::fromLatin1("win32-msvc2010");
|
||||
result << "win32-msvc2012"
|
||||
<< "win32-msvc2010";
|
||||
break;
|
||||
case Abi::WindowsMsvc2013Flavor:
|
||||
result << Utils::FileName::fromLatin1("win32-msvc2013")
|
||||
<< Utils::FileName::fromLatin1("winphone-arm-msvc2013")
|
||||
<< Utils::FileName::fromLatin1("winphone-x86-msvc2013")
|
||||
<< Utils::FileName::fromLatin1("winrt-arm-msvc2013")
|
||||
<< Utils::FileName::fromLatin1("winrt-x86-msvc2013")
|
||||
<< Utils::FileName::fromLatin1("winrt-x64-msvc2013")
|
||||
<< Utils::FileName::fromLatin1("win32-msvc2012")
|
||||
<< Utils::FileName::fromLatin1("win32-msvc2010");
|
||||
result << "win32-msvc2013"
|
||||
<< "winphone-arm-msvc2013"
|
||||
<< "winphone-x86-msvc2013"
|
||||
<< "winrt-arm-msvc2013"
|
||||
<< "winrt-x86-msvc2013"
|
||||
<< "winrt-x64-msvc2013"
|
||||
<< "win32-msvc2012"
|
||||
<< "win32-msvc2010";
|
||||
break;
|
||||
case Abi::WindowsMsvc2015Flavor:
|
||||
result << Utils::FileName::fromLatin1("win32-msvc2015")
|
||||
<< Utils::FileName::fromLatin1("winphone-arm-msvc2015")
|
||||
<< Utils::FileName::fromLatin1("winphone-x86-msvc2015")
|
||||
<< Utils::FileName::fromLatin1("winrt-arm-msvc2015")
|
||||
<< Utils::FileName::fromLatin1("winrt-x86-msvc2015")
|
||||
<< Utils::FileName::fromLatin1("winrt-x64-msvc2015");
|
||||
result << "win32-msvc2015"
|
||||
<< "winphone-arm-msvc2015"
|
||||
<< "winphone-x86-msvc2015"
|
||||
<< "winrt-arm-msvc2015"
|
||||
<< "winrt-x86-msvc2015"
|
||||
<< "winrt-x64-msvc2015";
|
||||
break;
|
||||
case Abi::WindowsMsvc2017Flavor:
|
||||
result << Utils::FileName::fromLatin1("win32-msvc2017")
|
||||
<< Utils::FileName::fromLatin1("winrt-arm-msvc2017")
|
||||
<< Utils::FileName::fromLatin1("winrt-x86-msvc2017")
|
||||
<< Utils::FileName::fromLatin1("winrt-x64-msvc2017");
|
||||
result << "win32-msvc2017"
|
||||
<< "winrt-arm-msvc2017"
|
||||
<< "winrt-x86-msvc2017"
|
||||
<< "winrt-x64-msvc2017";
|
||||
break;
|
||||
case Abi::WindowsMsvc2019Flavor:
|
||||
result << Utils::FileName::fromLatin1("win32-msvc2019")
|
||||
<< Utils::FileName::fromLatin1("winrt-arm-msvc2019")
|
||||
<< Utils::FileName::fromLatin1("winrt-x86-msvc2019")
|
||||
<< Utils::FileName::fromLatin1("winrt-x64-msvc2019");
|
||||
result << "win32-msvc2019"
|
||||
<< "winrt-arm-msvc2019"
|
||||
<< "winrt-x86-msvc2019"
|
||||
<< "winrt-x64-msvc2019";
|
||||
break;
|
||||
default:
|
||||
result.clear();
|
||||
@@ -1706,11 +1705,10 @@ QString ClangClToolChain::typeDisplayName() const
|
||||
return QCoreApplication::translate("ProjectExplorer::ClangToolChainFactory", "Clang");
|
||||
}
|
||||
|
||||
QList<Utils::FileName> ClangClToolChain::suggestedMkspecList() const
|
||||
QStringList ClangClToolChain::suggestedMkspecList() const
|
||||
{
|
||||
const QString mkspec = QLatin1String("win32-clang-") + Abi::toString(targetAbi().osFlavor());
|
||||
return QList<Utils::FileName>{Utils::FileName::fromString(mkspec),
|
||||
Utils::FileName::fromString("win32-clang-msvc")};
|
||||
const QString mkspec = "win32-clang-" + Abi::toString(targetAbi().osFlavor());
|
||||
return {mkspec, "win32-clang-msvc"};
|
||||
}
|
||||
|
||||
IOutputParser *ClangClToolChain::outputParser() const
|
||||
|
@@ -71,7 +71,7 @@ public:
|
||||
|
||||
QString originalTargetTriple() const override;
|
||||
|
||||
Utils::FileNameList suggestedMkspecList() const override;
|
||||
QStringList suggestedMkspecList() const override;
|
||||
|
||||
QString typeDisplayName() const override;
|
||||
|
||||
@@ -182,7 +182,7 @@ public:
|
||||
|
||||
bool isValid() const override;
|
||||
QString typeDisplayName() const override;
|
||||
QList<Utils::FileName> suggestedMkspecList() const override;
|
||||
QStringList suggestedMkspecList() const override;
|
||||
void addToEnvironment(Utils::Environment &env) const override;
|
||||
Utils::FileName compilerCommand() const override;
|
||||
IOutputParser *outputParser() const override;
|
||||
|
@@ -164,9 +164,9 @@ QByteArray ToolChain::id() const
|
||||
return d->m_id;
|
||||
}
|
||||
|
||||
Utils::FileNameList ToolChain::suggestedMkspecList() const
|
||||
QStringList ToolChain::suggestedMkspecList() const
|
||||
{
|
||||
return Utils::FileNameList();
|
||||
return {};
|
||||
}
|
||||
|
||||
Utils::FileName ToolChain::suggestedDebugger() const
|
||||
|
@@ -98,7 +98,7 @@ public:
|
||||
|
||||
QByteArray id() const;
|
||||
|
||||
virtual Utils::FileNameList suggestedMkspecList() const;
|
||||
virtual QStringList suggestedMkspecList() const;
|
||||
virtual Utils::FileName suggestedDebugger() const;
|
||||
|
||||
Core::Id typeId() const;
|
||||
|
@@ -123,7 +123,7 @@ void QmakeKitAspect::setup(Kit *k)
|
||||
|
||||
ToolChain *tc = ToolChainKitAspect::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
|
||||
|
||||
if (!tc || (!tc->suggestedMkspecList().empty() && !tc->suggestedMkspecList().contains(spec))) {
|
||||
if (!tc || (!tc->suggestedMkspecList().empty() && !tc->suggestedMkspecList().contains(spec.toString()))) {
|
||||
const QList<ToolChain *> possibleTcs = ToolChainManager::toolChains(
|
||||
[version](const ToolChain *t) {
|
||||
return t->isValid()
|
||||
@@ -133,7 +133,7 @@ void QmakeKitAspect::setup(Kit *k)
|
||||
if (!possibleTcs.isEmpty()) {
|
||||
const QList<ToolChain *> goodTcs = Utils::filtered(possibleTcs,
|
||||
[&spec](const ToolChain *t) {
|
||||
return t->suggestedMkspecList().contains(spec);
|
||||
return t->suggestedMkspecList().contains(spec.toString());
|
||||
});
|
||||
// Hack to prefer a tool chain from PATH (e.g. autodetected) over other matches.
|
||||
// This improves the situation a bit if a cross-compilation tool chain has the
|
||||
|
@@ -274,7 +274,7 @@ static const QList<ToolChain *> preferredToolChains(BaseQtVersion *qtVersion, co
|
||||
const Abis qtAbis = qtVersion->qtAbis();
|
||||
const auto matcher = [&](const ToolChain *tc) {
|
||||
return qtAbis.contains(tc->targetAbi())
|
||||
&& tc->suggestedMkspecList().contains(spec)
|
||||
&& tc->suggestedMkspecList().contains(spec.toString())
|
||||
&& QMakeStepConfig::targetArchFor(tc->targetAbi(), qtVersion) == archConfig;
|
||||
};
|
||||
ToolChain * const cxxToolchain = findOrDefault(toolchains, [matcher](const ToolChain *tc) {
|
||||
|
@@ -124,15 +124,14 @@ void QnxToolChain::addToEnvironment(Environment &env) const
|
||||
GccToolChain::addToEnvironment(env);
|
||||
}
|
||||
|
||||
FileNameList QnxToolChain::suggestedMkspecList() const
|
||||
QStringList QnxToolChain::suggestedMkspecList() const
|
||||
{
|
||||
FileNameList mkspecList;
|
||||
mkspecList << FileName::fromLatin1("qnx-armle-v7-qcc");
|
||||
mkspecList << FileName::fromLatin1("qnx-x86-qcc");
|
||||
mkspecList << FileName::fromLatin1("qnx-aarch64le-qcc");
|
||||
mkspecList << FileName::fromLatin1("qnx-x86-64-qcc");
|
||||
|
||||
return mkspecList;
|
||||
return {
|
||||
"qnx-armle-v7-qcc",
|
||||
"qnx-x86-qcc",
|
||||
"qnx-aarch64le-qcc",
|
||||
"qnx-x86-64-qcc"
|
||||
};
|
||||
}
|
||||
|
||||
QVariantMap QnxToolChain::toMap() const
|
||||
|
@@ -41,7 +41,7 @@ public:
|
||||
std::unique_ptr<ProjectExplorer::ToolChainConfigWidget> createConfigurationWidget() override;
|
||||
|
||||
void addToEnvironment(Utils::Environment &env) const override;
|
||||
Utils::FileNameList suggestedMkspecList() const override;
|
||||
QStringList suggestedMkspecList() const override;
|
||||
|
||||
QVariantMap toMap() const override;
|
||||
bool fromMap(const QVariantMap &data) override;
|
||||
|
@@ -977,12 +977,12 @@ FileName BaseQtVersion::mkspecFor(ToolChain *tc) const
|
||||
if (!tc)
|
||||
return versionSpec;
|
||||
|
||||
const FileNameList tcSpecList = tc->suggestedMkspecList();
|
||||
if (tcSpecList.contains(versionSpec))
|
||||
const QStringList tcSpecList = tc->suggestedMkspecList();
|
||||
if (tcSpecList.contains(versionSpec.toString()))
|
||||
return versionSpec;
|
||||
foreach (const FileName &tcSpec, tcSpecList) {
|
||||
if (hasMkspec(tcSpec))
|
||||
return tcSpec;
|
||||
for (const QString &tcSpec : tcSpecList) {
|
||||
if (hasMkspec(FileName::fromString(tcSpec)))
|
||||
return FileName::fromString(tcSpec);
|
||||
}
|
||||
|
||||
return versionSpec;
|
||||
|
Reference in New Issue
Block a user