ABI: Improve tool chain selection for Qt projects

* Set a null-ABI for toolchains where detection of ABI failed: This
  allows the user to select any tool chain.

* Warn if ABI detection fails by showing a message in the Qt version
  setup dialog

* Do not override the mkspec if the Qt version has a null ABI only:
  We (have to) trust the user to know what he is doing in that case.

* GCC: Add version information to GCC tool chain and use it to select
  the mkspec on Mac.

* GCC: Do not override mkspec if we do a cross-compile
  (and actually detect that).

* GCC: Leave out -32 or -64 from mkspec if the compiler binaries ABI
  matches the target ABI.

* Linux-generic is compatible with all other linuxes (both ways)
  The targets themselves do additional filtering and will remove
  anything that does not work for them anyway.

Task-number: QTCREATORBUG-5756
Task-number: QTCREATORBUG-5960
Change-Id: Ib3c0ac91f3aa8e2a823e3e9891a02bdccb97af14
Reviewed-on: http://codereview.qt-project.org/4281
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Daniel Teske <daniel.teske@nokia.com>
This commit is contained in:
Tobias Hunger
2011-09-06 15:19:05 +00:00
parent bfd9fcbb3c
commit aaf260c04b
15 changed files with 97 additions and 97 deletions

View File

@@ -273,6 +273,12 @@ static QList<ProjectExplorer::Abi> guessGccAbi(const QString &path, const QStrin
return guessGccAbi(machine); return guessGccAbi(machine);
} }
static QString gccVersion(const QString &path, const QStringList &env)
{
QStringList arguments(QLatin1String("-dumpversion"));
return QString::fromLocal8Bit(runGcc(path, arguments, env)).trimmed();
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// GccToolChain // GccToolChain
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -322,6 +328,13 @@ Abi GccToolChain::targetAbi() const
return m_targetAbi; return m_targetAbi;
} }
QString GccToolChain::version() const
{
if (m_version.isEmpty())
m_version = detectVersion();
return m_version;
}
void GccToolChain::setTargetAbi(const Abi &abi) void GccToolChain::setTargetAbi(const Abi &abi)
{ {
if (abi == m_targetAbi) if (abi == m_targetAbi)
@@ -389,10 +402,30 @@ QString GccToolChain::debuggerCommand() const
QString GccToolChain::mkspec() const QString GccToolChain::mkspec() const
{ {
Abi abi = targetAbi(); Abi abi = targetAbi();
if (abi.os() == Abi::MacOS) if (abi.os() == Abi::MacOS) {
QString v = version();
// prefer versioned g++ on mac. This is required to enable building for older Mac OS versions
if (v.startsWith(QLatin1String("4.0")))
return QLatin1String("macx-g++40");
if (v.startsWith(QLatin1String("4.2")))
return QLatin1String("macx-g++42");
return QLatin1String("macx-g++"); return QLatin1String("macx-g++");
if (abi.os() == Abi::LinuxOS) }
Abi gccAbi = Abi::abisOfBinary(m_compilerPath);
if (gccAbi.architecture() != abi.architecture()
|| gccAbi.os() != abi.os()
|| gccAbi.osFlavor() != abi.osFlavor()) {
// Note: This can fail:-(
return QString(); // this is a cross-compiler, leave the mkspec alone!
}
if (abi.os() == Abi::LinuxOS) {
if (abi.osFlavor() != Abi::GenericLinuxFlavor)
return QString(); // most likely not a desktop, so leave the mkspec alone.
if (abi.wordWidth() == gccAbi.wordWidth())
return QLatin1String("linux-g++"); // no need to explicitly set the word width
return QLatin1String("linux-g++-") + QString::number(m_targetAbi.wordWidth()); return QLatin1String("linux-g++-") + QString::number(m_targetAbi.wordWidth());
}
if (abi.os() == Abi::BsdOS && abi.osFlavor() == Abi::FreeBsdFlavor) if (abi.os() == Abi::BsdOS && abi.osFlavor() == Abi::FreeBsdFlavor)
return QLatin1String("freebsd-g++"); return QLatin1String("freebsd-g++");
return QString(); return QString();
@@ -507,6 +540,13 @@ QList<Abi> GccToolChain::detectSupportedAbis() const
return guessGccAbi(m_compilerPath, env.toStringList()); return guessGccAbi(m_compilerPath, env.toStringList());
} }
QString GccToolChain::detectVersion() const
{
Utils::Environment env = Utils::Environment::systemEnvironment();
addToEnvironment(env);
return gccVersion(m_compilerPath, env.toStringList());
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// GccToolChainFactory // GccToolChainFactory
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -734,11 +774,12 @@ QString ClangToolChain::makeCommand() const
QString ClangToolChain::mkspec() const QString ClangToolChain::mkspec() const
{ {
if (targetAbi().os() == Abi::MacOS) Abi abi = targetAbi();
if (abi.os() == Abi::MacOS)
return QLatin1String("unsupported/macx-clang"); return QLatin1String("unsupported/macx-clang");
else if (targetAbi().os() == Abi::LinuxOS) else if (abi.os() == Abi::LinuxOS)
return QLatin1String("unsupported/linux-clang"); return QLatin1String("unsupported/linux-clang");
return QLatin1String("unsupported/win32-clang"); // Note: Not part of Qt yet! return QString(); // Note: Not supported by Qt yet, so default to the mkspec the Qt was build with
} }
IOutputParser *ClangToolChain::outputParser() const IOutputParser *ClangToolChain::outputParser() const

View File

@@ -56,6 +56,7 @@ class PROJECTEXPLORER_EXPORT GccToolChain : public ToolChain
public: public:
QString typeName() const; QString typeName() const;
Abi targetAbi() const; Abi targetAbi() const;
QString version() const;
QList<Abi> supportedAbis() const; QList<Abi> supportedAbis() const;
void setTargetAbi(const Abi &); void setTargetAbi(const Abi &);
@@ -91,6 +92,7 @@ protected:
void updateId(); void updateId();
virtual QList<Abi> detectSupportedAbis() const; virtual QList<Abi> detectSupportedAbis() const;
virtual QString detectVersion() const;
mutable QByteArray m_predefinedMacros; mutable QByteArray m_predefinedMacros;
@@ -105,6 +107,7 @@ private:
Abi m_targetAbi; Abi m_targetAbi;
mutable QList<Abi> m_supportedAbis; mutable QList<Abi> m_supportedAbis;
mutable QList<HeaderPath> m_headerPathes; mutable QList<HeaderPath> m_headerPathes;
mutable QString m_version;
friend class Internal::GccToolChainFactory; friend class Internal::GccToolChainFactory;
friend class ToolChainFactory; friend class ToolChainFactory;

View File

@@ -146,8 +146,9 @@ QString QMakeStep::allArguments(bool shorted)
} }
} }
} }
if (!userProvidedMkspec) QString specArg = mkspec();
arguments << "-spec" << mkspec(); if (!userProvidedMkspec && !specArg.isEmpty())
arguments << "-spec" << specArg;
// Find out what flags we pass on to qmake // Find out what flags we pass on to qmake
arguments << bc->configCommandLineArguments(); arguments << bc->configCommandLineArguments();
@@ -454,12 +455,17 @@ QString QMakeStep::mkspec()
} }
} }
QtSupport::BaseQtVersion *version = bc->qtVersion();
// We do not know which abi the Qt version has, so let's stick with the defaults
if (version && version->qtAbis().count() == 1 && version->qtAbis().first().isNull())
return QString();
const QString tcSpec = bc->toolChain() ? bc->toolChain()->mkspec() : QString(); const QString tcSpec = bc->toolChain() ? bc->toolChain()->mkspec() : QString();
if (!bc->qtVersion()) if (!version)
return tcSpec; return tcSpec;
if (!tcSpec.isEmpty() && bc->qtVersion()->hasMkspec(tcSpec)) if (!tcSpec.isEmpty() && version->hasMkspec(tcSpec))
return tcSpec; return tcSpec;
return bc->qtVersion()->mkspec(); return version->mkspec();
} }
QVariantMap QMakeStep::toMap() const QVariantMap QMakeStep::toMap() const

