From 1caff90686a7f87f9cf305c81d71e943c200bf01 Mon Sep 17 00:00:00 2001 From: Denis Shienkov Date: Thu, 21 Feb 2019 17:38:22 +0300 Subject: [PATCH] bare-metal: Add support for IAR EW toolchain This patch adds support for the toolchains, provided by IAR Embedded Workbench: * https://www.iar.com/iar-embedded-workbench/ Now QtC's compiler page have additional 'IAREW' selector which allows to user to choose a desired C/C++ compiler from set of the IAR EW toolchains. In this case the QtC will tries to detect the compiler ABI, in which was added the additional MCS51 architecture (which includes all family for Intel x8051 MCU's): * https://en.wikipedia.org/wiki/Intel_MCS-51 Also, now the ABI has an additional proprietary UBROF binary format type which is produced by some of IAR EW compilers: * https://netstorage.iar.com/SuppDB/Public/UPDINFO/011281/ew/doc/EW_MigrationFromUBROF.pdf * https://netstorage.iar.com/SuppDB/Public/UPDINFO/013556/ew/doc/UBROFRecordTags.pdf Currently are supported the following architectures: * ARM * 8051 (aka MCS51) * AVR In addition, were added changes to the QBS Project Manager plugin to make it work with QBS 1.13 (where previously were added support for IAR toolchain). So, now do not need to do an additional 'hacks' into the 'qbs.toolchain' property of QtC IAR kit. Following features are not implemented yet: * C-SPY debugger integration. * Compile output parsers. * Toolchains auto-detection. Change-Id: I4a7794efe8dc15652f5a7f1f3dd966c367943484 Reviewed-by: Christian Kandeler Reviewed-by: Leena Miettinen --- src/plugins/baremetal/baremetal.pro | 6 +- src/plugins/baremetal/baremetal.qbs | 1 + src/plugins/baremetal/baremetalconstants.h | 3 + src/plugins/baremetal/baremetalplugin.cpp | 3 + src/plugins/baremetal/iarewtoolchain.cpp | 431 ++++++++++++++++++ src/plugins/baremetal/iarewtoolchain.h | 145 ++++++ src/plugins/projectexplorer/abi.cpp | 4 + src/plugins/projectexplorer/abi.h | 2 + .../defaultpropertyprovider.cpp | 3 + 9 files changed, 596 insertions(+), 2 deletions(-) create mode 100644 src/plugins/baremetal/iarewtoolchain.cpp create mode 100644 src/plugins/baremetal/iarewtoolchain.h diff --git a/src/plugins/baremetal/baremetal.pro b/src/plugins/baremetal/baremetal.pro index 9af653b43ea..bb089aa2b81 100644 --- a/src/plugins/baremetal/baremetal.pro +++ b/src/plugins/baremetal/baremetal.pro @@ -19,7 +19,8 @@ SOURCES += baremetalplugin.cpp \ gdbserverprovidermanager.cpp \ openocdgdbserverprovider.cpp \ defaultgdbserverprovider.cpp \ - stlinkutilgdbserverprovider.cpp + stlinkutilgdbserverprovider.cpp \ + iarewtoolchain.cpp \ HEADERS += baremetalplugin.h \ baremetalconstants.h \ @@ -38,7 +39,8 @@ HEADERS += baremetalplugin.h \ gdbserverprovidermanager.h \ openocdgdbserverprovider.h \ defaultgdbserverprovider.h \ - stlinkutilgdbserverprovider.h + stlinkutilgdbserverprovider.h \ + iarewtoolchain.h \ RESOURCES += \ baremetal.qrc diff --git a/src/plugins/baremetal/baremetal.qbs b/src/plugins/baremetal/baremetal.qbs index 3ac05a12761..40212e65083 100644 --- a/src/plugins/baremetal/baremetal.qbs +++ b/src/plugins/baremetal/baremetal.qbs @@ -31,5 +31,6 @@ QtcPlugin { "openocdgdbserverprovider.cpp", "openocdgdbserverprovider.h", "defaultgdbserverprovider.cpp", "defaultgdbserverprovider.h", "stlinkutilgdbserverprovider.cpp", "stlinkutilgdbserverprovider.h", + "iarewtoolchain.cpp", "iarewtoolchain.h", ] } diff --git a/src/plugins/baremetal/baremetalconstants.h b/src/plugins/baremetal/baremetalconstants.h index def72715773..a5d4c6015f9 100644 --- a/src/plugins/baremetal/baremetalconstants.h +++ b/src/plugins/baremetal/baremetalconstants.h @@ -41,5 +41,8 @@ const char OPENOCD_PROVIDER_ID[] = "BareMetal.GdbServerProvider.OpenOcd"; const char DEFAULT_PROVIDER_ID[] = "BareMetal.GdbServerProvider.Default"; const char STLINK_UTIL_PROVIDER_ID[] = "BareMetal.GdbServerProvider.STLinkUtil"; +// Toolchain types. +const char IAREW_TOOLCHAIN_TYPEID[] = "BareMetal.ToolChain.Iar"; + } // namespace BareMetal } // namespace Constants diff --git a/src/plugins/baremetal/baremetalplugin.cpp b/src/plugins/baremetal/baremetalplugin.cpp index 60afa6f911a..f272063cb2d 100644 --- a/src/plugins/baremetal/baremetalplugin.cpp +++ b/src/plugins/baremetal/baremetalplugin.cpp @@ -34,6 +34,8 @@ #include "gdbserverproviderssettingspage.h" #include "gdbserverprovidermanager.h" +#include "iarewtoolchain.h" + #include #include #include @@ -49,6 +51,7 @@ namespace Internal { class BareMetalPluginPrivate { public: + IarToolChainFactory iarToolChainFactory; BareMetalDeviceFactory deviceFactory; BareMetalRunConfigurationFactory runConfigurationFactory; BareMetalCustomRunConfigurationFactory customRunConfigurationFactory; diff --git a/src/plugins/baremetal/iarewtoolchain.cpp b/src/plugins/baremetal/iarewtoolchain.cpp new file mode 100644 index 00000000000..c1eb28dd07e --- /dev/null +++ b/src/plugins/baremetal/iarewtoolchain.cpp @@ -0,0 +1,431 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "baremetalconstants.h" +#include "iarewtoolchain.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace ProjectExplorer; +using namespace Utils; + +namespace BareMetal { +namespace Internal { + +// Helpers: + +static const char compilerCommandKeyC[] = "BareMetal.IarToolChain.CompilerPath"; +static const char targetAbiKeyC[] = "BareMetal.IarToolChain.TargetAbi"; + +static bool isCompilerExists(const FileName &compilerPath) +{ + const QFileInfo fi = compilerPath.toFileInfo(); + return fi.exists() && fi.isExecutable() && fi.isFile(); +} + +static Macros dumpPredefinedMacros(const FileName &compiler, const QStringList &env) +{ + if (compiler.isEmpty() || !compiler.toFileInfo().isExecutable()) + return {}; + + // IAR compiler requires an input and output files. + + QTemporaryFile fakeIn; + if (!fakeIn.open()) + return {}; + fakeIn.close(); + + const QString outpath = fakeIn.fileName() + ".tmp"; + + SynchronousProcess cpp; + cpp.setEnvironment(env); + cpp.setTimeoutS(10); + + QStringList arguments; + arguments.push_back(fakeIn.fileName()); + arguments.push_back("--predef_macros"); + arguments.push_back(outpath); + + const SynchronousProcessResponse response = cpp.runBlocking(compiler.toString(), arguments); + if (response.result != SynchronousProcessResponse::Finished + || response.exitCode != 0) { + qWarning() << response.exitMessage(compiler.toString(), 10); + return {}; + } + + QByteArray output; + QFile fakeOut(outpath); + if (fakeOut.open(QIODevice::ReadOnly)) + output = fakeOut.readAll(); + fakeOut.remove(); + + return Macro::toMacros(output); +} + +static Abi::Architecture guessArchitecture(const Macros ¯os) +{ + for (const Macro ¯o : macros) { + if (macro.key == "__ICCARM__") + return Abi::Architecture::ArmArchitecture; + if (macro.key == "__ICC8051__") + return Abi::Architecture::Mcs51Architecture; + if (macro.key == "__ICCAVR__") + return Abi::Architecture::AvrArchitecture; + } + return Abi::Architecture::UnknownArchitecture; +} + +static unsigned char guessWordWidth(const Macros ¯os) +{ + const Macro sizeMacro = Utils::findOrDefault(macros, [](const Macro &m) { + return m.key == "__INT_SIZE__"; + }); + if (sizeMacro.isValid() && sizeMacro.type == MacroType::Define) + return sizeMacro.value.toInt() * 8; + return 0; +} + +static Abi::BinaryFormat guessFormat(Abi::Architecture arch) +{ + if (arch == Abi::Architecture::ArmArchitecture) + return Abi::BinaryFormat::ElfFormat; + if (arch == Abi::Architecture::Mcs51Architecture + || arch == Abi::Architecture::AvrArchitecture) { + return Abi::BinaryFormat::UbrofFormat; + } + return Abi::BinaryFormat::UnknownFormat; +} + +static Abi guessAbi(const Macros ¯os) +{ + const auto arch = guessArchitecture(macros); + return {arch, Abi::OS::BareMetalOS, Abi::OSFlavor::GenericFlavor, + guessFormat(arch), guessWordWidth(macros)}; +} + +// IarToolChain + +IarToolChain::IarToolChain(Detection d) : + ToolChain(Constants::IAREW_TOOLCHAIN_TYPEID, d), + m_predefinedMacrosCache(std::make_shared>()) +{ } + +IarToolChain::IarToolChain(Core::Id language, Detection d) : + IarToolChain(d) +{ + setLanguage(language); +} + +QString IarToolChain::typeDisplayName() const +{ + return Internal::IarToolChainFactory::tr("IAREW"); +} + +void IarToolChain::setTargetAbi(const Abi &abi) +{ + if (abi == m_targetAbi) + return; + m_targetAbi = abi; + toolChainUpdated(); +} + +Abi IarToolChain::targetAbi() const +{ + return m_targetAbi; +} + +bool IarToolChain::isValid() const +{ + return true; +} + +ToolChain::MacroInspectionRunner IarToolChain::createMacroInspectionRunner() const +{ + Environment env = Environment::systemEnvironment(); + addToEnvironment(env); + + const Utils::FileName compilerCommand = m_compilerCommand; + const Core::Id lang = language(); + + MacrosCache macrosCache = m_predefinedMacrosCache; + + return [env, compilerCommand, macrosCache, lang] + (const QStringList &flags) { + Q_UNUSED(flags) + + const Macros macros = dumpPredefinedMacros(compilerCommand, env.toStringList()); + const auto report = MacroInspectionReport{macros, languageVersion(lang, macros)}; + macrosCache->insert({}, report); + + return report; + }; +} + +Macros IarToolChain::predefinedMacros(const QStringList &cxxflags) const +{ + return createMacroInspectionRunner()(cxxflags).macros; +} + +Utils::LanguageExtensions IarToolChain::languageExtensions(const QStringList &) const +{ + return LanguageExtension::None; +} + +WarningFlags IarToolChain::warningFlags(const QStringList &cxxflags) const +{ + Q_UNUSED(cxxflags); + return WarningFlags::Default; +} + +ToolChain::BuiltInHeaderPathsRunner IarToolChain::createBuiltInHeaderPathsRunner() const +{ + return {}; +} + +HeaderPaths IarToolChain::builtInHeaderPaths(const QStringList &cxxFlags, + const FileName &fileName) const +{ + Q_UNUSED(cxxFlags) + Q_UNUSED(fileName) + return {}; +} + +void IarToolChain::addToEnvironment(Environment &env) const +{ + if (!m_compilerCommand.isEmpty()) { + const FileName path = m_compilerCommand.parentDir(); + env.prependOrSetPath(path.toString()); + } +} + +IOutputParser *IarToolChain::outputParser() const +{ + return nullptr; +} + +QVariantMap IarToolChain::toMap() const +{ + QVariantMap data = ToolChain::toMap(); + data.insert(compilerCommandKeyC, m_compilerCommand.toString()); + data.insert(targetAbiKeyC, m_targetAbi.toString()); + return data; +} + +bool IarToolChain::fromMap(const QVariantMap &data) +{ + if (!ToolChain::fromMap(data)) + return false; + m_compilerCommand = FileName::fromString(data.value(compilerCommandKeyC).toString()); + m_targetAbi = Abi::fromString(data.value(targetAbiKeyC).toString()); + return true; +} + +std::unique_ptr IarToolChain::createConfigurationWidget() +{ + return std::make_unique(this); +} + +bool IarToolChain::operator==(const ToolChain &other) const +{ + if (!ToolChain::operator==(other)) + return false; + + const auto customTc = static_cast(&other); + return m_compilerCommand == customTc->m_compilerCommand + && m_targetAbi == customTc->m_targetAbi + ; +} + +void IarToolChain::setCompilerCommand(const FileName &file) +{ + if (file == m_compilerCommand) + return; + m_compilerCommand = file; + toolChainUpdated(); +} + +FileName IarToolChain::compilerCommand() const +{ + return m_compilerCommand; +} + +QString IarToolChain::makeCommand(const Environment &env) const +{ + Q_UNUSED(env) + return {}; +} + +ToolChain *IarToolChain::clone() const +{ + return new IarToolChain(*this); +} + +void IarToolChain::toolChainUpdated() +{ + m_predefinedMacrosCache->invalidate(); + ToolChain::toolChainUpdated(); +} + +// IarToolChainFactory + +IarToolChainFactory::IarToolChainFactory() +{ + setDisplayName(tr("IAREW")); +} + +QSet IarToolChainFactory::supportedLanguages() const +{ + return {ProjectExplorer::Constants::C_LANGUAGE_ID, + ProjectExplorer::Constants::CXX_LANGUAGE_ID}; +} + +bool IarToolChainFactory::canCreate() +{ + return true; +} + +ToolChain *IarToolChainFactory::create(Core::Id language) +{ + return new IarToolChain(language, ToolChain::ManualDetection); +} + +bool IarToolChainFactory::canRestore(const QVariantMap &data) +{ + return typeIdFromMap(data) == Constants::IAREW_TOOLCHAIN_TYPEID; +} + +ToolChain *IarToolChainFactory::restore(const QVariantMap &data) +{ + const auto tc = new IarToolChain(ToolChain::ManualDetection); + if (tc->fromMap(data)) + return tc; + + delete tc; + return nullptr; +} + +// IarToolChainConfigWidget + +IarToolChainConfigWidget::IarToolChainConfigWidget(IarToolChain *tc) : + ToolChainConfigWidget(tc), + m_compilerCommand(new PathChooser), + m_abiWidget(new AbiWidget) +{ + Q_ASSERT(tc); + + m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand); + m_compilerCommand->setHistoryCompleter("PE.ToolChainCommand.History"); + m_mainLayout->addRow(tr("&Compiler path:"), m_compilerCommand); + m_mainLayout->addRow(tr("&ABI:"), m_abiWidget); + + m_abiWidget->setEnabled(false); + + addErrorLabel(); + setFromToolchain(); + + connect(m_compilerCommand, &PathChooser::rawPathChanged, + this, &IarToolChainConfigWidget::handleCompilerCommandChange); + connect(m_abiWidget, &AbiWidget::abiChanged, + this, &ToolChainConfigWidget::dirty); +} + +void IarToolChainConfigWidget::applyImpl() +{ + if (toolChain()->isAutoDetected()) + return; + + const auto tc = static_cast(toolChain()); + Q_ASSERT(tc); + const QString displayName = tc->displayName(); + tc->setCompilerCommand(m_compilerCommand->fileName()); + tc->setTargetAbi(m_abiWidget->currentAbi()); + tc->setDisplayName(displayName); + + if (m_macros.isEmpty()) + return; + + const auto languageVersion = ToolChain::languageVersion(tc->language(), m_macros); + tc->m_predefinedMacrosCache->insert({}, {m_macros, languageVersion}); + + setFromToolchain(); +} + +bool IarToolChainConfigWidget::isDirtyImpl() const +{ + const auto tc = static_cast(toolChain()); + Q_ASSERT(tc); + return m_compilerCommand->fileName() != tc->compilerCommand() + || m_abiWidget->currentAbi() != tc->targetAbi() + ; +} + +void IarToolChainConfigWidget::makeReadOnlyImpl() +{ + m_mainLayout->setEnabled(false); +} + +void IarToolChainConfigWidget::setFromToolchain() +{ + const QSignalBlocker blocker(this); + const auto tc = static_cast(toolChain()); + m_compilerCommand->setFileName(tc->compilerCommand()); + m_abiWidget->setAbis({}, tc->targetAbi()); + const bool haveCompiler = isCompilerExists(m_compilerCommand->fileName()); + m_abiWidget->setEnabled(haveCompiler); +} + +void IarToolChainConfigWidget::handleCompilerCommandChange() +{ + const FileName compilerPath = m_compilerCommand->fileName(); + const bool haveCompiler = isCompilerExists(compilerPath); + if (haveCompiler) { + const auto env = Environment::systemEnvironment(); + m_macros = dumpPredefinedMacros(compilerPath, env.toStringList()); + const Abi guessed = guessAbi(m_macros); + m_abiWidget->setAbis({}, guessed); + } + + m_abiWidget->setEnabled(haveCompiler); + emit dirty(); +} + +} // namespace Internal +} // namespace BareMetal diff --git a/src/plugins/baremetal/iarewtoolchain.h b/src/plugins/baremetal/iarewtoolchain.h new file mode 100644 index 00000000000..4e7e4b6daf1 --- /dev/null +++ b/src/plugins/baremetal/iarewtoolchain.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QPlainTextEdit; +class QPushButton; +class QTextEdit; +QT_END_NAMESPACE + +namespace Utils { class PathChooser; } +namespace ProjectExplorer { class AbiWidget; } + +namespace BareMetal { +namespace Internal { + +// IarToolChain + +class IarToolChain final : public ProjectExplorer::ToolChain +{ + Q_DECLARE_TR_FUNCTIONS(IarToolChain) + +public: + QString typeDisplayName() const override; + + void setTargetAbi(const ProjectExplorer::Abi &abi); + ProjectExplorer::Abi targetAbi() const override; + + bool isValid() const override; + + MacroInspectionRunner createMacroInspectionRunner() const override; + ProjectExplorer::Macros predefinedMacros(const QStringList &cxxflags) const override; + + Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const override; + ProjectExplorer::WarningFlags warningFlags(const QStringList &cxxflags) const override; + + BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner() const override; + ProjectExplorer::HeaderPaths builtInHeaderPaths(const QStringList &cxxFlags, + const Utils::FileName &) const override; + void addToEnvironment(Utils::Environment &env) const override; + ProjectExplorer::IOutputParser *outputParser() const override; + + QVariantMap toMap() const override; + bool fromMap(const QVariantMap &data) override; + + std::unique_ptr createConfigurationWidget() override; + + bool operator ==(const ToolChain &other) const override; + + void setCompilerCommand(const Utils::FileName &file); + Utils::FileName compilerCommand() const override; + + QString makeCommand(const Utils::Environment &env) const override; + + ToolChain *clone() const override; + + void toolChainUpdated() override; + +protected: + IarToolChain(const IarToolChain &tc) = default; + +private: + explicit IarToolChain(Detection d); + explicit IarToolChain(Core::Id language, Detection d); + + ProjectExplorer::Abi m_targetAbi; + Utils::FileName m_compilerCommand; + + using MacrosCache = std::shared_ptr>; + mutable MacrosCache m_predefinedMacrosCache; + + friend class IarToolChainFactory; + friend class IarToolChainConfigWidget; +}; + +// IarToolChainFactory + +class IarToolChainFactory final : public ProjectExplorer::ToolChainFactory +{ + Q_OBJECT + +public: + IarToolChainFactory(); + QSet supportedLanguages() const override; + + bool canCreate() override; + ProjectExplorer::ToolChain *create(Core::Id language) override; + + bool canRestore(const QVariantMap &data) override; + ProjectExplorer::ToolChain *restore(const QVariantMap &data) override; +}; + +// IarToolChainConfigWidget + +class IarToolChainConfigWidget final : public ProjectExplorer::ToolChainConfigWidget +{ + Q_OBJECT + +public: + explicit IarToolChainConfigWidget(IarToolChain *tc); + +private: + void applyImpl() override; + void discardImpl() override { setFromToolchain(); } + bool isDirtyImpl() const override; + void makeReadOnlyImpl() override; + + void setFromToolchain(); + void handleCompilerCommandChange(); + + Utils::PathChooser *m_compilerCommand = nullptr; + ProjectExplorer::AbiWidget *m_abiWidget = nullptr; + ProjectExplorer::Macros m_macros; +}; + +} // namespace Internal +} // namespace BareMetal diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp index 0de4ea655d2..29a93d35bfd 100644 --- a/src/plugins/projectexplorer/abi.cpp +++ b/src/plugins/projectexplorer/abi.cpp @@ -661,6 +661,8 @@ QString Abi::toString(const Architecture &a) return QLatin1String("xtensa"); case X86Architecture: return QLatin1String("x86"); + case Mcs51Architecture: + return QLatin1String("mcs51"); case MipsArchitecture: return QLatin1String("mips"); case PowerPCArchitecture: @@ -722,6 +724,8 @@ QString Abi::toString(const BinaryFormat &bf) return QLatin1String("mach_o"); case RuntimeQmlFormat: return QLatin1String("qml_rt"); + case UbrofFormat: + return "ubrof"; case UnknownFormat: Q_FALLTHROUGH(); default: diff --git a/src/plugins/projectexplorer/abi.h b/src/plugins/projectexplorer/abi.h index 43243847c87..d8d9a9ee9f9 100644 --- a/src/plugins/projectexplorer/abi.h +++ b/src/plugins/projectexplorer/abi.h @@ -54,6 +54,7 @@ public: ShArchitecture, AvrArchitecture, XtensaArchitecture, + Mcs51Architecture, UnknownArchitecture }; @@ -108,6 +109,7 @@ public: MachOFormat, PEFormat, RuntimeQmlFormat, + UbrofFormat, UnknownFormat }; diff --git a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp index 513a163ed67..92d6da6b0c9 100644 --- a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp +++ b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp @@ -29,6 +29,7 @@ #include "qbsprojectmanagerconstants.h" #include +#include #include #include #include @@ -130,6 +131,8 @@ static QStringList toolchainList(const ProjectExplorer::ToolChain *tc) list << QLatin1String("mingw") << QLatin1String("gcc"); else if (tc->typeId() == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) list << QLatin1String("msvc"); + else if (tc->typeId() == BareMetal::Constants::IAREW_TOOLCHAIN_TYPEID) + list << QLatin1String("iar"); return list; }