View File

@@ -44,15 +44,13 @@ using namespace Qt4ProjectManager;
using namespace Qt4ProjectManager::Internal; using namespace Qt4ProjectManager::Internal;
DesktopQtVersion::DesktopQtVersion() DesktopQtVersion::DesktopQtVersion()
: BaseQtVersion(), : BaseQtVersion()
m_qtAbisUpToDate(false)
{ {
} }
DesktopQtVersion::DesktopQtVersion(const QString &path, bool isAutodetected, const QString &autodetectionSource) DesktopQtVersion::DesktopQtVersion(const QString &path, bool isAutodetected, const QString &autodetectionSource)
: BaseQtVersion(path, isAutodetected, autodetectionSource), : BaseQtVersion(path, isAutodetected, autodetectionSource)
m_qtAbisUpToDate(false)
{ {
} }
@@ -72,38 +70,19 @@ QString DesktopQtVersion::type() const
return QtSupport::Constants::DESKTOPQT; return QtSupport::Constants::DESKTOPQT;
} }
bool DesktopQtVersion::isValid() const
{
if (!BaseQtVersion::isValid())
return false;
if (qtAbis().isEmpty())
return false;
return true;
}
QString DesktopQtVersion::invalidReason() const
{
QString tmp = BaseQtVersion::invalidReason();
if (tmp.isEmpty() && qtAbis().isEmpty())
return QCoreApplication::translate("QtVersion", "Failed to detect the ABI(s) used by the Qt version.");
return tmp;
}
QString DesktopQtVersion::warningReason() const QString DesktopQtVersion::warningReason() const
{ {
if (qtAbis().count() == 1 && qtAbis().first().isNull())
return QCoreApplication::translate("QtVersion", "ABI detection failed: Make sure to use a matching tool chain when building.");
if (qtVersion() >= QtSupport::QtVersionNumber(4, 7, 0) && qmlviewerCommand().isEmpty()) if (qtVersion() >= QtSupport::QtVersionNumber(4, 7, 0) && qmlviewerCommand().isEmpty())
return QCoreApplication::translate("QtVersion", "No qmlviewer installed."); return QCoreApplication::translate("QtVersion", "No qmlviewer installed.");
return QString(); return QString();
} }
QList<ProjectExplorer::Abi> DesktopQtVersion::qtAbis() const QList<ProjectExplorer::Abi> DesktopQtVersion::detectQtAbis() const
{ {
if (!m_qtAbisUpToDate) { ensureMkSpecParsed();
m_qtAbisUpToDate = true; return qtAbisFromLibrary(qtCorePath(versionInfo(), qtVersionString()));
ensureMkSpecParsed();
m_qtAbis = qtAbisFromLibrary(qtCorePath(versionInfo(), qtVersionString()));
}
return m_qtAbis;
} }
bool DesktopQtVersion::supportsTargetId(const QString &id) const bool DesktopQtVersion::supportsTargetId(const QString &id) const

View File

@@ -49,20 +49,14 @@ public:
QString type() const; QString type() const;
bool isValid() const;
QString invalidReason() const;
QString warningReason() const; QString warningReason() const;
QList<ProjectExplorer::Abi> qtAbis() const; QList<ProjectExplorer::Abi> detectQtAbis() const;
bool supportsTargetId(const QString &id) const; bool supportsTargetId(const QString &id) const;
QSet<QString> supportedTargetIds() const; QSet<QString> supportedTargetIds() const;
QString description() const; QString description() const;
private:
mutable bool m_qtAbisUpToDate;
mutable QList<ProjectExplorer::Abi> m_qtAbis;
}; };
} }

View File

@@ -44,15 +44,13 @@ using namespace Qt4ProjectManager;
using namespace Qt4ProjectManager::Internal; using namespace Qt4ProjectManager::Internal;
SimulatorQtVersion::SimulatorQtVersion() SimulatorQtVersion::SimulatorQtVersion()
: QtSupport::BaseQtVersion(), : QtSupport::BaseQtVersion()
m_qtAbisUpToDate(false)
{ {
} }
SimulatorQtVersion::SimulatorQtVersion(const QString &path, bool isAutodetected, const QString &autodetectionSource) SimulatorQtVersion::SimulatorQtVersion(const QString &path, bool isAutodetected, const QString &autodetectionSource)
: QtSupport::BaseQtVersion(path, isAutodetected, autodetectionSource), : QtSupport::BaseQtVersion(path, isAutodetected, autodetectionSource)
m_qtAbisUpToDate(false)
{ {
} }
@@ -72,38 +70,19 @@ QString SimulatorQtVersion::type() const
return QtSupport::Constants::SIMULATORQT; return QtSupport::Constants::SIMULATORQT;
} }
bool SimulatorQtVersion::isValid() const
{
if (!BaseQtVersion::isValid())
return false;
if (qtAbis().isEmpty())
return false;
return true;
}
QString SimulatorQtVersion::invalidReason() const
{
QString tmp = BaseQtVersion::invalidReason();
if (tmp.isEmpty() && qtAbis().isEmpty())
return QCoreApplication::translate("QtVersion", "Failed to detect the ABI(s) used by the Qt version.");
return tmp;
}
QString SimulatorQtVersion::warningReason() const QString SimulatorQtVersion::warningReason() const
{ {
if (qtAbis().count() == 1 && qtAbis().first().isNull())
return QCoreApplication::translate("QtVersion", "ABI detection failed: Make sure to use a matching tool chain when building.");
if (qtVersion() >= QtSupport::QtVersionNumber(4, 7, 0) && qmlviewerCommand().isEmpty()) if (qtVersion() >= QtSupport::QtVersionNumber(4, 7, 0) && qmlviewerCommand().isEmpty())
return QCoreApplication::translate("QtVersion", "No qmlviewer installed."); return QCoreApplication::translate("QtVersion", "No qmlviewer installed.");
return QString(); return QString();
} }
QList<ProjectExplorer::Abi> SimulatorQtVersion::qtAbis() const QList<ProjectExplorer::Abi> SimulatorQtVersion::detectQtAbis() const
{ {
if (!m_qtAbisUpToDate) { ensureMkSpecParsed();
m_qtAbisUpToDate = true; return qtAbisFromLibrary(qtCorePath(versionInfo(), qtVersionString()));
ensureMkSpecParsed();
m_qtAbis = qtAbisFromLibrary(qtCorePath(versionInfo(), qtVersionString()));
}
return m_qtAbis;
} }
bool SimulatorQtVersion::supportsTargetId(const QString &id) const bool SimulatorQtVersion::supportsTargetId(const QString &id) const
@@ -120,4 +99,3 @@ QString SimulatorQtVersion::description() const
{ {
return QCoreApplication::translate("QtVersion", "Qt Simulator", "Qt Version is meant for Qt Simulator"); return QCoreApplication::translate("QtVersion", "Qt Simulator", "Qt Version is meant for Qt Simulator");
} }

View File

@@ -49,20 +49,14 @@ public:
QString type() const; QString type() const;
bool isValid() const;
QString invalidReason() const;
QString warningReason() const; QString warningReason() const;
QList<ProjectExplorer::Abi> qtAbis() const; QList<ProjectExplorer::Abi> detectQtAbis() const;
bool supportsTargetId(const QString &id) const; bool supportsTargetId(const QString &id) const;
QSet<QString> supportedTargetIds() const; QSet<QString> supportedTargetIds() const;
QString description() const; QString description() const;
private:
mutable bool m_qtAbisUpToDate;
mutable QList<ProjectExplorer::Abi> m_qtAbis;
}; };
} }

View File

@@ -163,7 +163,7 @@ QVariantMap SymbianQtVersion::toMap() const
return result; return result;
} }
QList<ProjectExplorer::Abi> SymbianQtVersion::qtAbis() const QList<ProjectExplorer::Abi> SymbianQtVersion::detectQtAbis() const
{ {
return QList<ProjectExplorer::Abi>() return QList<ProjectExplorer::Abi>()
<< ProjectExplorer::Abi(ProjectExplorer::Abi::ArmArchitecture, ProjectExplorer::Abi::SymbianOS, << ProjectExplorer::Abi(ProjectExplorer::Abi::ArmArchitecture, ProjectExplorer::Abi::SymbianOS,

View File

@@ -46,7 +46,7 @@ public:
SymbianQtVersion *clone() const; SymbianQtVersion *clone() const;
~SymbianQtVersion(); ~SymbianQtVersion();
virtual bool equals(BaseQtVersion *other); bool equals(BaseQtVersion *other);
QString type() const; QString type() const;
@@ -59,7 +59,7 @@ public:
void fromMap(const QVariantMap &map); void fromMap(const QVariantMap &map);
QVariantMap toMap() const; QVariantMap toMap() const;
QList<ProjectExplorer::Abi> qtAbis() const; QList<ProjectExplorer::Abi> detectQtAbis() const;
bool supportsTargetId(const QString &id) const; bool supportsTargetId(const QString &id) const;
QSet<QString> supportedTargetIds() const; QSet<QString> supportedTargetIds() const;

View File

@@ -65,7 +65,7 @@ QString WinCeQtVersion::type() const
return QtSupport::Constants::WINCEQT; return QtSupport::Constants::WINCEQT;
} }
QList<ProjectExplorer::Abi> WinCeQtVersion::qtAbis() const QList<ProjectExplorer::Abi> WinCeQtVersion::detectQtAbis() const
{ {
return QList<ProjectExplorer::Abi>() return QList<ProjectExplorer::Abi>()
<< ProjectExplorer::Abi(ProjectExplorer::Abi::ArmArchitecture, << ProjectExplorer::Abi(ProjectExplorer::Abi::ArmArchitecture,

View File

@@ -48,7 +48,7 @@ public:
QString type() const; QString type() const;
QList<ProjectExplorer::Abi> qtAbis() const; QList<ProjectExplorer::Abi> detectQtAbis() const;
bool supportsTargetId(const QString &id) const; bool supportsTargetId(const QString &id) const;
QSet<QString> supportedTargetIds() const; QSet<QString> supportedTargetIds() const;

View File

@@ -299,7 +299,7 @@ bool BaseQtVersion::isValid() const
return !qmakeCommand().isEmpty() return !qmakeCommand().isEmpty()
&& !m_notInstalled && !m_notInstalled
&& m_versionInfo.contains("QT_INSTALL_BINS") && m_versionInfo.contains("QT_INSTALL_BINS")
&& (!m_mkspecFullPath.isEmpty() || !m_mkspecUpToDate) && !m_mkspecFullPath.isEmpty()
&& m_qmakeIsExecutable; && m_qmakeIsExecutable;
} }
@@ -342,6 +342,15 @@ bool BaseQtVersion::toolChainAvailable(const QString &id) const
return false; return false;
} }
QList<ProjectExplorer::Abi> BaseQtVersion::qtAbis() const
{
if (m_qtAbis.isEmpty())
m_qtAbis = detectQtAbis();
if (m_qtAbis.isEmpty())
m_qtAbis.append(ProjectExplorer::Abi()); // add empty ABI by default: This is compatible with all TCs.
return m_qtAbis;
}
bool BaseQtVersion::equals(BaseQtVersion *other) bool BaseQtVersion::equals(BaseQtVersion *other)
{ {
if (type() != other->type()) if (type() != other->type())
@@ -1199,11 +1208,5 @@ QString BaseQtVersion::qtCorePath(const QHash<QString,QString> &versionInfo, con
QList<ProjectExplorer::Abi> BaseQtVersion::qtAbisFromLibrary(const QString &coreLibrary) QList<ProjectExplorer::Abi> BaseQtVersion::qtAbisFromLibrary(const QString &coreLibrary)
{ {
QList<ProjectExplorer::Abi> qtAbis = ProjectExplorer::Abi::abisOfBinary(coreLibrary); return ProjectExplorer::Abi::abisOfBinary(coreLibrary);
if (qtAbis.isEmpty() && !coreLibrary.isEmpty()) {
qWarning("Warning: Could not find ABI for '%s'"
"Qt Creator does not know about the system includes, "
"nor the system defines.", qPrintable(coreLibrary));
}
return qtAbis;
} }

View File

@@ -125,7 +125,8 @@ public:
virtual bool supportsTargetId(const QString &id) const = 0; virtual bool supportsTargetId(const QString &id) const = 0;
virtual QSet<QString> supportedTargetIds() const = 0; virtual QSet<QString> supportedTargetIds() const = 0;
virtual QList<ProjectExplorer::Abi> qtAbis() const = 0; QList<ProjectExplorer::Abi> qtAbis() const;
virtual QList<ProjectExplorer::Abi> detectQtAbis() const = 0;
// Returns the PREFIX, BINPREFIX, DOCPREFIX and similar information // Returns the PREFIX, BINPREFIX, DOCPREFIX and similar information
virtual QHash<QString,QString> versionInfo() const; virtual QHash<QString,QString> versionInfo() const;
@@ -268,6 +269,7 @@ private:
mutable QString m_qmlviewerCommand; mutable QString m_qmlviewerCommand;
mutable bool m_qmakeIsExecutable; mutable bool m_qmakeIsExecutable;
mutable QList<ProjectExplorer::Abi> m_qtAbis;
}; };
} }

View File

@@ -110,7 +110,7 @@ QString MaemoQtVersion::systemRoot() const
return m_systemRoot; return m_systemRoot;
} }
QList<ProjectExplorer::Abi> MaemoQtVersion::qtAbis() const QList<ProjectExplorer::Abi> MaemoQtVersion::detectQtAbis() const
{ {
QList<ProjectExplorer::Abi> result; QList<ProjectExplorer::Abi> result;
if (!m_isvalidVersion) if (!m_isvalidVersion)

View File

@@ -50,7 +50,7 @@ public:
QString type() const; QString type() const;
bool isValid() const; bool isValid() const;
QString systemRoot() const; QString systemRoot() const;
QList<ProjectExplorer::Abi> qtAbis() const; QList<ProjectExplorer::Abi> detectQtAbis() const;
void addToEnvironment(Utils::Environment &env) const; void addToEnvironment(Utils::Environment &env) const;
bool supportsTargetId(const QString &id) const; bool supportsTargetId(const QString &id) const;