aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/baremetal
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/baremetal')
-rw-r--r--src/plugins/baremetal/CMakeLists.txt30
-rw-r--r--src/plugins/baremetal/baremetal.pro18
-rw-r--r--src/plugins/baremetal/baremetal.qbs8
-rw-r--r--src/plugins/baremetal/baremetalconstants.h5
-rw-r--r--src/plugins/baremetal/baremetalcustomrunconfiguration.cpp9
-rw-r--r--src/plugins/baremetal/baremetalcustomrunconfiguration.h18
-rw-r--r--src/plugins/baremetal/baremetaldebugsupport.cpp29
-rw-r--r--src/plugins/baremetal/baremetaldebugsupport.h8
-rw-r--r--src/plugins/baremetal/baremetaldevice.cpp33
-rw-r--r--src/plugins/baremetal/baremetaldevice.h40
-rw-r--r--src/plugins/baremetal/baremetaldeviceconfigurationwidget.cpp10
-rw-r--r--src/plugins/baremetal/baremetaldeviceconfigurationwidget.h8
-rw-r--r--src/plugins/baremetal/baremetaldeviceconfigurationwizard.cpp8
-rw-r--r--src/plugins/baremetal/baremetaldeviceconfigurationwizard.h8
-rw-r--r--src/plugins/baremetal/baremetaldeviceconfigurationwizardpages.cpp6
-rw-r--r--src/plugins/baremetal/baremetaldeviceconfigurationwizardpages.h12
-rw-r--r--src/plugins/baremetal/baremetalgdbcommandsdeploystep.cpp6
-rw-r--r--src/plugins/baremetal/baremetalgdbcommandsdeploystep.h23
-rw-r--r--src/plugins/baremetal/baremetalplugin.cpp34
-rw-r--r--src/plugins/baremetal/baremetalplugin.h20
-rw-r--r--src/plugins/baremetal/baremetalrunconfiguration.cpp7
-rw-r--r--src/plugins/baremetal/baremetalrunconfiguration.h13
-rw-r--r--src/plugins/baremetal/defaultgdbserverprovider.cpp26
-rw-r--r--src/plugins/baremetal/defaultgdbserverprovider.h23
-rw-r--r--src/plugins/baremetal/gdbserverprovider.cpp62
-rw-r--r--src/plugins/baremetal/gdbserverprovider.h37
-rw-r--r--src/plugins/baremetal/gdbserverproviderchooser.cpp16
-rw-r--r--src/plugins/baremetal/gdbserverproviderchooser.h8
-rw-r--r--src/plugins/baremetal/gdbserverprovidermanager.cpp14
-rw-r--r--src/plugins/baremetal/gdbserverprovidermanager.h16
-rw-r--r--src/plugins/baremetal/gdbserverproviderprocess.cpp9
-rw-r--r--src/plugins/baremetal/gdbserverproviderprocess.h28
-rw-r--r--src/plugins/baremetal/gdbserverproviderssettingspage.cpp81
-rw-r--r--src/plugins/baremetal/gdbserverproviderssettingspage.h16
-rw-r--r--src/plugins/baremetal/iarewparser.cpp450
-rw-r--r--src/plugins/baremetal/iarewparser.h (renamed from src/plugins/baremetal/baremetaldeviceconfigurationfactory.cpp)56
-rw-r--r--src/plugins/baremetal/iarewtoolchain.cpp594
-rw-r--r--src/plugins/baremetal/iarewtoolchain.h139
-rw-r--r--src/plugins/baremetal/keilparser.cpp516
-rw-r--r--src/plugins/baremetal/keilparser.h (renamed from src/plugins/baremetal/baremetaldeviceconfigurationfactory.h)24
-rw-r--r--src/plugins/baremetal/keiltoolchain.cpp596
-rw-r--r--src/plugins/baremetal/keiltoolchain.h139
-rw-r--r--src/plugins/baremetal/openocdgdbserverprovider.cpp85
-rw-r--r--src/plugins/baremetal/openocdgdbserverprovider.h35
-rw-r--r--src/plugins/baremetal/sdccparser.cpp339
-rw-r--r--src/plugins/baremetal/sdccparser.h57
-rw-r--r--src/plugins/baremetal/sdcctoolchain.cpp564
-rw-r--r--src/plugins/baremetal/sdcctoolchain.h139
-rw-r--r--src/plugins/baremetal/stlinkutilgdbserverprovider.cpp80
-rw-r--r--src/plugins/baremetal/stlinkutilgdbserverprovider.h46
50 files changed, 4148 insertions, 400 deletions
diff --git a/src/plugins/baremetal/CMakeLists.txt b/src/plugins/baremetal/CMakeLists.txt
new file mode 100644
index 0000000000..f9d9bc0dc5
--- /dev/null
+++ b/src/plugins/baremetal/CMakeLists.txt
@@ -0,0 +1,30 @@
+add_qtc_plugin(BareMetal
+ DEPENDS QtcSsh
+ PLUGIN_DEPENDS Core Debugger ProjectExplorer
+ SOURCES
+ baremetal.qrc
+ baremetalconstants.h
+ baremetalcustomrunconfiguration.cpp baremetalcustomrunconfiguration.h
+ baremetaldebugsupport.cpp baremetaldebugsupport.h
+ baremetaldevice.cpp baremetaldevice.h
+ baremetaldeviceconfigurationwidget.cpp baremetaldeviceconfigurationwidget.h
+ baremetaldeviceconfigurationwizard.cpp baremetaldeviceconfigurationwizard.h
+ baremetaldeviceconfigurationwizardpages.cpp baremetaldeviceconfigurationwizardpages.h
+ baremetalgdbcommandsdeploystep.cpp baremetalgdbcommandsdeploystep.h
+ baremetalplugin.cpp baremetalplugin.h
+ baremetalrunconfiguration.cpp baremetalrunconfiguration.h
+ defaultgdbserverprovider.cpp defaultgdbserverprovider.h
+ gdbserverprovider.cpp gdbserverprovider.h
+ gdbserverproviderchooser.cpp gdbserverproviderchooser.h
+ gdbserverprovidermanager.cpp gdbserverprovidermanager.h
+ gdbserverproviderprocess.cpp gdbserverproviderprocess.h
+ gdbserverproviderssettingspage.cpp gdbserverproviderssettingspage.h
+ iarewparser.cpp iarewparser.h
+ iarewtoolchain.cpp iarewtoolchain.h
+ keilparser.cpp keilparser.h
+ keiltoolchain.cpp keiltoolchain.h
+ sdccparser.cpp sdccparser.h
+ sdcctoolchain.cpp sdcctoolchain.h
+ openocdgdbserverprovider.cpp openocdgdbserverprovider.h
+ stlinkutilgdbserverprovider.cpp stlinkutilgdbserverprovider.h
+)
diff --git a/src/plugins/baremetal/baremetal.pro b/src/plugins/baremetal/baremetal.pro
index 886cc98284..ac49b0041f 100644
--- a/src/plugins/baremetal/baremetal.pro
+++ b/src/plugins/baremetal/baremetal.pro
@@ -11,7 +11,6 @@ SOURCES += baremetalplugin.cpp \
baremetaldeviceconfigurationwizardpages.cpp \
baremetaldeviceconfigurationwizard.cpp \
baremetaldeviceconfigurationwidget.cpp \
- baremetaldeviceconfigurationfactory.cpp \
baremetaldebugsupport.cpp \
gdbserverproviderprocess.cpp \
gdbserverproviderssettingspage.cpp \
@@ -20,7 +19,13 @@ SOURCES += baremetalplugin.cpp \
gdbserverprovidermanager.cpp \
openocdgdbserverprovider.cpp \
defaultgdbserverprovider.cpp \
- stlinkutilgdbserverprovider.cpp
+ stlinkutilgdbserverprovider.cpp \
+ iarewtoolchain.cpp \
+ keiltoolchain.cpp \
+ sdcctoolchain.cpp \
+ iarewparser.cpp \
+ keilparser.cpp \
+ sdccparser.cpp \
HEADERS += baremetalplugin.h \
baremetalconstants.h \
@@ -28,7 +33,6 @@ HEADERS += baremetalplugin.h \
baremetaldevice.h \
baremetalrunconfiguration.h \
baremetalgdbcommandsdeploystep.h \
- baremetaldeviceconfigurationfactory.h \
baremetaldeviceconfigurationwidget.h \
baremetaldeviceconfigurationwizard.h \
baremetaldeviceconfigurationwizardpages.h \
@@ -40,7 +44,13 @@ HEADERS += baremetalplugin.h \
gdbserverprovidermanager.h \
openocdgdbserverprovider.h \
defaultgdbserverprovider.h \
- stlinkutilgdbserverprovider.h
+ stlinkutilgdbserverprovider.h \
+ iarewtoolchain.h \
+ keiltoolchain.h \
+ sdcctoolchain.h \
+ iarewparser.h \
+ keilparser.h \
+ sdccparser.h \
RESOURCES += \
baremetal.qrc
diff --git a/src/plugins/baremetal/baremetal.qbs b/src/plugins/baremetal/baremetal.qbs
index 04c1b228b1..018c2dc23b 100644
--- a/src/plugins/baremetal/baremetal.qbs
+++ b/src/plugins/baremetal/baremetal.qbs
@@ -10,13 +10,13 @@ QtcPlugin {
Depends { name: "Core" }
Depends { name: "Debugger" }
Depends { name: "ProjectExplorer" }
+ Depends { name: "TextEditor" }
files: [
"baremetal.qrc",
"baremetalconstants.h",
"baremetalcustomrunconfiguration.cpp", "baremetalcustomrunconfiguration.h",
"baremetaldevice.cpp", "baremetaldevice.h",
- "baremetaldeviceconfigurationfactory.cpp", "baremetaldeviceconfigurationfactory.h",
"baremetaldeviceconfigurationwidget.cpp", "baremetaldeviceconfigurationwidget.h",
"baremetaldeviceconfigurationwizard.cpp", "baremetaldeviceconfigurationwizard.h",
"baremetaldeviceconfigurationwizardpages.cpp", "baremetaldeviceconfigurationwizardpages.h",
@@ -32,5 +32,11 @@ QtcPlugin {
"openocdgdbserverprovider.cpp", "openocdgdbserverprovider.h",
"defaultgdbserverprovider.cpp", "defaultgdbserverprovider.h",
"stlinkutilgdbserverprovider.cpp", "stlinkutilgdbserverprovider.h",
+ "iarewtoolchain.cpp", "iarewtoolchain.h",
+ "keiltoolchain.cpp", "keiltoolchain.h",
+ "sdcctoolchain.cpp", "sdcctoolchain.h",
+ "iarewparser.cpp", "iarewparser.h",
+ "keilparser.cpp", "keilparser.h",
+ "sdccparser.cpp", "sdccparser.h",
]
}
diff --git a/src/plugins/baremetal/baremetalconstants.h b/src/plugins/baremetal/baremetalconstants.h
index def7271577..9f8a08cc50 100644
--- a/src/plugins/baremetal/baremetalconstants.h
+++ b/src/plugins/baremetal/baremetalconstants.h
@@ -41,5 +41,10 @@ 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";
+const char KEIL_TOOLCHAIN_TYPEID[] = "BareMetal.ToolChain.Keil";
+const char SDCC_TOOLCHAIN_TYPEID[] = "BareMetal.ToolChain.Sdcc";
+
} // namespace BareMetal
} // namespace Constants
diff --git a/src/plugins/baremetal/baremetalcustomrunconfiguration.cpp b/src/plugins/baremetal/baremetalcustomrunconfiguration.cpp
index 14b957d5e4..db4aac7622 100644
--- a/src/plugins/baremetal/baremetalcustomrunconfiguration.cpp
+++ b/src/plugins/baremetal/baremetalcustomrunconfiguration.cpp
@@ -24,11 +24,10 @@
****************************************************************************/
#include "baremetalcustomrunconfiguration.h"
-
#include "baremetalconstants.h"
-#include <projectexplorer/target.h>
#include <projectexplorer/runconfigurationaspects.h>
+#include <projectexplorer/target.h>
#include <qtsupport/qtoutputformatter.h>
@@ -38,10 +37,12 @@ using namespace ProjectExplorer;
namespace BareMetal {
namespace Internal {
+// BareMetalCustomRunConfiguration
+
BareMetalCustomRunConfiguration::BareMetalCustomRunConfiguration(Target *target, Core::Id id)
: RunConfiguration(target, id)
{
- auto exeAspect = addAspect<ExecutableAspect>();
+ const auto exeAspect = addAspect<ExecutableAspect>();
exeAspect->setSettingsKey("BareMetal.CustomRunConfig.Executable");
exeAspect->setPlaceHolderText(tr("Unknown"));
exeAspect->setDisplayStyle(BaseStringAspect::PathChooserDisplay);
@@ -49,7 +50,7 @@ BareMetalCustomRunConfiguration::BareMetalCustomRunConfiguration(Target *target,
exeAspect->setExpectedKind(PathChooser::Any);
addAspect<ArgumentsAspect>();
- addAspect<WorkingDirectoryAspect>(nullptr);
+ addAspect<WorkingDirectoryAspect>();
setDefaultDisplayName(RunConfigurationFactory::decoratedTargetName(tr("Custom Executable"), target));
}
diff --git a/src/plugins/baremetal/baremetalcustomrunconfiguration.h b/src/plugins/baremetal/baremetalcustomrunconfiguration.h
index 72b1500511..a7ccd48233 100644
--- a/src/plugins/baremetal/baremetalcustomrunconfiguration.h
+++ b/src/plugins/baremetal/baremetalcustomrunconfiguration.h
@@ -30,23 +30,29 @@
namespace BareMetal {
namespace Internal {
-class BareMetalCustomRunConfiguration : public ProjectExplorer::RunConfiguration
+// BareMetalCustomRunConfiguration
+
+class BareMetalCustomRunConfiguration final
+ : public ProjectExplorer::RunConfiguration
{
Q_OBJECT
public:
- BareMetalCustomRunConfiguration(ProjectExplorer::Target *target, Core::Id id);
+ explicit BareMetalCustomRunConfiguration(ProjectExplorer::Target *target, Core::Id id);
public:
static const char *Id;
- bool isConfigured() const override;
- ConfigurationState ensureConfigured(QString *errorMessage) override;
+ bool isConfigured() const final;
+ ConfigurationState ensureConfigured(QString *errorMessage) final;
};
-class BareMetalCustomRunConfigurationFactory : public ProjectExplorer::FixedRunConfigurationFactory
+// BareMetalCustomRunConfigurationFactory
+
+class BareMetalCustomRunConfigurationFactory final
+ : public ProjectExplorer::FixedRunConfigurationFactory
{
public:
- BareMetalCustomRunConfigurationFactory();
+ explicit BareMetalCustomRunConfigurationFactory();
};
} // namespace Internal
diff --git a/src/plugins/baremetal/baremetaldebugsupport.cpp b/src/plugins/baremetal/baremetaldebugsupport.cpp
index ab8783a446..cda24139df 100644
--- a/src/plugins/baremetal/baremetaldebugsupport.cpp
+++ b/src/plugins/baremetal/baremetaldebugsupport.cpp
@@ -30,8 +30,8 @@
#include "gdbserverprovider.h"
#include "gdbserverprovidermanager.h"
-#include <debugger/debuggerruncontrol.h>
#include <debugger/debuggerkitinformation.h>
+#include <debugger/debuggerruncontrol.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/buildsteplist.h>
@@ -52,10 +52,12 @@ using namespace ProjectExplorer;
namespace BareMetal {
namespace Internal {
+// BareMetalDebugSupport
+
BareMetalDebugSupport::BareMetalDebugSupport(RunControl *runControl)
: Debugger::DebuggerRunTool(runControl)
{
- auto dev = qSharedPointerCast<const BareMetalDevice>(device());
+ const auto dev = qSharedPointerCast<const BareMetalDevice>(device());
if (!dev) {
reportFailure(tr("Cannot debug: Kit has no device."));
return;
@@ -70,11 +72,9 @@ BareMetalDebugSupport::BareMetalDebugSupport(RunControl *runControl)
if (p->startupMode() == GdbServerProvider::StartupOnNetwork) {
Runnable r;
- r.executable = p->executable();
- // We need to wrap the command arguments depending on a host OS,
- // as the bare metal's GDB servers are launched on a host,
- // but not on a target.
- r.commandLineArguments = Utils::QtcProcess::joinArgs(p->arguments(), Utils::HostOsInfo::hostOs());
+ r.setCommandLine(p->command());
+ // Command arguments are in host OS style as the bare metal's GDB servers are launched
+ // on the host, not on that target.
m_gdbServer = new SimpleTargetRunner(runControl);
m_gdbServer->setRunnable(r);
addStartDependency(m_gdbServer);
@@ -83,9 +83,7 @@ BareMetalDebugSupport::BareMetalDebugSupport(RunControl *runControl)
void BareMetalDebugSupport::start()
{
- const auto rc = runControl()->runConfiguration();
- QTC_ASSERT(rc, reportFailure(); return);
- const auto exeAspect = rc->aspect<ExecutableAspect>();
+ const auto exeAspect = runControl()->aspect<ExecutableAspect>();
QTC_ASSERT(exeAspect, reportFailure(); return);
const QString bin = exeAspect->executable().toString();
@@ -98,10 +96,10 @@ void BareMetalDebugSupport::start()
return;
}
- const Target *target = rc->target();
+ const Target *target = runControl()->target();
QTC_ASSERT(target, reportFailure(); return);
- auto dev = qSharedPointerCast<const BareMetalDevice>(device());
+ const auto dev = qSharedPointerCast<const BareMetalDevice>(device());
QTC_ASSERT(dev, reportFailure(); return);
const GdbServerProvider *p = GdbServerProviderManager::findProvider(dev->gdbServerProviderId());
QTC_ASSERT(p, reportFailure(); return);
@@ -112,7 +110,7 @@ void BareMetalDebugSupport::start()
QString commands;
if (const BuildConfiguration *bc = target->activeBuildConfiguration()) {
if (BuildStepList *bsl = bc->stepList(BareMetalGdbCommandsDeployStep::stepId())) {
- foreach (const BareMetalGdbCommandsDeployStep *bs, bsl->allOfType<BareMetalGdbCommandsDeployStep>()) {
+ for (const BareMetalGdbCommandsDeployStep *bs : bsl->allOfType<BareMetalGdbCommandsDeployStep>()) {
if (!commands.endsWith("\n"))
commands.append("\n");
commands.append(bs->gdbCommands());
@@ -124,8 +122,8 @@ void BareMetalDebugSupport::start()
Runnable inferior;
inferior.executable = bin;
- if (auto aspect = rc->aspect<ArgumentsAspect>())
- inferior.commandLineArguments = aspect->arguments(rc->macroExpander());
+ if (const auto aspect = runControl()->aspect<ArgumentsAspect>())
+ inferior.commandLineArguments = aspect->arguments(runControl()->macroExpander());
setInferior(inferior);
setSymbolFile(bin);
setStartMode(AttachToRemoteServer);
@@ -133,6 +131,7 @@ void BareMetalDebugSupport::start()
setCommandsForReset(p->resetCommands());
setRemoteChannel(p->channel());
setUseContinueInsteadOfRun(true);
+ setUseExtendedRemote(p->useExtendedRemote());
DebuggerRunTool::start();
}
diff --git a/src/plugins/baremetal/baremetaldebugsupport.h b/src/plugins/baremetal/baremetaldebugsupport.h
index 2de31c467e..3a59343a9e 100644
--- a/src/plugins/baremetal/baremetaldebugsupport.h
+++ b/src/plugins/baremetal/baremetaldebugsupport.h
@@ -30,15 +30,17 @@
namespace BareMetal {
namespace Internal {
-class BareMetalDebugSupport : public Debugger::DebuggerRunTool
+// BareMetalDebugSupport
+
+class BareMetalDebugSupport final : public Debugger::DebuggerRunTool
{
Q_OBJECT
public:
- BareMetalDebugSupport(ProjectExplorer::RunControl *runControl);
+ explicit BareMetalDebugSupport(ProjectExplorer::RunControl *runControl);
private:
- void start() override;
+ void start() final;
ProjectExplorer::SimpleTargetRunner *m_gdbServer = nullptr;
};
diff --git a/src/plugins/baremetal/baremetaldevice.cpp b/src/plugins/baremetal/baremetaldevice.cpp
index 2be3a4dadd..340ca1a229 100644
--- a/src/plugins/baremetal/baremetaldevice.cpp
+++ b/src/plugins/baremetal/baremetaldevice.cpp
@@ -24,9 +24,13 @@
**
****************************************************************************/
+#include "baremetalconstants.h"
#include "baremetaldevice.h"
#include "baremetaldeviceconfigurationwidget.h"
+#include "baremetaldeviceconfigurationwizard.h"
+
#include "defaultgdbserverprovider.h"
+
#include "gdbserverprovidermanager.h"
#include "gdbserverproviderprocess.h"
@@ -44,6 +48,8 @@ namespace Internal {
const char gdbServerProviderIdKeyC[] = "GdbServerProviderId";
+// BareMetalDevice
+
BareMetalDevice::~BareMetalDevice()
{
if (GdbServerProvider *provider = GdbServerProviderManager::findProvider(m_gdbServerProviderId))
@@ -104,7 +110,7 @@ void BareMetalDevice::fromMap(const QVariantMap &map)
gdbServerProvider = provider->id();
} else {
const QSsh::SshConnectionParameters sshParams = sshParameters();
- auto newProvider = new DefaultGdbServerProvider;
+ const auto newProvider = new DefaultGdbServerProvider;
newProvider->setDisplayName(name);
newProvider->m_host = sshParams.host();
newProvider->m_port = sshParams.port();
@@ -124,11 +130,6 @@ QVariantMap BareMetalDevice::toMap() const
return map;
}
-BareMetalDevice::IDevice::Ptr BareMetalDevice::clone() const
-{
- return Ptr(new BareMetalDevice(*this));
-}
-
DeviceProcessSignalOperation::Ptr BareMetalDevice::signalOperation() const
{
return DeviceProcessSignalOperation::Ptr();
@@ -154,10 +155,24 @@ DeviceProcess *BareMetalDevice::createProcess(QObject *parent) const
return new GdbServerProviderProcess(sharedFromThis(), parent);
}
-BareMetalDevice::BareMetalDevice(const BareMetalDevice &other)
- : IDevice(other)
+// Factory
+
+BareMetalDeviceFactory::BareMetalDeviceFactory()
+ : IDeviceFactory(Constants::BareMetalOsType)
+{
+ setDisplayName(tr("Bare Metal Device"));
+ setCombinedIcon(":/baremetal/images/baremetaldevicesmall.png",
+ ":/baremetal/images/baremetaldevice.png");
+ setCanCreate(true);
+ setConstructionFunction(&BareMetalDevice::create);
+}
+
+IDevice::Ptr BareMetalDeviceFactory::create() const
{
- setGdbServerProviderId(other.gdbServerProviderId());
+ BareMetalDeviceConfigurationWizard wizard;
+ if (wizard.exec() != QDialog::Accepted)
+ return {};
+ return wizard.device();
}
} //namespace Internal
diff --git a/src/plugins/baremetal/baremetaldevice.h b/src/plugins/baremetal/baremetaldevice.h
index 50f099f8e4..b4d1b3afce 100644
--- a/src/plugins/baremetal/baremetaldevice.h
+++ b/src/plugins/baremetal/baremetaldevice.h
@@ -27,47 +27,59 @@
#pragma once
#include <projectexplorer/devicesupport/idevice.h>
+#include <projectexplorer/devicesupport/idevicefactory.h>
namespace BareMetal {
namespace Internal {
class GdbServerProvider;
-class BareMetalDevice : public ProjectExplorer::IDevice
+// BareMetalDevice
+
+class BareMetalDevice final : public ProjectExplorer::IDevice
{
public:
using Ptr = QSharedPointer<BareMetalDevice>;
using ConstPtr = QSharedPointer<const BareMetalDevice>;
static Ptr create() { return Ptr(new BareMetalDevice); }
- ~BareMetalDevice() override;
+ ~BareMetalDevice() final;
- QString displayType() const override;
- ProjectExplorer::IDeviceWidget *createWidget() override;
- Utils::OsType osType() const override;
- ProjectExplorer::IDevice::Ptr clone() const override;
+ QString displayType() const final;
+ ProjectExplorer::IDeviceWidget *createWidget() final;
+ Utils::OsType osType() const final;
- ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override;
+ ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const final;
- bool canCreateProcess() const override { return true; }
- ProjectExplorer::DeviceProcess *createProcess(QObject *parent) const override;
+ bool canCreateProcess() const final { return true; }
+ ProjectExplorer::DeviceProcess *createProcess(QObject *parent) const final;
QString gdbServerProviderId() const;
void setGdbServerProviderId(const QString &id);
void unregisterProvider(GdbServerProvider *provider);
void providerUpdated(GdbServerProvider *provider);
- void fromMap(const QVariantMap &map) override;
- QVariantMap toMap() const override;
+ void fromMap(const QVariantMap &map) final;
+ QVariantMap toMap() const final;
private:
- BareMetalDevice() = default;
- BareMetalDevice(const BareMetalDevice &other);
+ explicit BareMetalDevice() = default;
void setChannelByServerProvider(GdbServerProvider *provider);
- BareMetalDevice &operator=(const BareMetalDevice &);
QString m_gdbServerProviderId;
};
+// BareMetalDeviceFactory
+
+class BareMetalDeviceFactory final : public ProjectExplorer::IDeviceFactory
+{
+ Q_OBJECT
+
+public:
+ explicit BareMetalDeviceFactory();
+
+ ProjectExplorer::IDevice::Ptr create() const final;
+};
+
} //namespace Internal
} //namespace BareMetal
diff --git a/src/plugins/baremetal/baremetaldeviceconfigurationwidget.cpp b/src/plugins/baremetal/baremetaldeviceconfigurationwidget.cpp
index b1074323e2..a528bd4b8e 100644
--- a/src/plugins/baremetal/baremetaldeviceconfigurationwidget.cpp
+++ b/src/plugins/baremetal/baremetaldeviceconfigurationwidget.cpp
@@ -24,11 +24,11 @@
**
****************************************************************************/
-#include "baremetaldeviceconfigurationwidget.h"
#include "baremetaldevice.h"
+#include "baremetaldeviceconfigurationwidget.h"
-#include "gdbserverproviderchooser.h"
#include "gdbserverprovider.h"
+#include "gdbserverproviderchooser.h"
#include <utils/qtcassert.h>
@@ -37,6 +37,8 @@
namespace BareMetal {
namespace Internal {
+// BareMetalDeviceConfigurationWidget
+
BareMetalDeviceConfigurationWidget::BareMetalDeviceConfigurationWidget(
const ProjectExplorer::IDevice::Ptr &deviceConfig, QWidget *parent)
: IDeviceWidget(deviceConfig, parent)
@@ -44,7 +46,7 @@ BareMetalDeviceConfigurationWidget::BareMetalDeviceConfigurationWidget(
const auto dev = qSharedPointerCast<const BareMetalDevice>(device());
QTC_ASSERT(dev, return);
- auto formLayout = new QFormLayout(this);
+ const auto formLayout = new QFormLayout(this);
formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
m_gdbServerProviderChooser = new GdbServerProviderChooser(true, this);
@@ -58,7 +60,7 @@ BareMetalDeviceConfigurationWidget::BareMetalDeviceConfigurationWidget(
void BareMetalDeviceConfigurationWidget::gdbServerProviderChanged()
{
- auto dev = qSharedPointerCast<BareMetalDevice>(device());
+ const auto dev = qSharedPointerCast<BareMetalDevice>(device());
QTC_ASSERT(dev, return);
dev->setGdbServerProviderId(m_gdbServerProviderChooser->currentProviderId());
}
diff --git a/src/plugins/baremetal/baremetaldeviceconfigurationwidget.h b/src/plugins/baremetal/baremetaldeviceconfigurationwidget.h
index e56e7e76ce..ad8017f53f 100644
--- a/src/plugins/baremetal/baremetaldeviceconfigurationwidget.h
+++ b/src/plugins/baremetal/baremetaldeviceconfigurationwidget.h
@@ -33,7 +33,9 @@ namespace Internal {
class GdbServerProviderChooser;
-class BareMetalDeviceConfigurationWidget
+// BareMetalDeviceConfigurationWidget
+
+class BareMetalDeviceConfigurationWidget final
: public ProjectExplorer::IDeviceWidget
{
Q_OBJECT
@@ -44,9 +46,9 @@ public:
private:
void gdbServerProviderChanged();
- void updateDeviceFromUi() override;
+ void updateDeviceFromUi() final;
- GdbServerProviderChooser *m_gdbServerProviderChooser;
+ GdbServerProviderChooser *m_gdbServerProviderChooser = nullptr;
};
} // namespace Internal
diff --git a/src/plugins/baremetal/baremetaldeviceconfigurationwizard.cpp b/src/plugins/baremetal/baremetaldeviceconfigurationwizard.cpp
index 36a563ae88..7a4b05928b 100644
--- a/src/plugins/baremetal/baremetaldeviceconfigurationwizard.cpp
+++ b/src/plugins/baremetal/baremetaldeviceconfigurationwizard.cpp
@@ -24,16 +24,18 @@
**
****************************************************************************/
+#include "baremetalconstants.h"
+#include "baremetaldevice.h"
#include "baremetaldeviceconfigurationwizard.h"
#include "baremetaldeviceconfigurationwizardpages.h"
-#include "baremetaldevice.h"
-#include "baremetalconstants.h"
namespace BareMetal {
namespace Internal {
enum PageId { SetupPageId };
+// BareMetalDeviceConfigurationWizard
+
BareMetalDeviceConfigurationWizard::BareMetalDeviceConfigurationWizard(QWidget *parent) :
Utils::Wizard(parent),
m_setupPage(new BareMetalDeviceConfigurationWizardSetupPage(this))
@@ -45,7 +47,7 @@ BareMetalDeviceConfigurationWizard::BareMetalDeviceConfigurationWizard(QWidget *
ProjectExplorer::IDevice::Ptr BareMetalDeviceConfigurationWizard::device() const
{
- auto dev = BareMetalDevice::create();
+ const auto dev = BareMetalDevice::create();
dev->setupId(ProjectExplorer::IDevice::ManuallyAdded, Core::Id());
dev->setDisplayName(m_setupPage->configurationName());
dev->setType(Constants::BareMetalOsType);
diff --git a/src/plugins/baremetal/baremetaldeviceconfigurationwizard.h b/src/plugins/baremetal/baremetaldeviceconfigurationwizard.h
index 4663516fd9..79ada6a0a8 100644
--- a/src/plugins/baremetal/baremetaldeviceconfigurationwizard.h
+++ b/src/plugins/baremetal/baremetaldeviceconfigurationwizard.h
@@ -33,17 +33,19 @@ namespace Internal {
class BareMetalDeviceConfigurationWizardSetupPage;
-class BareMetalDeviceConfigurationWizard : public Utils::Wizard
+// BareMetalDeviceConfigurationWizard
+
+class BareMetalDeviceConfigurationWizard final : public Utils::Wizard
{
Q_OBJECT
public:
- BareMetalDeviceConfigurationWizard(QWidget *parent = nullptr);
+ explicit BareMetalDeviceConfigurationWizard(QWidget *parent = nullptr);
ProjectExplorer::IDevice::Ptr device() const;
private:
- BareMetalDeviceConfigurationWizardSetupPage *m_setupPage;
+ BareMetalDeviceConfigurationWizardSetupPage *m_setupPage = nullptr;
};
} // namespace Internal
diff --git a/src/plugins/baremetal/baremetaldeviceconfigurationwizardpages.cpp b/src/plugins/baremetal/baremetaldeviceconfigurationwizardpages.cpp
index 2c41e361a3..4e0e69b4f8 100644
--- a/src/plugins/baremetal/baremetaldeviceconfigurationwizardpages.cpp
+++ b/src/plugins/baremetal/baremetaldeviceconfigurationwizardpages.cpp
@@ -24,8 +24,8 @@
**
****************************************************************************/
-#include "baremetaldeviceconfigurationwizardpages.h"
#include "baremetaldevice.h"
+#include "baremetaldeviceconfigurationwizardpages.h"
#include "gdbserverproviderchooser.h"
@@ -38,13 +38,15 @@
namespace BareMetal {
namespace Internal {
+// BareMetalDeviceConfigurationWizardSetupPage
+
BareMetalDeviceConfigurationWizardSetupPage::BareMetalDeviceConfigurationWizardSetupPage(
QWidget *parent)
: QWizardPage(parent)
{
setTitle(tr("Set up GDB Server or Hardware Debugger"));
- auto formLayout = new QFormLayout(this);
+ const auto formLayout = new QFormLayout(this);
formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
m_nameLineEdit = new QLineEdit(this);
formLayout->addRow(tr("Name:"), m_nameLineEdit);
diff --git a/src/plugins/baremetal/baremetaldeviceconfigurationwizardpages.h b/src/plugins/baremetal/baremetaldeviceconfigurationwizardpages.h
index f47c8a79e9..27ac808108 100644
--- a/src/plugins/baremetal/baremetaldeviceconfigurationwizardpages.h
+++ b/src/plugins/baremetal/baremetaldeviceconfigurationwizardpages.h
@@ -37,23 +37,25 @@ namespace Internal {
class GdbServerProviderChooser;
-class BareMetalDeviceConfigurationWizardSetupPage : public QWizardPage
+// BareMetalDeviceConfigurationWizardSetupPage
+
+class BareMetalDeviceConfigurationWizardSetupPage final : public QWizardPage
{
Q_OBJECT
public:
explicit BareMetalDeviceConfigurationWizardSetupPage(QWidget *parent = nullptr);
- void initializePage() override;
- bool isComplete() const override;
+ void initializePage() final;
+ bool isComplete() const final;
QString configurationName() const;
QString gdbServerProviderId() const;
virtual QString defaultConfigurationName() const;
private:
- QLineEdit *m_nameLineEdit;
- GdbServerProviderChooser *m_gdbServerProviderChooser;
+ QLineEdit *m_nameLineEdit = nullptr;
+ GdbServerProviderChooser *m_gdbServerProviderChooser = nullptr;
};
} // namespace Internal
diff --git a/src/plugins/baremetal/baremetalgdbcommandsdeploystep.cpp b/src/plugins/baremetal/baremetalgdbcommandsdeploystep.cpp
index fd79faf4bd..60f34a47e7 100644
--- a/src/plugins/baremetal/baremetalgdbcommandsdeploystep.cpp
+++ b/src/plugins/baremetal/baremetalgdbcommandsdeploystep.cpp
@@ -34,10 +34,12 @@ namespace Internal {
const char GdbCommandsKey[] = "BareMetal.GdbCommandsStep.Commands";
+// BareMetalGdbCommandsDeployStepWidget
+
BareMetalGdbCommandsDeployStepWidget::BareMetalGdbCommandsDeployStepWidget(BareMetalGdbCommandsDeployStep &step)
: BuildStepConfigWidget(&step), m_step(step)
{
- auto fl = new QFormLayout(this);
+ const auto fl = new QFormLayout(this);
fl->setMargin(0);
fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
setLayout(fl);
@@ -62,6 +64,8 @@ QString BareMetalGdbCommandsDeployStepWidget::summaryText() const
return displayName();
}
+// BareMetalGdbCommandsDeployStep
+
BareMetalGdbCommandsDeployStep::BareMetalGdbCommandsDeployStep(BuildStepList *bsl)
: BuildStep(bsl, stepId())
{
diff --git a/src/plugins/baremetal/baremetalgdbcommandsdeploystep.h b/src/plugins/baremetal/baremetalgdbcommandsdeploystep.h
index 3507bbcb49..b5c85466be 100644
--- a/src/plugins/baremetal/baremetalgdbcommandsdeploystep.h
+++ b/src/plugins/baremetal/baremetalgdbcommandsdeploystep.h
@@ -27,23 +27,25 @@
#include <projectexplorer/buildstep.h>
-#include <QVariantMap>
#include <QPlainTextEdit>
+#include <QVariantMap>
namespace BareMetal {
namespace Internal {
-class BareMetalGdbCommandsDeployStep : public ProjectExplorer::BuildStep
+// BareMetalGdbCommandsDeployStep
+
+class BareMetalGdbCommandsDeployStep final : public ProjectExplorer::BuildStep
{
Q_OBJECT
public:
explicit BareMetalGdbCommandsDeployStep(ProjectExplorer::BuildStepList *bsl);
- bool fromMap(const QVariantMap &map) override;
- QVariantMap toMap() const override;
+ bool fromMap(const QVariantMap &map) final;
+ QVariantMap toMap() const final;
- ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
+ ProjectExplorer::BuildStepConfigWidget *createConfigWidget() final;
static Core::Id stepId();
static QString displayName();
@@ -52,13 +54,16 @@ public:
QString gdbCommands() const;
private:
- bool init() override;
- void doRun() override;
+ bool init() final;
+ void doRun() final;
QString m_gdbCommands;
};
-class BareMetalGdbCommandsDeployStepWidget: public ProjectExplorer::BuildStepConfigWidget
+// BareMetalGdbCommandsDeployStepWidget
+
+class BareMetalGdbCommandsDeployStepWidget final
+ : public ProjectExplorer::BuildStepConfigWidget
{
Q_OBJECT
@@ -71,7 +76,7 @@ private:
QString summaryText() const;
BareMetalGdbCommandsDeployStep &m_step;
- QPlainTextEdit *m_commands;
+ QPlainTextEdit *m_commands = nullptr;
};
} // namespace Internal
diff --git a/src/plugins/baremetal/baremetalplugin.cpp b/src/plugins/baremetal/baremetalplugin.cpp
index 42290772e4..0ce4c51835 100644
--- a/src/plugins/baremetal/baremetalplugin.cpp
+++ b/src/plugins/baremetal/baremetalplugin.cpp
@@ -24,46 +24,52 @@
**
****************************************************************************/
-#include "baremetalplugin.h"
#include "baremetalconstants.h"
#include "baremetalcustomrunconfiguration.h"
-#include "baremetaldeviceconfigurationfactory.h"
#include "baremetaldebugsupport.h"
+#include "baremetaldevice.h"
+#include "baremetalplugin.h"
#include "baremetalrunconfiguration.h"
-#include "gdbserverproviderssettingspage.h"
#include "gdbserverprovidermanager.h"
+#include "gdbserverproviderssettingspage.h"
-#include <coreplugin/icore.h>
-#include <coreplugin/icontext.h>
+#include "iarewtoolchain.h"
+#include "keiltoolchain.h"
+#include "sdcctoolchain.h"
+
+#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
-#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/coreconstants.h>
+#include <coreplugin/icontext.h>
+#include <coreplugin/icore.h>
using namespace ProjectExplorer;
namespace BareMetal {
namespace Internal {
-class BareMetalPluginRunData
+// BareMetalPluginPrivate
+
+class BareMetalPluginPrivate
{
public:
- BareMetalDeviceConfigurationFactory deviceConfigurationFactory;
+ IarToolChainFactory iarToolChainFactory;
+ KeilToolchainFactory keilToolChainFactory;
+ SdccToolChainFactory sdccToolChainFactory;
+ BareMetalDeviceFactory deviceFactory;
BareMetalRunConfigurationFactory runConfigurationFactory;
BareMetalCustomRunConfigurationFactory customRunConfigurationFactory;
GdbServerProvidersSettingsPage gdbServerProviderSettinsPage;
GdbServerProviderManager gdbServerProviderManager;
};
-BareMetalPlugin::BareMetalPlugin()
-{
- setObjectName(QLatin1String("BareMetalPlugin"));
-}
+// BareMetalPlugin
BareMetalPlugin::~BareMetalPlugin()
{
- delete m_runData;
+ delete d;
}
bool BareMetalPlugin::initialize(const QStringList &arguments, QString *errorString)
@@ -71,7 +77,7 @@ bool BareMetalPlugin::initialize(const QStringList &arguments, QString *errorStr
Q_UNUSED(arguments)
Q_UNUSED(errorString)
- m_runData = new BareMetalPluginRunData;
+ d = new BareMetalPluginPrivate;
auto constraint = [](RunConfiguration *runConfig) {
const QByteArray idStr = runConfig->id().name();
diff --git a/src/plugins/baremetal/baremetalplugin.h b/src/plugins/baremetal/baremetalplugin.h
index 17ecbcc85d..a9ced735db 100644
--- a/src/plugins/baremetal/baremetalplugin.h
+++ b/src/plugins/baremetal/baremetalplugin.h
@@ -31,23 +31,29 @@
namespace BareMetal {
namespace Internal {
-class BareMetalPluginRunData;
+// BareMetalPlugin
-class BareMetalPlugin : public ExtensionSystem::IPlugin
+class BareMetalPlugin final : public ExtensionSystem::IPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "BareMetal.json")
-public:
- BareMetalPlugin();
-
-private:
~BareMetalPlugin() final;
bool initialize(const QStringList &arguments, QString *errorString) final;
void extensionsInitialized() final;
- BareMetalPluginRunData *m_runData;
+ class BareMetalPluginPrivate *d = nullptr;
+
+#ifdef WITH_TESTS
+private slots:
+ void testIarOutputParsers_data();
+ void testIarOutputParsers();
+ void testKeilOutputParsers_data();
+ void testKeilOutputParsers();
+ void testSdccOutputParsers_data();
+ void testSdccOutputParsers();
+#endif // WITH_TESTS
};
} // namespace Internal
diff --git a/src/plugins/baremetal/baremetalrunconfiguration.cpp b/src/plugins/baremetal/baremetalrunconfiguration.cpp
index cdfa2ddca6..8ba44b9343 100644
--- a/src/plugins/baremetal/baremetalrunconfiguration.cpp
+++ b/src/plugins/baremetal/baremetalrunconfiguration.cpp
@@ -23,9 +23,8 @@
**
****************************************************************************/
-#include "baremetalrunconfiguration.h"
-
#include "baremetalconstants.h"
+#include "baremetalrunconfiguration.h"
#include <projectexplorer/buildtargetinfo.h>
#include <projectexplorer/project.h>
@@ -43,7 +42,7 @@ namespace Internal {
BareMetalRunConfiguration::BareMetalRunConfiguration(Target *target, Core::Id id)
: RunConfiguration(target, id)
{
- auto exeAspect = addAspect<ExecutableAspect>();
+ const auto exeAspect = addAspect<ExecutableAspect>();
exeAspect->setDisplayStyle(BaseStringAspect::LabelDisplay);
exeAspect->setPlaceHolderText(tr("Unknown"));
@@ -62,7 +61,7 @@ BareMetalRunConfiguration::BareMetalRunConfiguration(Target *target, Core::Id id
void BareMetalRunConfiguration::updateTargetInformation()
{
- const BuildTargetInfo bti = target()->applicationTargets().buildTargetInfo(buildKey());
+ const BuildTargetInfo bti = buildTargetInfo();
aspect<ExecutableAspect>()->setExecutable(bti.targetFilePath);
emit enabledChanged();
}
diff --git a/src/plugins/baremetal/baremetalrunconfiguration.h b/src/plugins/baremetal/baremetalrunconfiguration.h
index 9699bae1ea..dfc426e8c2 100644
--- a/src/plugins/baremetal/baremetalrunconfiguration.h
+++ b/src/plugins/baremetal/baremetalrunconfiguration.h
@@ -30,12 +30,14 @@
namespace BareMetal {
namespace Internal {
-class BareMetalRunConfiguration : public ProjectExplorer::RunConfiguration
+// BareMetalRunConfiguration
+
+class BareMetalRunConfiguration final : public ProjectExplorer::RunConfiguration
{
Q_OBJECT
public:
- BareMetalRunConfiguration(ProjectExplorer::Target *target, Core::Id id);
+ explicit BareMetalRunConfiguration(ProjectExplorer::Target *target, Core::Id id);
static const char *IdPrefix;
@@ -43,10 +45,13 @@ private:
void updateTargetInformation();
};
-class BareMetalRunConfigurationFactory : public ProjectExplorer::RunConfigurationFactory
+// BareMetalRunConfigurationFactory
+
+class BareMetalRunConfigurationFactory final
+ : public ProjectExplorer::RunConfigurationFactory
{
public:
- BareMetalRunConfigurationFactory();
+ explicit BareMetalRunConfigurationFactory();
};
} // namespace Internal
diff --git a/src/plugins/baremetal/defaultgdbserverprovider.cpp b/src/plugins/baremetal/defaultgdbserverprovider.cpp
index 10ade87396..49d126479d 100644
--- a/src/plugins/baremetal/defaultgdbserverprovider.cpp
+++ b/src/plugins/baremetal/defaultgdbserverprovider.cpp
@@ -23,14 +23,15 @@
**
****************************************************************************/
-#include "defaultgdbserverprovider.h"
#include "baremetalconstants.h"
+#include "defaultgdbserverprovider.h"
#include "gdbserverprovidermanager.h"
#include <utils/qtcassert.h>
#include <coreplugin/variablechooser.h>
+#include <QCheckBox>
#include <QFormLayout>
#include <QPlainTextEdit>
@@ -40,10 +41,10 @@ namespace Internal {
static const char hostKeyC[] = "BareMetal.DefaultGdbServerProvider.Host";
static const char portKeyC[] = "BareMetal.DefaultGdbServerProvider.Port";
+// DefaultGdbServerProvider
+
DefaultGdbServerProvider::DefaultGdbServerProvider()
: GdbServerProvider(QLatin1String(Constants::DEFAULT_PROVIDER_ID))
- , m_host(QLatin1String("localhost"))
- , m_port(3333)
{
}
@@ -132,6 +133,8 @@ GdbServerProviderConfigWidget *DefaultGdbServerProvider::configurationWidget()
return new DefaultGdbServerProviderConfigWidget(this);
}
+// DefaultGdbServerProviderFactory
+
DefaultGdbServerProviderFactory::DefaultGdbServerProviderFactory()
{
setId(QLatin1String(Constants::DEFAULT_PROVIDER_ID));
@@ -152,14 +155,16 @@ bool DefaultGdbServerProviderFactory::canRestore(const QVariantMap &data) const
GdbServerProvider *DefaultGdbServerProviderFactory::restore(const QVariantMap &data)
{
- auto p = new DefaultGdbServerProvider;
- auto updated = data;
+ const auto p = new DefaultGdbServerProvider;
+ const auto updated = data;
if (p->fromMap(updated))
return p;
delete p;
return nullptr;
}
+// GdbServerProviderConfigWidget
+
DefaultGdbServerProviderConfigWidget::DefaultGdbServerProviderConfigWidget(
DefaultGdbServerProvider *provider)
: GdbServerProviderConfigWidget(provider)
@@ -169,6 +174,9 @@ DefaultGdbServerProviderConfigWidget::DefaultGdbServerProviderConfigWidget(
m_hostWidget = new HostWidget(this);
m_mainLayout->addRow(tr("Host:"), m_hostWidget);
+ m_useExtendedRemoteCheckBox = new QCheckBox(this);
+ m_useExtendedRemoteCheckBox->setToolTip("Use GDB target extended-remote");
+ m_mainLayout->addRow(tr("Extended mode:"), m_useExtendedRemoteCheckBox);
m_initCommandsTextEdit = new QPlainTextEdit(this);
m_initCommandsTextEdit->setToolTip(defaultInitCommandsTooltip());
m_mainLayout->addRow(tr("Init commands:"), m_initCommandsTextEdit);
@@ -179,12 +187,14 @@ DefaultGdbServerProviderConfigWidget::DefaultGdbServerProviderConfigWidget(
addErrorLabel();
setFromProvider();
- auto chooser = new Core::VariableChooser(this);
+ const auto chooser = new Core::VariableChooser(this);
chooser->addSupportedWidget(m_initCommandsTextEdit);
chooser->addSupportedWidget(m_resetCommandsTextEdit);
connect(m_hostWidget, &HostWidget::dataChanged,
this, &GdbServerProviderConfigWidget::dirty);
+ connect(m_useExtendedRemoteCheckBox, &QCheckBox::stateChanged,
+ this, &GdbServerProviderConfigWidget::dirty);
connect(m_initCommandsTextEdit, &QPlainTextEdit::textChanged,
this, &GdbServerProviderConfigWidget::dirty);
connect(m_resetCommandsTextEdit, &QPlainTextEdit::textChanged,
@@ -198,6 +208,7 @@ void DefaultGdbServerProviderConfigWidget::applyImpl()
p->setHost(m_hostWidget->host());
p->setPort(m_hostWidget->port());
+ p->setUseExtendedRemote(m_useExtendedRemoteCheckBox->isChecked());
p->setInitCommands(m_initCommandsTextEdit->toPlainText());
p->setResetCommands(m_resetCommandsTextEdit->toPlainText());
}
@@ -212,9 +223,10 @@ void DefaultGdbServerProviderConfigWidget::setFromProvider()
const auto p = static_cast<DefaultGdbServerProvider *>(provider());
Q_ASSERT(p);
- QSignalBlocker blocker(this);
+ const QSignalBlocker blocker(this);
m_hostWidget->setHost(p->m_host);
m_hostWidget->setPort(p->m_port);
+ m_useExtendedRemoteCheckBox->setChecked(p->useExtendedRemote());
m_initCommandsTextEdit->setPlainText(p->initCommands());
m_resetCommandsTextEdit->setPlainText(p->resetCommands());
}
diff --git a/src/plugins/baremetal/defaultgdbserverprovider.h b/src/plugins/baremetal/defaultgdbserverprovider.h
index f5cb1dd3db..82b7e78160 100644
--- a/src/plugins/baremetal/defaultgdbserverprovider.h
+++ b/src/plugins/baremetal/defaultgdbserverprovider.h
@@ -33,7 +33,9 @@ namespace Internal {
class DefaultGdbServerProviderConfigWidget;
class DefaultGdbServerProviderFactory;
-class DefaultGdbServerProvider : public GdbServerProvider
+// DefaultGdbServerProvider
+
+class DefaultGdbServerProvider final : public GdbServerProvider
{
public:
QString typeDisplayName() const final;
@@ -60,15 +62,17 @@ private:
explicit DefaultGdbServerProvider();
explicit DefaultGdbServerProvider(const DefaultGdbServerProvider &);
- QString m_host;
- quint16 m_port;
+ QString m_host = QLatin1String("localhost");
+ quint16 m_port = 3333;
friend class DefaultGdbServerProviderConfigWidget;
friend class DefaultGdbServerProviderFactory;
friend class BareMetalDevice;
};
-class DefaultGdbServerProviderFactory : public GdbServerProviderFactory
+// DefaultGdbServerProviderFactory
+
+class DefaultGdbServerProviderFactory final : public GdbServerProviderFactory
{
Q_OBJECT
@@ -81,7 +85,9 @@ public:
GdbServerProvider *restore(const QVariantMap &data) final;
};
-class DefaultGdbServerProviderConfigWidget : public GdbServerProviderConfigWidget
+// DefaultGdbServerProviderConfigWidget
+
+class DefaultGdbServerProviderConfigWidget final : public GdbServerProviderConfigWidget
{
Q_OBJECT
@@ -94,9 +100,10 @@ private:
void setFromProvider();
- HostWidget *m_hostWidget;
- QPlainTextEdit *m_initCommandsTextEdit;
- QPlainTextEdit *m_resetCommandsTextEdit;
+ HostWidget *m_hostWidget = nullptr;
+ QCheckBox *m_useExtendedRemoteCheckBox = nullptr;
+ QPlainTextEdit *m_initCommandsTextEdit = nullptr;
+ QPlainTextEdit *m_resetCommandsTextEdit = nullptr;
};
} // namespace Internal
diff --git a/src/plugins/baremetal/gdbserverprovider.cpp b/src/plugins/baremetal/gdbserverprovider.cpp
index cf633d8602..520e8fb30f 100644
--- a/src/plugins/baremetal/gdbserverprovider.cpp
+++ b/src/plugins/baremetal/gdbserverprovider.cpp
@@ -23,22 +23,21 @@
**
****************************************************************************/
+#include "baremetaldevice.h"
#include "gdbserverprovider.h"
#include "gdbserverprovidermanager.h"
-#include "baremetaldevice.h"
-#include <utils/qtcassert.h>
#include <utils/environment.h>
+#include <utils/qtcassert.h>
+#include <QComboBox>
#include <QCoreApplication>
-#include <QUuid>
-
#include <QFormLayout>
-#include <QLineEdit>
#include <QLabel>
-#include <QComboBox>
-#include <QSpinBox>
+#include <QLineEdit>
#include <QPlainTextEdit>
+#include <QSpinBox>
+#include <QUuid>
namespace BareMetal {
namespace Internal {
@@ -48,6 +47,7 @@ const char displayNameKeyC[] = "BareMetal.GdbServerProvider.DisplayName";
const char startupModeKeyC[] = "BareMetal.GdbServerProvider.Mode";
const char initCommandsKeyC[] = "BareMetal.GdbServerProvider.InitCommands";
const char resetCommandsKeyC[] = "BareMetal.GdbServerProvider.ResetCommands";
+const char useExtendedRemoteKeyC[] = "BareMetal.GdbServerProvider.UseExtendedRemote";
static QString createId(const QString &id)
{
@@ -56,9 +56,10 @@ static QString createId(const QString &id)
return newId;
}
+// GdbServerProvider
+
GdbServerProvider::GdbServerProvider(const QString &id)
: m_id(createId(id))
- , m_startupMode(NoStartup)
{
}
@@ -67,6 +68,7 @@ GdbServerProvider::GdbServerProvider(const GdbServerProvider &other)
, m_startupMode(other.m_startupMode)
, m_initCommands(other.m_initCommands)
, m_resetCommands(other.m_resetCommands)
+ , m_useExtendedRemote(other.useExtendedRemote())
{
m_displayName = QCoreApplication::translate(
"BareMetal::GdbServerProvider", "Clone of %1")
@@ -121,6 +123,16 @@ void GdbServerProvider::setInitCommands(const QString &cmds)
m_initCommands = cmds;
}
+bool GdbServerProvider::useExtendedRemote() const
+{
+ return m_useExtendedRemote;
+}
+
+void GdbServerProvider::setUseExtendedRemote(bool useExtendedRemote)
+{
+ m_useExtendedRemote = useExtendedRemote;
+}
+
QString GdbServerProvider::resetCommands() const
{
return m_resetCommands;
@@ -131,14 +143,9 @@ void GdbServerProvider::setResetCommands(const QString &cmds)
m_resetCommands = cmds;
}
-QString GdbServerProvider::executable() const
+Utils::CommandLine GdbServerProvider::command() const
{
- return QString();
-}
-
-QStringList GdbServerProvider::arguments() const
-{
- return QStringList();
+ return {};
}
bool GdbServerProvider::operator==(const GdbServerProvider &other) const
@@ -153,7 +160,8 @@ bool GdbServerProvider::operator==(const GdbServerProvider &other) const
return thisId == otherId
&& m_startupMode == other.m_startupMode
&& m_initCommands == other.m_initCommands
- && m_resetCommands == other.m_resetCommands;
+ && m_resetCommands == other.m_resetCommands
+ && m_useExtendedRemote == other.m_useExtendedRemote;
}
QVariantMap GdbServerProvider::toMap() const
@@ -163,7 +171,8 @@ QVariantMap GdbServerProvider::toMap() const
{QLatin1String(displayNameKeyC), m_displayName},
{QLatin1String(startupModeKeyC), m_startupMode},
{QLatin1String(initCommandsKeyC), m_initCommands},
- {QLatin1String(resetCommandsKeyC), m_resetCommands}
+ {QLatin1String(resetCommandsKeyC), m_resetCommands},
+ {QLatin1String(useExtendedRemoteKeyC), m_useExtendedRemote},
};
}
@@ -201,9 +210,12 @@ bool GdbServerProvider::fromMap(const QVariantMap &data)
m_startupMode = static_cast<StartupMode>(data.value(QLatin1String(startupModeKeyC)).toInt());
m_initCommands = data.value(QLatin1String(initCommandsKeyC)).toString();
m_resetCommands = data.value(QLatin1String(resetCommandsKeyC)).toString();
+ m_useExtendedRemote = data.value(QLatin1String(useExtendedRemoteKeyC)).toBool();
return true;
}
+// GdbServerProviderFactory
+
QString GdbServerProviderFactory::id() const
{
return m_id;
@@ -234,6 +246,8 @@ void GdbServerProviderFactory::idToMap(QVariantMap &data, const QString &id)
data.insert(QLatin1String(idKeyC), id);
}
+// GdbServerProviderConfigWidget
+
GdbServerProviderConfigWidget::GdbServerProviderConfigWidget(
GdbServerProvider *provider)
: m_provider(provider)
@@ -258,7 +272,7 @@ GdbServerProviderConfigWidget::GdbServerProviderConfigWidget(
connect(m_nameLineEdit, &QLineEdit::textChanged,
this, &GdbServerProviderConfigWidget::dirty);
connect(m_startupModeComboBox,
- static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &GdbServerProviderConfigWidget::dirty);
}
@@ -354,7 +368,7 @@ void GdbServerProviderConfigWidget::clearErrorMessage()
void GdbServerProviderConfigWidget::setFromProvider()
{
- QSignalBlocker blocker(this);
+ const QSignalBlocker blocker(this);
m_nameLineEdit->setText(m_provider->displayName());
setStartupMode(m_provider->startupMode());
}
@@ -373,6 +387,8 @@ QString GdbServerProviderConfigWidget::defaultResetCommandsTooltip()
"The MCU should be halted after these commands.");
}
+// HostWidget
+
HostWidget::HostWidget(QWidget *parent)
: QWidget(parent)
{
@@ -383,20 +399,20 @@ HostWidget::HostWidget(QWidget *parent)
m_portSpinBox->setRange(0, 65535);
m_portSpinBox->setToolTip(tr("Enter TCP/IP port which will be listened by "
"the GDB server provider."));
- auto layout = new QHBoxLayout(this);
+ const auto layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_hostLineEdit);
layout->addWidget(m_portSpinBox);
connect(m_hostLineEdit, &QLineEdit::textChanged,
this, &HostWidget::dataChanged);
- connect(m_portSpinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
+ connect(m_portSpinBox, QOverload<int>::of(&QSpinBox::valueChanged),
this, &HostWidget::dataChanged);
}
void HostWidget::setHost(const QString &host)
{
- QSignalBlocker blocker(this);
+ const QSignalBlocker blocker(this);
m_hostLineEdit->setText(host);
}
@@ -407,7 +423,7 @@ QString HostWidget::host() const
void HostWidget::setPort(const quint16 &port)
{
- QSignalBlocker blocker(this);
+ const QSignalBlocker blocker(this);
m_portSpinBox->setValue(port);
}
diff --git a/src/plugins/baremetal/gdbserverprovider.h b/src/plugins/baremetal/gdbserverprovider.h
index 8ca0777ea7..8d91408a2e 100644
--- a/src/plugins/baremetal/gdbserverprovider.h
+++ b/src/plugins/baremetal/gdbserverprovider.h
@@ -33,12 +33,13 @@
#include <utils/fileutils.h>
QT_BEGIN_NAMESPACE
+class QCheckBox;
+class QComboBox;
class QFormLayout;
-class QLineEdit;
class QLabel;
-class QComboBox;
-class QSpinBox;
+class QLineEdit;
class QPlainTextEdit;
+class QSpinBox;
QT_END_NAMESPACE
namespace BareMetal {
@@ -48,6 +49,8 @@ class BareMetalDevice;
class GdbServerProviderConfigWidget;
class GdbServerProviderManager;
+// GdbServerProvider
+
class GdbServerProvider
{
public:
@@ -68,6 +71,7 @@ public:
StartupMode startupMode() const;
QString initCommands() const;
QString resetCommands() const;
+ bool useExtendedRemote() const;
virtual bool operator==(const GdbServerProvider &) const;
@@ -80,8 +84,7 @@ public:
virtual QVariantMap toMap() const;
- virtual QString executable() const;
- virtual QStringList arguments() const;
+ virtual Utils::CommandLine command() const;
virtual bool isValid() const;
virtual bool canStartupMode(StartupMode) const;
@@ -96,6 +99,7 @@ protected:
void setStartupMode(StartupMode);
void setInitCommands(const QString &);
void setResetCommands(const QString &);
+ void setUseExtendedRemote(bool);
void providerUpdated();
@@ -104,14 +108,17 @@ protected:
private:
QString m_id;
mutable QString m_displayName;
- StartupMode m_startupMode;
+ StartupMode m_startupMode = NoStartup;
QString m_initCommands;
QString m_resetCommands;
QSet<BareMetalDevice *> m_devices;
+ bool m_useExtendedRemote = false;
friend class GdbServerProviderConfigWidget;
};
+// GdbServerProviderFactory
+
class GdbServerProviderFactory : public QObject
{
Q_OBJECT
@@ -137,6 +144,8 @@ private:
QString m_id;
};
+// GdbServerProviderConfigWidget
+
class GdbServerProviderConfigWidget : public QWidget
{
Q_OBJECT
@@ -166,18 +175,20 @@ protected:
static QString defaultInitCommandsTooltip();
static QString defaultResetCommandsTooltip();
- QFormLayout *m_mainLayout;
- QLineEdit *m_nameLineEdit;
- QComboBox *m_startupModeComboBox;
+ QFormLayout *m_mainLayout = nullptr;
+ QLineEdit *m_nameLineEdit = nullptr;
+ QComboBox *m_startupModeComboBox = nullptr;
private:
void setFromProvider();
- GdbServerProvider *m_provider;
+ GdbServerProvider *m_provider = nullptr;
QLabel *m_errorLabel = nullptr;
};
-class HostWidget : public QWidget
+// HostWidget
+
+class HostWidget final : public QWidget
{
Q_OBJECT
@@ -193,8 +204,8 @@ signals:
void dataChanged();
private:
- QLineEdit *m_hostLineEdit;
- QSpinBox *m_portSpinBox;
+ QLineEdit *m_hostLineEdit = nullptr;
+ QSpinBox *m_portSpinBox = nullptr;
};
} // namespace Internal
diff --git a/src/plugins/baremetal/gdbserverproviderchooser.cpp b/src/plugins/baremetal/gdbserverproviderchooser.cpp
index 043d71bd2f..764a9ee0cd 100644
--- a/src/plugins/baremetal/gdbserverproviderchooser.cpp
+++ b/src/plugins/baremetal/gdbserverproviderchooser.cpp
@@ -23,11 +23,11 @@
**
****************************************************************************/
-#include "gdbserverproviderchooser.h"
+#include "baremetalconstants.h"
-#include "gdbserverprovidermanager.h"
#include "gdbserverprovider.h"
-#include "baremetalconstants.h"
+#include "gdbserverproviderchooser.h"
+#include "gdbserverprovidermanager.h"
#include <coreplugin/icore.h>
@@ -39,6 +39,8 @@
namespace BareMetal {
namespace Internal {
+// GdbServerProviderChooser
+
GdbServerProviderChooser::GdbServerProviderChooser(
bool useManageButton, QWidget *parent)
: QWidget(parent)
@@ -49,13 +51,13 @@ GdbServerProviderChooser::GdbServerProviderChooser(
m_manageButton->setEnabled(useManageButton);
m_manageButton->setVisible(useManageButton);
- auto layout = new QHBoxLayout(this);
+ const auto layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_chooser);
layout->addWidget(m_manageButton);
setFocusProxy(m_manageButton);
- connect(m_chooser, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ connect(m_chooser, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &GdbServerProviderChooser::currentIndexChanged);
connect(m_manageButton, &QAbstractButton::clicked,
this, &GdbServerProviderChooser::manageButtonClicked);
@@ -101,14 +103,14 @@ QString GdbServerProviderChooser::providerText(const GdbServerProvider *provider
void GdbServerProviderChooser::populate()
{
- QSignalBlocker blocker(m_chooser);
+ const QSignalBlocker blocker(m_chooser);
m_chooser->clear();
m_chooser->addItem(tr("None"));
for (const GdbServerProvider *p : GdbServerProviderManager::providers()) {
if (!providerMatches(p))
continue;
- m_chooser->addItem(providerText(p), qVariantFromValue(p->id()));
+ m_chooser->addItem(providerText(p), QVariant::fromValue(p->id()));
}
}
diff --git a/src/plugins/baremetal/gdbserverproviderchooser.h b/src/plugins/baremetal/gdbserverproviderchooser.h
index c2827921ca..a53f228a0c 100644
--- a/src/plugins/baremetal/gdbserverproviderchooser.h
+++ b/src/plugins/baremetal/gdbserverproviderchooser.h
@@ -39,7 +39,9 @@ namespace Internal {
class GdbServerProvider;
-class GdbServerProviderChooser : public QWidget
+// GdbServerProviderChooser
+
+class GdbServerProviderChooser final : public QWidget
{
Q_OBJECT
@@ -60,8 +62,8 @@ private:
bool providerMatches(const GdbServerProvider *) const;
QString providerText(const GdbServerProvider *) const;
- QComboBox *m_chooser;
- QPushButton *m_manageButton;
+ QComboBox *m_chooser = nullptr;
+ QPushButton *m_manageButton = nullptr;
};
} // namespace Internal
diff --git a/src/plugins/baremetal/gdbserverprovidermanager.cpp b/src/plugins/baremetal/gdbserverprovidermanager.cpp
index e08b9bb30f..16758ee30c 100644
--- a/src/plugins/baremetal/gdbserverprovidermanager.cpp
+++ b/src/plugins/baremetal/gdbserverprovidermanager.cpp
@@ -23,11 +23,11 @@
**
****************************************************************************/
-#include "gdbserverprovidermanager.h"
#include "gdbserverprovider.h"
+#include "gdbserverprovidermanager.h"
-#include "openocdgdbserverprovider.h"
#include "defaultgdbserverprovider.h"
+#include "openocdgdbserverprovider.h"
#include "stlinkutilgdbserverprovider.h"
#include <coreplugin/icore.h>
@@ -35,8 +35,8 @@
#include <extensionsystem/pluginmanager.h>
#include <utils/algorithm.h>
-#include <utils/qtcassert.h>
#include <utils/persistentsettings.h>
+#include <utils/qtcassert.h>
#include <QDir>
@@ -50,8 +50,10 @@ const char fileNameKeyC[] = "/gdbserverproviders.xml";
static GdbServerProviderManager *m_instance = nullptr;
+// GdbServerProviderManager
+
GdbServerProviderManager::GdbServerProviderManager()
- : m_configFile(Utils::FileName::fromString(Core::ICore::userResourcePath() + fileNameKeyC))
+ : m_configFile(Utils::FilePath::fromString(Core::ICore::userResourcePath() + fileNameKeyC))
, m_factories({new DefaultGdbServerProviderFactory,
new OpenOcdGdbServerProviderFactory,
new StLinkUtilGdbServerProviderFactory})
@@ -103,7 +105,7 @@ void GdbServerProviderManager::restoreProviders()
const QVariantMap map = data.value(key).toMap();
bool restored = false;
- foreach (GdbServerProviderFactory *f, m_factories) {
+ for (GdbServerProviderFactory *f : qAsConst(m_factories)) {
if (f->canRestore(map)) {
if (GdbServerProvider *p = f->restore(map)) {
registerProvider(p);
@@ -127,7 +129,7 @@ void GdbServerProviderManager::saveProviders()
data.insert(QLatin1String(fileVersionKeyC), 1);
int count = 0;
- foreach (const GdbServerProvider *p, m_providers) {
+ for (const GdbServerProvider *p : qAsConst(m_providers)) {
if (p->isValid()) {
const QVariantMap tmp = p->toMap();
if (tmp.isEmpty())
diff --git a/src/plugins/baremetal/gdbserverprovidermanager.h b/src/plugins/baremetal/gdbserverprovidermanager.h
index 8a6ed109ba..64bd6df409 100644
--- a/src/plugins/baremetal/gdbserverprovidermanager.h
+++ b/src/plugins/baremetal/gdbserverprovidermanager.h
@@ -25,8 +25,8 @@
#pragma once
-#include <QObject>
#include <QList>
+#include <QObject>
#include <utils/fileutils.h>
@@ -36,17 +36,19 @@ namespace BareMetal {
namespace Internal {
class BareMetalPlugin;
-class BareMetalPluginRunData;
+class BareMetalPluginPrivate;
class GdbServerProvider;
class GdbServerProviderFactory;
-class GdbServerProviderManager : public QObject
+// GdbServerProviderManager
+
+class GdbServerProviderManager final : public QObject
{
Q_OBJECT
public:
static GdbServerProviderManager *instance();
- ~GdbServerProviderManager() override;
+ ~GdbServerProviderManager() final;
static QList<GdbServerProvider *> providers();
static QList<GdbServerProviderFactory *> factories();
@@ -69,13 +71,13 @@ private:
void restoreProviders();
static void notifyAboutUpdate(GdbServerProvider *);
- Utils::PersistentSettingsWriter *m_writer;
+ Utils::PersistentSettingsWriter *m_writer = nullptr;
QList<GdbServerProvider *> m_providers;
- const Utils::FileName m_configFile;
+ const Utils::FilePath m_configFile;
const QList<GdbServerProviderFactory *> m_factories;
friend class BareMetalPlugin; // for restoreProviders
- friend class BareMetalPluginRunData; // for constructor
+ friend class BareMetalPluginPrivate; // for constructor
friend class GdbServerProvider;
};
diff --git a/src/plugins/baremetal/gdbserverproviderprocess.cpp b/src/plugins/baremetal/gdbserverproviderprocess.cpp
index 45d14d57e0..d893e5fae4 100644
--- a/src/plugins/baremetal/gdbserverproviderprocess.cpp
+++ b/src/plugins/baremetal/gdbserverproviderprocess.cpp
@@ -26,16 +26,19 @@
#include "gdbserverproviderprocess.h"
#include <projectexplorer/devicesupport/idevice.h>
+#include <projectexplorer/runcontrol.h>
#include <utils/environment.h>
-#include <utils/qtcprocess.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
using namespace ProjectExplorer;
namespace BareMetal {
namespace Internal {
+// GdbServerProviderProcess
+
GdbServerProviderProcess::GdbServerProviderProcess(
const QSharedPointer<const ProjectExplorer::IDevice> &device,
QObject *parent)
@@ -46,7 +49,7 @@ GdbServerProviderProcess::GdbServerProviderProcess(
m_process->setUseCtrlCStub(true);
connect(m_process, &QProcess::errorOccurred, this, &GdbServerProviderProcess::error);
- connect(m_process, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
+ connect(m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &GdbServerProviderProcess::finished);
connect(m_process, &QProcess::readyReadStandardOutput,
@@ -60,7 +63,7 @@ GdbServerProviderProcess::GdbServerProviderProcess(
void GdbServerProviderProcess::start(const ProjectExplorer::Runnable &runnable)
{
QTC_ASSERT(m_process->state() == QProcess::NotRunning, return);
- m_process->setCommand(runnable.executable, runnable.commandLineArguments);
+ m_process->setCommand(runnable.commandLine());
m_process->start();
}
diff --git a/src/plugins/baremetal/gdbserverproviderprocess.h b/src/plugins/baremetal/gdbserverproviderprocess.h
index 8640db5aef..bddb59fdcd 100644
--- a/src/plugins/baremetal/gdbserverproviderprocess.h
+++ b/src/plugins/baremetal/gdbserverproviderprocess.h
@@ -32,7 +32,9 @@ namespace Utils { class QtcProcess; }
namespace BareMetal {
namespace Internal {
-class GdbServerProviderProcess : public ProjectExplorer::DeviceProcess
+// GdbServerProviderProcess
+
+class GdbServerProviderProcess final : public ProjectExplorer::DeviceProcess
{
Q_OBJECT
public:
@@ -40,23 +42,23 @@ public:
const QSharedPointer<const ProjectExplorer::IDevice> &device,
QObject *parent = nullptr);
- void start(const ProjectExplorer::Runnable &runnable) override;
- void interrupt() override;
- void terminate() override;
- void kill() override;
+ void start(const ProjectExplorer::Runnable &runnable) final;
+ void interrupt() final;
+ void terminate() final;
+ void kill() final;
- QProcess::ProcessState state() const override;
- QProcess::ExitStatus exitStatus() const override;
- int exitCode() const override;
- QString errorString() const override;
+ QProcess::ProcessState state() const final;
+ QProcess::ExitStatus exitStatus() const final;
+ int exitCode() const final;
+ QString errorString() const final;
- QByteArray readAllStandardOutput() override;
- QByteArray readAllStandardError() override;
+ QByteArray readAllStandardOutput() final;
+ QByteArray readAllStandardError() final;
- qint64 write(const QByteArray &data) override;
+ qint64 write(const QByteArray &data) final;
private:
- Utils::QtcProcess *m_process;
+ Utils::QtcProcess *m_process = nullptr;
};
} // namespace Internal
diff --git a/src/plugins/baremetal/gdbserverproviderssettingspage.cpp b/src/plugins/baremetal/gdbserverproviderssettingspage.cpp
index 60af0a9d2b..b538ebce33 100644
--- a/src/plugins/baremetal/gdbserverproviderssettingspage.cpp
+++ b/src/plugins/baremetal/gdbserverproviderssettingspage.cpp
@@ -23,21 +23,23 @@
**
****************************************************************************/
-#include "gdbserverproviderssettingspage.h"
-#include "gdbserverprovider.h"
#include "baremetalconstants.h"
+
+#include "gdbserverprovider.h"
#include "gdbserverprovidermanager.h"
+#include "gdbserverproviderssettingspage.h"
#include <coreplugin/icore.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/projectexplorerconstants.h>
+#include <utils/algorithm.h>
#include <utils/detailswidget.h>
#include <utils/qtcassert.h>
-#include <utils/algorithm.h>
-#include <QApplication>
#include <QAction>
+#include <QApplication>
+#include <QGroupBox>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QItemSelectionModel>
@@ -48,22 +50,23 @@
#include <QTextStream>
#include <QTreeView>
#include <QVBoxLayout>
-#include <QGroupBox>
using namespace Utils;
namespace BareMetal {
namespace Internal {
-class GdbServerProviderNode : public TreeItem
+// GdbServerProviderNode
+
+class GdbServerProviderNode final : public TreeItem
{
public:
- GdbServerProviderNode(GdbServerProvider *provider, bool changed = false)
+ explicit GdbServerProviderNode(GdbServerProvider *provider, bool changed = false)
: provider(provider), changed(changed)
{
}
- QVariant data(int column, int role) const override
+ QVariant data(int column, int role) const final
{
if (role == Qt::FontRole) {
QFont f = QApplication::font();
@@ -77,7 +80,7 @@ public:
}
// FIXME: Need to handle ToolTipRole role?
- return QVariant();
+ return {};
}
GdbServerProvider *provider = nullptr;
@@ -85,6 +88,8 @@ public:
bool changed = false;
};
+// GdbServerProviderModel
+
GdbServerProviderModel::GdbServerProviderModel()
{
setHeader({tr("Name"), tr("Type")});
@@ -102,7 +107,7 @@ GdbServerProviderModel::GdbServerProviderModel()
GdbServerProvider *GdbServerProviderModel::provider(const QModelIndex &index) const
{
- if (GdbServerProviderNode *node = nodeForIndex(index))
+ if (const GdbServerProviderNode *node = nodeForIndex(index))
return node->provider;
return nullptr;
@@ -119,13 +124,13 @@ GdbServerProviderNode *GdbServerProviderModel::nodeForIndex(const QModelIndex &i
void GdbServerProviderModel::apply()
{
// Remove unused providers
- foreach (GdbServerProvider *provider, m_providersToRemove)
+ for (GdbServerProvider *provider : qAsConst(m_providersToRemove))
GdbServerProviderManager::deregisterProvider(provider);
QTC_ASSERT(m_providersToRemove.isEmpty(), m_providersToRemove.clear());
// Update providers
for (TreeItem *item : *rootItem()) {
- auto n = static_cast<GdbServerProviderNode *>(item);
+ const auto n = static_cast<GdbServerProviderNode *>(item);
if (!n->changed)
continue;
@@ -139,7 +144,7 @@ void GdbServerProviderModel::apply()
// Add new (and already updated) providers
QStringList skippedProviders;
- foreach (GdbServerProvider *provider, m_providersToAdd) {
+ for (GdbServerProvider *provider: qAsConst(m_providersToAdd)) {
if (!GdbServerProviderManager::registerProvider(provider))
skippedProviders << provider->displayName();
}
@@ -167,7 +172,7 @@ GdbServerProviderNode *GdbServerProviderModel::findNode(const GdbServerProvider
QModelIndex GdbServerProviderModel::indexForProvider(GdbServerProvider *provider) const
{
- GdbServerProviderNode *n = findNode(provider);
+ const GdbServerProviderNode *n = findNode(provider);
return n ? indexForItem(n) : QModelIndex();
}
@@ -195,7 +200,7 @@ void GdbServerProviderModel::markForAddition(GdbServerProvider *provider)
GdbServerProviderNode *GdbServerProviderModel::createNode(
GdbServerProvider *provider, bool changed)
{
- auto node = new GdbServerProviderNode(provider, changed);
+ const auto node = new GdbServerProviderNode(provider, changed);
node->widget = provider->configurationWidget();
connect(node->widget, &GdbServerProviderConfigWidget::dirty, this, [node] {
node->changed = true;
@@ -223,12 +228,14 @@ void GdbServerProviderModel::removeProvider(GdbServerProvider *provider)
emit providerStateChanged();
}
-class GdbServerProvidersSettingsWidget : public QWidget
+// GdbServerProvidersSettingsWidget
+
+class GdbServerProvidersSettingsWidget final : public QWidget
{
Q_DECLARE_TR_FUNCTIONS(BareMetal::Internal::GdbServerProvidersSettingsPage)
public:
- GdbServerProvidersSettingsWidget(GdbServerProvidersSettingsPage *page);
+ explicit GdbServerProvidersSettingsWidget(GdbServerProvidersSettingsPage *page);
void providerSelectionChanged();
void removeProvider();
@@ -238,14 +245,14 @@ public:
QModelIndex currentIndex() const;
public:
- GdbServerProvidersSettingsPage *m_page;
+ GdbServerProvidersSettingsPage *m_page = nullptr;
GdbServerProviderModel m_model;
- QItemSelectionModel *m_selectionModel;
- QTreeView *m_providerView;
- Utils::DetailsWidget *m_container;
- QPushButton *m_addButton;
- QPushButton *m_cloneButton;
- QPushButton *m_delButton;
+ QItemSelectionModel *m_selectionModel = nullptr;
+ QTreeView *m_providerView = nullptr;
+ Utils::DetailsWidget *m_container = nullptr;
+ QPushButton *m_addButton = nullptr;
+ QPushButton *m_cloneButton = nullptr;
+ QPushButton *m_delButton = nullptr;
};
GdbServerProvidersSettingsWidget::GdbServerProvidersSettingsWidget
@@ -265,27 +272,27 @@ GdbServerProvidersSettingsWidget::GdbServerProvidersSettingsWidget
m_container->setMinimumWidth(500);
m_container->setVisible(false);
- auto buttonLayout = new QHBoxLayout();
+ const auto buttonLayout = new QHBoxLayout;
buttonLayout->setSpacing(6);
buttonLayout->setContentsMargins(0, 0, 0, 0);
buttonLayout->addWidget(m_addButton);
buttonLayout->addWidget(m_cloneButton);
buttonLayout->addWidget(m_delButton);
- auto spacerItem = new QSpacerItem(40, 10, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ const auto spacerItem = new QSpacerItem(40, 10, QSizePolicy::Expanding, QSizePolicy::Minimum);
buttonLayout->addItem(spacerItem);
- auto verticalLayout = new QVBoxLayout();
+ const auto verticalLayout = new QVBoxLayout;
verticalLayout->addWidget(m_providerView);
verticalLayout->addLayout(buttonLayout);
- auto horizontalLayout = new QHBoxLayout();
+ const auto horizontalLayout = new QHBoxLayout;
horizontalLayout->addLayout(verticalLayout);
horizontalLayout->addWidget(m_container);
- auto groupBox = new QGroupBox(tr("GDB Server Providers"), this);
+ const auto groupBox = new QGroupBox(tr("GDB Server Providers"), this);
groupBox->setLayout(horizontalLayout);
- auto topLayout = new QVBoxLayout(this);
+ const auto topLayout = new QVBoxLayout(this);
topLayout->addWidget(groupBox);
connect(&m_model, &GdbServerProviderModel::providerStateChanged,
@@ -293,7 +300,7 @@ GdbServerProvidersSettingsWidget::GdbServerProvidersSettingsWidget
m_providerView->setModel(&m_model);
- auto headerView = m_providerView->header();
+ const auto headerView = m_providerView->header();
headerView->setSectionResizeMode(0, QHeaderView::ResizeToContents);
headerView->setSectionResizeMode(1, QHeaderView::Stretch);
m_providerView->expandAll();
@@ -307,10 +314,10 @@ GdbServerProvidersSettingsWidget::GdbServerProvidersSettingsWidget
this, &GdbServerProvidersSettingsWidget::providerSelectionChanged);
// Set up add menu:
- auto addMenu = new QMenu(m_addButton);
+ const auto addMenu = new QMenu(m_addButton);
for (const auto f : GdbServerProviderManager::factories()) {
- auto action = new QAction(addMenu);
+ const auto action = new QAction(addMenu);
action->setText(f->displayName());
connect(action, &QAction::triggered, this, [this, f] { createProvider(f); });
addMenu->addAction(action);
@@ -335,7 +342,7 @@ void GdbServerProvidersSettingsWidget::providerSelectionChanged()
if (w)
w->setVisible(false);
- GdbServerProviderNode *node = m_model.nodeForIndex(current);
+ const GdbServerProviderNode *node = m_model.nodeForIndex(current);
w = node ? node->widget : nullptr;
m_container->setWidget(w);
m_container->setVisible(w != nullptr);
@@ -346,7 +353,7 @@ void GdbServerProvidersSettingsWidget::createProvider(GdbServerProviderFactory *
{
GdbServerProvider *provider = nullptr;
if (!f) {
- GdbServerProvider *old = m_model.provider(currentIndex());
+ const GdbServerProvider *old = m_model.provider(currentIndex());
if (!old)
return;
provider = old->clone();
@@ -390,11 +397,11 @@ void GdbServerProvidersSettingsWidget::updateState()
QModelIndex GdbServerProvidersSettingsWidget::currentIndex() const
{
if (!m_selectionModel)
- return QModelIndex();
+ return {};
const QModelIndexList rows = m_selectionModel->selectedRows();
if (rows.count() != 1)
- return QModelIndex();
+ return {};
return rows.at(0);
}
diff --git a/src/plugins/baremetal/gdbserverproviderssettingspage.h b/src/plugins/baremetal/gdbserverproviderssettingspage.h
index d1b6119fd9..a68515526e 100644
--- a/src/plugins/baremetal/gdbserverproviderssettingspage.h
+++ b/src/plugins/baremetal/gdbserverproviderssettingspage.h
@@ -46,13 +46,15 @@ class GdbServerProviderFactory;
class GdbServerProviderNode;
class GdbServerProvidersSettingsWidget;
-class GdbServerProviderModel
+// GdbServerProviderModel
+
+class GdbServerProviderModel final
: public Utils::TreeModel<Utils::TypedTreeItem<GdbServerProviderNode>, GdbServerProviderNode>
{
Q_OBJECT
public:
- GdbServerProviderModel();
+ explicit GdbServerProviderModel();
GdbServerProvider *provider(const QModelIndex &) const;
GdbServerProviderConfigWidget *widget(const QModelIndex &) const;
@@ -78,7 +80,9 @@ private:
QList<GdbServerProvider *> m_providersToRemove;
};
-class GdbServerProvidersSettingsPage : public Core::IOptionsPage
+// GdbServerProvidersSettingsPage
+
+class GdbServerProvidersSettingsPage final : public Core::IOptionsPage
{
Q_OBJECT
@@ -86,9 +90,9 @@ public:
explicit GdbServerProvidersSettingsPage(QObject *parent = nullptr);
private:
- QWidget *widget() override;
- void apply() override;
- void finish() override;
+ QWidget *widget() final;
+ void apply() final;
+ void finish() final;
GdbServerProvidersSettingsWidget *m_configWidget = nullptr;
};
diff --git a/src/plugins/baremetal/iarewparser.cpp b/src/plugins/baremetal/iarewparser.cpp
new file mode 100644
index 0000000000..50e25706ca
--- /dev/null
+++ b/src/plugins/baremetal/iarewparser.cpp
@@ -0,0 +1,450 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** 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 "iarewparser.h"
+
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/task.h>
+
+#include <texteditor/fontsettings.h>
+#include <texteditor/texteditorsettings.h>
+
+#include <QRegularExpression>
+
+using namespace ProjectExplorer;
+
+namespace BareMetal {
+namespace Internal {
+
+// Helpers:
+
+static Task::TaskType taskType(const QString &msgType)
+{
+ if (msgType == "Warning")
+ return Task::TaskType::Warning;
+ else if (msgType == "Error" || msgType == "Fatal error")
+ return Task::TaskType::Error;
+ return Task::TaskType::Unknown;
+}
+
+// IarParser
+
+IarParser::IarParser()
+{
+ setObjectName("IarParser");
+}
+
+Core::Id IarParser::id()
+{
+ return "BareMetal.OutputParser.Iar";
+}
+
+void IarParser::newTask(const Task &task)
+{
+ doFlush();
+ m_lastTask = task;
+ m_lines = 1;
+}
+
+void IarParser::amendDescription()
+{
+ while (!m_descriptionParts.isEmpty())
+ m_lastTask.description.append(m_descriptionParts.takeFirst());
+
+ while (!m_snippets.isEmpty()) {
+ const QString snippet = m_snippets.takeFirst();
+ const int start = m_lastTask.description.count() + 1;
+ m_lastTask.description.append(QLatin1Char('\n'));
+ m_lastTask.description.append(snippet);
+
+ QTextLayout::FormatRange fr;
+ fr.start = start;
+ fr.length = m_lastTask.description.count() + 1;
+ fr.format.setFont(TextEditor::TextEditorSettings::fontSettings().font());
+ fr.format.setFontStyleHint(QFont::Monospace);
+ m_lastTask.formats.append(fr);
+
+ ++m_lines;
+ }
+}
+
+void IarParser::amendFilePath()
+{
+ if (m_filePathParts.isEmpty())
+ return;
+ QString filePath;
+ while (!m_filePathParts.isEmpty())
+ filePath.append(m_filePathParts.takeFirst().trimmed());
+ m_lastTask.setFile(Utils::FilePath::fromUserInput(filePath));
+ m_expectFilePath = false;
+}
+
+void IarParser::stdError(const QString &line)
+{
+ IOutputParser::stdError(line);
+
+ const QString lne = rightTrimmed(line);
+
+ QRegularExpression re;
+ QRegularExpressionMatch match;
+
+ re.setPattern("^(Error|Fatal error)\\[(.+)\\]:\\s(.+)\\s\\[(.+)$");
+ match = re.match(lne);
+ if (match.hasMatch()) {
+ enum CaptureIndex { MessageTypeIndex = 1, MessageCodeIndex,
+ DescriptionIndex, FilepathBeginIndex };
+ const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
+ const QString descr = QString("[%1]: %2").arg(match.captured(MessageCodeIndex),
+ match.captured(DescriptionIndex));
+ // This task has a file path, but this patch are split on
+ // some lines, which will be received later.
+ const Task task(type, descr, {}, -1, Constants::TASK_CATEGORY_COMPILE);
+ newTask(task);
+ // Prepare first part of a file path.
+ QString firstPart = match.captured(FilepathBeginIndex);
+ firstPart.remove("referenced from ");
+ m_filePathParts.push_back(firstPart);
+ m_expectFilePath = true;
+ m_expectSnippet = false;
+ return;
+ }
+
+ re.setPattern("^.*(Error|Fatal error)\\[(.+)\\]:\\s(.+)$");
+ match = re.match(lne);
+ if (match.hasMatch()) {
+ enum CaptureIndex { MessageTypeIndex = 1, MessageCodeIndex,
+ DescriptionIndex };
+ const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
+ const QString descr = QString("[%1]: %2").arg(match.captured(MessageCodeIndex),
+ match.captured(DescriptionIndex));
+ // This task has not a file path. The description details
+ // will be received later on the next lines.
+ const Task task(type, descr, {}, -1, Constants::TASK_CATEGORY_COMPILE);
+ newTask(task);
+ m_expectSnippet = true;
+ m_expectFilePath = false;
+ m_expectDescription = false;
+ return;
+ }
+
+ re.setPattern("^\"(.+)\",(\\d+)?\\s+(Warning|Error|Fatal error)\\[(.+)\\].+$");
+ match = re.match(lne);
+ if (match.hasMatch()) {
+ enum CaptureIndex { FilePathIndex = 1, LineNumberIndex,
+ MessageTypeIndex, MessageCodeIndex };
+ const Utils::FilePath fileName = Utils::FilePath::fromUserInput(
+ match.captured(FilePathIndex));
+ const int lineno = match.captured(LineNumberIndex).toInt();
+ const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
+ // A full description will be received later on next lines.
+ const Task task(type, {}, fileName, lineno, Constants::TASK_CATEGORY_COMPILE);
+ newTask(task);
+ const QString firstPart = QString("[%1]: ").arg(match.captured(MessageCodeIndex));
+ m_descriptionParts.append(firstPart);
+ m_expectDescription = true;
+ m_expectSnippet = false;
+ m_expectFilePath = false;
+ return;
+ }
+
+ if (lne.isEmpty()) {
+ //
+ } else if (!lne.startsWith(QLatin1Char(' '))) {
+ return;
+ } else if (m_expectFilePath) {
+ if (lne.endsWith(QLatin1Char(']'))) {
+ const QString lastPart = lne.left(lne.size() - 1);
+ m_filePathParts.push_back(lastPart);
+ } else {
+ m_filePathParts.push_back(lne);
+ return;
+ }
+ } else if (m_expectSnippet) {
+ if (!lne.endsWith("Fatal error detected, aborting.")) {
+ m_snippets.push_back(lne);
+ return;
+ }
+ } else if (m_expectDescription) {
+ if (!lne.startsWith(" ")) {
+ m_descriptionParts.push_back(lne.trimmed());
+ return;
+ }
+ }
+
+ doFlush();
+}
+
+void IarParser::stdOutput(const QString &line)
+{
+ IOutputParser::stdOutput(line);
+
+ const QString lne = rightTrimmed(line);
+ if (!lne.startsWith("Error in command line"))
+ return;
+
+ const Task task(Task::TaskType::Error, line.trimmed(), {},
+ -1, Constants::TASK_CATEGORY_COMPILE);
+ newTask(task);
+ doFlush();
+}
+
+void IarParser::doFlush()
+{
+ if (m_lastTask.isNull())
+ return;
+
+ amendDescription();
+ amendFilePath();
+
+ m_expectSnippet = true;
+ m_expectFilePath = false;
+ m_expectDescription = false;
+
+ Task t = m_lastTask;
+ m_lastTask.clear();
+ emit addTask(t, m_lines, 1);
+ m_lines = 0;
+}
+
+} // namespace Internal
+} // namespace BareMetal
+
+// Unit tests:
+
+#ifdef WITH_TESTS
+#include "baremetalplugin.h"
+#include <projectexplorer/outputparser_test.h>
+#include <QTest>
+
+namespace BareMetal {
+namespace Internal {
+
+void BareMetalPlugin::testIarOutputParsers_data()
+{
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<OutputParserTester::Channel>("inputChannel");
+ QTest::addColumn<QString>("childStdOutLines");
+ QTest::addColumn<QString>("childStdErrLines");
+ QTest::addColumn<Tasks >("tasks");
+ QTest::addColumn<QString>("outputLines");
+
+ QTest::newRow("pass-through stdout")
+ << "Sometext" << OutputParserTester::STDOUT
+ << "Sometext\n" << QString()
+ << Tasks()
+ << QString();
+ QTest::newRow("pass-through stderr")
+ << "Sometext" << OutputParserTester::STDERR
+ << QString() << "Sometext\n"
+ << Tasks()
+ << QString();
+
+ const Core::Id categoryCompile = Constants::TASK_CATEGORY_COMPILE;
+
+ // For std out.
+ QTest::newRow("Error in command line")
+ << QString::fromLatin1("Error in command line: Some error")
+ << OutputParserTester::STDOUT
+ << QString::fromLatin1("Error in command line: Some error\n")
+ << QString()
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("Error in command line: Some error"),
+ Utils::FilePath(),
+ -1,
+ categoryCompile))
+ << QString();
+
+ // For std error.
+ QTest::newRow("No details warning")
+ << QString::fromLatin1("\"c:\\foo\\main.c\",63 Warning[Pe223]:\n"
+ " Some warning \"foo\" bar")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("\"c:\\foo\\main.c\",63 Warning[Pe223]:\n"
+ " Some warning \"foo\" bar\n")
+ << (Tasks() << Task(Task::Warning,
+ QLatin1String("[Pe223]: Some warning \"foo\" bar"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\main.c")),
+ 63,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("Details warning")
+ << QString::fromLatin1(" some_detail;\n"
+ " ^\n"
+ "\"c:\\foo\\main.c\",63 Warning[Pe223]:\n"
+ " Some warning")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1(" some_detail;\n"
+ " ^\n"
+ "\"c:\\foo\\main.c\",63 Warning[Pe223]:\n"
+ " Some warning\n")
+ << (Tasks() << Task(Task::Warning,
+ QLatin1String("[Pe223]: Some warning\n"
+ " some_detail;\n"
+ " ^"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\main.c")),
+ 63,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("No details split-description warning")
+ << QString::fromLatin1("\"c:\\foo\\main.c\",63 Warning[Pe223]:\n"
+ " Some warning\n"
+ " , split")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("\"c:\\foo\\main.c\",63 Warning[Pe223]:\n"
+ " Some warning\n"
+ " , split\n")
+ << (Tasks() << Task(Task::Warning,
+ QLatin1String("[Pe223]: Some warning, split"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\main.c")),
+ 63,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("No details error")
+ << QString::fromLatin1("\"c:\\foo\\main.c\",63 Error[Pe223]:\n"
+ " Some error")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("\"c:\\foo\\main.c\",63 Error[Pe223]:\n"
+ " Some error\n")
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("[Pe223]: Some error"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\main.c")),
+ 63,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("Details error")
+ << QString::fromLatin1(" some_detail;\n"
+ " ^\n"
+ "\"c:\\foo\\main.c\",63 Error[Pe223]:\n"
+ " Some error")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1(" some_detail;\n"
+ " ^\n"
+ "\"c:\\foo\\main.c\",63 Error[Pe223]:\n"
+ " Some error\n")
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("[Pe223]: Some error\n"
+ " some_detail;\n"
+ " ^"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\main.c")),
+ 63,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("No details split-description error")
+ << QString::fromLatin1("\"c:\\foo\\main.c\",63 Error[Pe223]:\n"
+ " Some error\n"
+ " , split")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("\"c:\\foo\\main.c\",63 Error[Pe223]:\n"
+ " Some error\n"
+ " , split\n")
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("[Pe223]: Some error, split"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\main.c")),
+ 63,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("No definition for")
+ << QString::fromLatin1("Error[Li005]: Some error \"foo\" [referenced from c:\\fo\n"
+ " o\\bar\\mai\n"
+ " n.c.o\n"
+ "]")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("Error[Li005]: Some error \"foo\" [referenced from c:\\fo\n"
+ " o\\bar\\mai\n"
+ " n.c.o\n"
+ "]\n")
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("[Li005]: Some error \"foo\""),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\bar\\main.c.o")),
+ -1,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("More than one source file specified")
+ << QString::fromLatin1("Fatal error[Su011]: Some error:\n"
+ " c:\\foo.c\n"
+ " c:\\bar.c\n"
+ "Fatal error detected, aborting.")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("Fatal error[Su011]: Some error:\n"
+ " c:\\foo.c\n"
+ " c:\\bar.c\n"
+ "Fatal error detected, aborting.\n")
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("[Su011]: Some error:\n"
+ " c:\\foo.c\n"
+ " c:\\bar.c"),
+ Utils::FilePath(),
+ -1,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("At end of source")
+ << QString::fromLatin1("At end of source Error[Pe040]: Some error \";\"")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("At end of source Error[Pe040]: Some error \";\"\n")
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("[Pe040]: Some error \";\""),
+ Utils::FilePath(),
+ -1,
+ categoryCompile))
+ << QString();
+}
+
+void BareMetalPlugin::testIarOutputParsers()
+{
+ OutputParserTester testbench;
+ testbench.appendOutputParser(new IarParser);
+ QFETCH(QString, input);
+ QFETCH(OutputParserTester::Channel, inputChannel);
+ QFETCH(Tasks, tasks);
+ QFETCH(QString, childStdOutLines);
+ QFETCH(QString, childStdErrLines);
+ QFETCH(QString, outputLines);
+
+ testbench.testParsing(input, inputChannel,
+ tasks, childStdOutLines, childStdErrLines,
+ outputLines);
+}
+
+} // namespace Internal
+} // namespace BareMetal
+
+#endif // WITH_TESTS
diff --git a/src/plugins/baremetal/baremetaldeviceconfigurationfactory.cpp b/src/plugins/baremetal/iarewparser.h
index 779f9305ad..48348d4f6f 100644
--- a/src/plugins/baremetal/baremetaldeviceconfigurationfactory.cpp
+++ b/src/plugins/baremetal/iarewparser.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 Tim Sander <tim@krieglstein.org>
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -23,36 +23,42 @@
**
****************************************************************************/
-#include "baremetaldeviceconfigurationfactory.h"
+#pragma once
-#include "baremetaldeviceconfigurationwizard.h"
-#include "baremetalconstants.h"
-#include "baremetaldevice.h"
-
-#include <utils/qtcassert.h>
-
-using namespace ProjectExplorer;
+#include <projectexplorer/ioutputparser.h>
+#include <projectexplorer/task.h>
namespace BareMetal {
namespace Internal {
-BareMetalDeviceConfigurationFactory::BareMetalDeviceConfigurationFactory()
- : IDeviceFactory(Constants::BareMetalOsType)
-{
- setDisplayName(tr("Bare Metal Device"));
- setCombinedIcon(":/baremetal/images/baremetaldevicesmall.png",
- ":/baremetal/images/baremetaldevice.png");
- setCanCreate(true);
- setConstructionFunction(&BareMetalDevice::create);
-}
-
-IDevice::Ptr BareMetalDeviceConfigurationFactory::create() const
+// IarParser
+
+class IarParser final : public ProjectExplorer::IOutputParser
{
- BareMetalDeviceConfigurationWizard wizard;
- if (wizard.exec() != QDialog::Accepted)
- return IDevice::Ptr();
- return wizard.device();
-}
+ Q_OBJECT
+
+public:
+ explicit IarParser();
+ static Core::Id id();
+
+private:
+ void newTask(const ProjectExplorer::Task &task);
+ void amendDescription();
+ void amendFilePath();
+
+ void stdError(const QString &line) final;
+ void stdOutput(const QString &line) final;
+ void doFlush() final;
+
+ ProjectExplorer::Task m_lastTask;
+ int m_lines = 0;
+ bool m_expectSnippet = true;
+ bool m_expectFilePath = false;
+ bool m_expectDescription = false;
+ QStringList m_snippets;
+ QStringList m_filePathParts;
+ QStringList m_descriptionParts;
+};
} // namespace Internal
} // namespace BareMetal
diff --git a/src/plugins/baremetal/iarewtoolchain.cpp b/src/plugins/baremetal/iarewtoolchain.cpp
new file mode 100644
index 0000000000..1955a0fec7
--- /dev/null
+++ b/src/plugins/baremetal/iarewtoolchain.cpp
@@ -0,0 +1,594 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** 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 "iarewparser.h"
+#include "iarewtoolchain.h"
+
+#include <projectexplorer/abiwidget.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/projectmacro.h>
+#include <projectexplorer/toolchainmanager.h>
+
+#include <utils/algorithm.h>
+#include <utils/environment.h>
+#include <utils/pathchooser.h>
+#include <utils/qtcassert.h>
+#include <utils/synchronousprocess.h>
+
+#include <QDebug>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QFormLayout>
+#include <QLineEdit>
+#include <QPlainTextEdit>
+#include <QSettings>
+#include <QTemporaryFile>
+
+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 compilerExists(const FilePath &compilerPath)
+{
+ const QFileInfo fi = compilerPath.toFileInfo();
+ return fi.exists() && fi.isExecutable() && fi.isFile();
+}
+
+static Macros dumpPredefinedMacros(const FilePath &compiler, const Core::Id languageId,
+ 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());
+ if (languageId == ProjectExplorer::Constants::CXX_LANGUAGE_ID)
+ arguments.push_back("--ec++");
+ 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 HeaderPaths dumpHeaderPaths(const FilePath &compiler, const Core::Id languageId,
+ const QStringList &env)
+{
+ if (!compiler.exists())
+ return {};
+
+ // Seems, that IAR compiler has not options to show a list of system
+ // include directories. But, we can use the following trick to enumerate
+ // this directories. We need to specify the '--preinclude' option with
+ // the wrong value (e.g. a dot). In this case the compiler fails and its
+ // error output will contains a mention about the using search directories
+ // in a form of tokens, like: ' searched: "<path/to/include>" '. Where are
+ // the resulting paths are escaped with a quotes.
+
+ QTemporaryFile fakeIn;
+ if (!fakeIn.open())
+ return {};
+ fakeIn.close();
+
+ SynchronousProcess cpp;
+ cpp.setEnvironment(env);
+ cpp.setTimeoutS(10);
+
+ QStringList arguments;
+ arguments.push_back(fakeIn.fileName());
+ if (languageId == ProjectExplorer::Constants::CXX_LANGUAGE_ID)
+ arguments.push_back("--ec++");
+ arguments.push_back("--preinclude");
+ arguments.push_back(".");
+
+ // Note: Response should retutn an error, just don't check on errors.
+ const SynchronousProcessResponse response = cpp.runBlocking(compiler.toString(),
+ arguments);
+
+ HeaderPaths headerPaths;
+
+ const QByteArray output = response.allOutput().toUtf8();
+ for (auto pos = 0; pos < output.size(); ++pos) {
+ const int searchIndex = output.indexOf("searched:", pos);
+ if (searchIndex == -1)
+ break;
+ const int startQuoteIndex = output.indexOf('"', searchIndex + 1);
+ if (startQuoteIndex == -1)
+ break;
+ const int endQuoteIndex = output.indexOf('"', startQuoteIndex + 1);
+ if (endQuoteIndex == -1)
+ break;
+
+ const QByteArray candidate = output.mid(startQuoteIndex + 1,
+ endQuoteIndex - startQuoteIndex - 1)
+ .simplified();
+
+ const QString headerPath = QFileInfo(QFile::decodeName(candidate))
+ .canonicalFilePath();
+
+ // Ignore the QtC binary directory path.
+ if (headerPath != QCoreApplication::applicationDirPath())
+ headerPaths.append({headerPath, HeaderPathType::BuiltIn});
+
+ pos = endQuoteIndex + 1;
+ }
+
+ return headerPaths;
+}
+
+static Abi::Architecture guessArchitecture(const Macros &macros)
+{
+ for (const Macro &macro : 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 &macros)
+{
+ 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 &macros)
+{
+ const auto arch = guessArchitecture(macros);
+ return {arch, Abi::OS::BareMetalOS, Abi::OSFlavor::GenericFlavor,
+ guessFormat(arch), guessWordWidth(macros)};
+}
+
+static QString buildDisplayName(Abi::Architecture arch, Core::Id language,
+ const QString &version)
+{
+ const auto archName = Abi::toString(arch);
+ const auto langName = ToolChainManager::displayNameOfLanguageId(language);
+ return IarToolChain::tr("IAREW %1 (%2, %3)")
+ .arg(version, langName, archName);
+}
+
+// IarToolChain
+
+IarToolChain::IarToolChain() :
+ ToolChain(Constants::IAREW_TOOLCHAIN_TYPEID)
+{ }
+
+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::FilePath compilerCommand = m_compilerCommand;
+ const Core::Id languageId = language();
+
+ MacrosCache macrosCache = predefinedMacrosCache();
+
+ return [env, compilerCommand,
+ macrosCache,
+ languageId]
+ (const QStringList &flags) {
+ Q_UNUSED(flags)
+
+ const Macros macros = dumpPredefinedMacros(compilerCommand, languageId,
+ env.toStringList());
+ const auto languageVersion = ToolChain::languageVersion(languageId, macros);
+ const auto report = MacroInspectionReport{macros, languageVersion};
+ 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
+{
+ Environment env = Environment::systemEnvironment();
+ addToEnvironment(env);
+
+ const Utils::FilePath compilerCommand = m_compilerCommand;
+ const Core::Id languageId = language();
+
+ HeaderPathsCache headerPaths = headerPathsCache();
+
+ return [env, compilerCommand, headerPaths, languageId](const QStringList &flags,
+ const QString &fileName,
+ const QString &) {
+ Q_UNUSED(flags)
+ Q_UNUSED(fileName)
+
+ const HeaderPaths paths = dumpHeaderPaths(compilerCommand, languageId, env.toStringList());
+ headerPaths->insert({}, paths);
+
+ return paths;
+ };
+}
+
+HeaderPaths IarToolChain::builtInHeaderPaths(const QStringList &cxxFlags,
+ const FilePath &fileName) const
+{
+ return createBuiltInHeaderPathsRunner()(cxxFlags, fileName.toString(), "");
+}
+
+void IarToolChain::addToEnvironment(Environment &env) const
+{
+ if (!m_compilerCommand.isEmpty()) {
+ const FilePath path = m_compilerCommand.parentDir();
+ env.prependOrSetPath(path.toString());
+ }
+}
+
+IOutputParser *IarToolChain::outputParser() const
+{
+ return new IarParser;
+}
+
+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 = FilePath::fromString(data.value(compilerCommandKeyC).toString());
+ m_targetAbi = Abi::fromString(data.value(targetAbiKeyC).toString());
+ return true;
+}
+
+std::unique_ptr<ToolChainConfigWidget> IarToolChain::createConfigurationWidget()
+{
+ return std::make_unique<IarToolChainConfigWidget>(this);
+}
+
+bool IarToolChain::operator==(const ToolChain &other) const
+{
+ if (!ToolChain::operator==(other))
+ return false;
+
+ const auto customTc = static_cast<const IarToolChain *>(&other);
+ return m_compilerCommand == customTc->m_compilerCommand
+ && m_targetAbi == customTc->m_targetAbi
+ ;
+}
+
+void IarToolChain::setCompilerCommand(const FilePath &file)
+{
+ if (file == m_compilerCommand)
+ return;
+ m_compilerCommand = file;
+ toolChainUpdated();
+}
+
+FilePath IarToolChain::compilerCommand() const
+{
+ return m_compilerCommand;
+}
+
+FilePath IarToolChain::makeCommand(const Environment &env) const
+{
+ Q_UNUSED(env)
+ return {};
+}
+
+// IarToolChainFactory
+
+IarToolChainFactory::IarToolChainFactory()
+{
+ setDisplayName(tr("IAREW"));
+ setSupportedToolChainType(Constants::IAREW_TOOLCHAIN_TYPEID);
+ setSupportedLanguages({ProjectExplorer::Constants::C_LANGUAGE_ID,
+ ProjectExplorer::Constants::CXX_LANGUAGE_ID});
+ setToolchainConstructor([] { return new IarToolChain; });
+ setUserCreatable(true);
+}
+
+QList<ToolChain *> IarToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
+{
+ Candidates candidates;
+
+#ifdef Q_OS_WIN
+
+#ifdef Q_OS_WIN64
+ static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\IAR Systems\\Embedded Workbench";
+#else
+ static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\IAR Systems\\Embedded Workbench";
+#endif
+
+ // Dictionary for know toolchains.
+ static const struct Entry {
+ QString registryKey;
+ QString subExePath;
+ } knowToolchains[] = {
+ {"EWARM", "\\arm\\bin\\iccarm.exe"},
+ {"EWAVR", "\\avr\\bin\\iccavr.exe"},
+ {"EW8051", "\\8051\\bin\\icc8051.exe"},
+ };
+
+ QSettings registry(kRegistryNode, QSettings::NativeFormat);
+ const auto oneLevelGroups = registry.childGroups();
+ for (const QString &oneLevelKey : oneLevelGroups) {
+ registry.beginGroup(oneLevelKey);
+ const auto twoLevelGroups = registry.childGroups();
+ for (const Entry &entry : knowToolchains) {
+ if (twoLevelGroups.contains(entry.registryKey)) {
+ registry.beginGroup(entry.registryKey);
+ const auto threeLevelGroups = registry.childGroups();
+ for (const QString &threeLevelKey : threeLevelGroups) {
+ registry.beginGroup(threeLevelKey);
+ QString compilerPath = registry.value("InstallPath").toString();
+ if (!compilerPath.isEmpty()) {
+ // Build full compiler path.
+ compilerPath += entry.subExePath;
+ const FileName fn = FileName::fromString(compilerPath);
+ if (compilerExists(fn)) {
+ // Note: threeLevelKey is a guessed toolchain version.
+ candidates.push_back({fn, threeLevelKey});
+ }
+ }
+ registry.endGroup();
+ }
+ registry.endGroup();
+ }
+ }
+ registry.endGroup();
+ }
+
+#endif // Q_OS_WIN
+
+ return autoDetectToolchains(candidates, alreadyKnown);
+}
+
+QList<ToolChain *> IarToolChainFactory::autoDetectToolchains(
+ const Candidates &candidates, const QList<ToolChain *> &alreadyKnown) const
+{
+ QList<ToolChain *> result;
+
+ for (const Candidate &candidate : qAsConst(candidates)) {
+ const QList<ToolChain *> filtered = Utils::filtered(
+ alreadyKnown, [candidate](ToolChain *tc) {
+ return tc->typeId() == Constants::IAREW_TOOLCHAIN_TYPEID
+ && tc->compilerCommand() == candidate.compilerPath
+ && (tc->language() == ProjectExplorer::Constants::C_LANGUAGE_ID
+ || tc->language() == ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ });
+
+ if (!filtered.isEmpty()) {
+ result << filtered;
+ continue;
+ }
+
+ // Create toolchains for both C and C++ languages.
+ result << autoDetectToolchain(candidate, ProjectExplorer::Constants::C_LANGUAGE_ID);
+ result << autoDetectToolchain(candidate, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ }
+
+ return result;
+}
+
+QList<ToolChain *> IarToolChainFactory::autoDetectToolchain(
+ const Candidate &candidate, Core::Id languageId) const
+{
+ const auto env = Environment::systemEnvironment();
+ const Macros macros = dumpPredefinedMacros(candidate.compilerPath, languageId,
+ env.toStringList());
+ if (macros.isEmpty())
+ return {};
+ const Abi abi = guessAbi(macros);
+
+ const auto tc = new IarToolChain;
+ tc->setDetection(ToolChain::AutoDetection);
+ tc->setLanguage(languageId);
+ tc->setCompilerCommand(candidate.compilerPath);
+ tc->setTargetAbi(abi);
+ tc->setDisplayName(buildDisplayName(abi.architecture(), languageId,
+ candidate.compilerVersion));
+
+ const auto languageVersion = ToolChain::languageVersion(languageId, macros);
+ tc->predefinedMacrosCache()->insert({}, {macros, languageVersion});
+ return {tc};
+}
+
+// IarToolChainConfigWidget
+
+IarToolChainConfigWidget::IarToolChainConfigWidget(IarToolChain *tc) :
+ ToolChainConfigWidget(tc),
+ m_compilerCommand(new PathChooser),
+ m_abiWidget(new AbiWidget)
+{
+ m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand);
+ m_compilerCommand->setHistoryCompleter("PE.IAREW.Command.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<IarToolChain *>(toolChain());
+ 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->predefinedMacrosCache()->insert({}, {m_macros, languageVersion});
+
+ setFromToolchain();
+}
+
+bool IarToolChainConfigWidget::isDirtyImpl() const
+{
+ const auto tc = static_cast<IarToolChain *>(toolChain());
+ return m_compilerCommand->fileName() != tc->compilerCommand()
+ || m_abiWidget->currentAbi() != tc->targetAbi()
+ ;
+}
+
+void IarToolChainConfigWidget::makeReadOnlyImpl()
+{
+ m_compilerCommand->setReadOnly(true);
+ m_abiWidget->setEnabled(false);
+}
+
+void IarToolChainConfigWidget::setFromToolchain()
+{
+ const QSignalBlocker blocker(this);
+ const auto tc = static_cast<IarToolChain *>(toolChain());
+ m_compilerCommand->setFileName(tc->compilerCommand());
+ m_abiWidget->setAbis({}, tc->targetAbi());
+ const bool haveCompiler = compilerExists(m_compilerCommand->fileName());
+ m_abiWidget->setEnabled(haveCompiler && !tc->isAutoDetected());
+}
+
+void IarToolChainConfigWidget::handleCompilerCommandChange()
+{
+ const FilePath compilerPath = m_compilerCommand->fileName();
+ const bool haveCompiler = compilerExists(compilerPath);
+ if (haveCompiler) {
+ const auto env = Environment::systemEnvironment();
+ const auto languageId = toolChain()->language();
+ m_macros = dumpPredefinedMacros(compilerPath, languageId,
+ 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 0000000000..019c9e7185
--- /dev/null
+++ b/src/plugins/baremetal/iarewtoolchain.h
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** 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 <projectexplorer/abi.h>
+#include <projectexplorer/toolchain.h>
+#include <projectexplorer/toolchainconfigwidget.h>
+
+QT_BEGIN_NAMESPACE
+class QPlainTextEdit;
+class QPushButton;
+class QTextEdit;
+QT_END_NAMESPACE
+
+namespace Utils {
+class FilePath;
+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 final;
+
+ void setTargetAbi(const ProjectExplorer::Abi &abi);
+ ProjectExplorer::Abi targetAbi() const final;
+
+ bool isValid() const final;
+
+ MacroInspectionRunner createMacroInspectionRunner() const final;
+ ProjectExplorer::Macros predefinedMacros(const QStringList &cxxflags) const final;
+
+ Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const final;
+ ProjectExplorer::WarningFlags warningFlags(const QStringList &cxxflags) const final;
+
+ BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner() const final;
+ ProjectExplorer::HeaderPaths builtInHeaderPaths(const QStringList &cxxFlags,
+ const Utils::FilePath &) const final;
+ void addToEnvironment(Utils::Environment &env) const final;
+ ProjectExplorer::IOutputParser *outputParser() const final;
+
+ QVariantMap toMap() const final;
+ bool fromMap(const QVariantMap &data) final;
+
+ std::unique_ptr<ProjectExplorer::ToolChainConfigWidget> createConfigurationWidget() final;
+
+ bool operator ==(const ToolChain &other) const final;
+
+ void setCompilerCommand(const Utils::FilePath &file);
+ Utils::FilePath compilerCommand() const final;
+
+ Utils::FilePath makeCommand(const Utils::Environment &env) const final;
+
+private:
+ IarToolChain();
+
+ ProjectExplorer::Abi m_targetAbi;
+ Utils::FilePath m_compilerCommand;
+
+ friend class IarToolChainFactory;
+ friend class IarToolChainConfigWidget;
+};
+
+// IarToolChainFactory
+
+class IarToolChainFactory final : public ProjectExplorer::ToolChainFactory
+{
+ Q_OBJECT
+
+public:
+ IarToolChainFactory();
+
+ QList<ProjectExplorer::ToolChain *> autoDetect(
+ const QList<ProjectExplorer::ToolChain *> &alreadyKnown) final;
+
+private:
+ QList<ProjectExplorer::ToolChain *> autoDetectToolchains(const Candidates &candidates,
+ const QList<ProjectExplorer::ToolChain *> &alreadyKnown) const;
+ QList<ProjectExplorer::ToolChain *> autoDetectToolchain(
+ const Candidate &candidate, Core::Id languageId) const;
+};
+
+// IarToolChainConfigWidget
+
+class IarToolChainConfigWidget final : public ProjectExplorer::ToolChainConfigWidget
+{
+ Q_OBJECT
+
+public:
+ explicit IarToolChainConfigWidget(IarToolChain *tc);
+
+private:
+ void applyImpl() final;
+ void discardImpl() final { setFromToolchain(); }
+ bool isDirtyImpl() const final;
+ void makeReadOnlyImpl() final;
+
+ 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/baremetal/keilparser.cpp b/src/plugins/baremetal/keilparser.cpp
new file mode 100644
index 0000000000..c1f8c34731
--- /dev/null
+++ b/src/plugins/baremetal/keilparser.cpp
@@ -0,0 +1,516 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** 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 "keilparser.h"
+
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/task.h>
+
+#include <texteditor/fontsettings.h>
+#include <texteditor/texteditorsettings.h>
+
+#include <QRegularExpression>
+
+using namespace ProjectExplorer;
+
+namespace BareMetal {
+namespace Internal {
+
+// Helpers:
+
+static Task::TaskType taskType(const QString &msgType)
+{
+ if (msgType == "Warning" || msgType == "WARNING") {
+ return Task::TaskType::Warning;
+ } else if (msgType == "Error" || msgType == "ERROR"
+ || msgType == "Fatal error" || msgType == "FATAL ERROR") {
+ return Task::TaskType::Error;
+ }
+ return Task::TaskType::Unknown;
+}
+
+// KeilParser
+
+KeilParser::KeilParser()
+{
+ setObjectName("KeilParser");
+}
+
+Core::Id KeilParser::id()
+{
+ return "BareMetal.OutputParser.Keil";
+}
+
+void KeilParser::newTask(const Task &task)
+{
+ doFlush();
+ m_lastTask = task;
+ m_lines = 1;
+}
+
+void KeilParser::amendDescription(const QString &desc)
+{
+ const int start = m_lastTask.description.count() + 1;
+ m_lastTask.description.append(QLatin1Char('\n'));
+ m_lastTask.description.append(desc);
+
+ QTextLayout::FormatRange fr;
+ fr.start = start;
+ fr.length = m_lastTask.description.count() + 1;
+ fr.format.setFont(TextEditor::TextEditorSettings::fontSettings().font());
+ fr.format.setFontStyleHint(QFont::Monospace);
+ m_lastTask.formats.append(fr);
+
+ ++m_lines;
+}
+
+void KeilParser::stdError(const QString &line)
+{
+ IOutputParser::stdError(line);
+
+ const QString lne = rightTrimmed(line);
+
+ QRegularExpression re;
+ QRegularExpressionMatch match;
+
+ // ARM compiler specific patterns.
+
+ re.setPattern("^\"(.+)\", line (\\d+).*:\\s+(Warning|Error):(\\s+|.+)([#|L].+)$");
+ match = re.match(lne);
+ if (match.hasMatch()) {
+ enum CaptureIndex { FilePathIndex = 1, LineNumberIndex,
+ MessageTypeIndex, MessageNoteIndex, DescriptionIndex };
+ const Utils::FilePath fileName = Utils::FilePath::fromUserInput(
+ match.captured(FilePathIndex));
+ const int lineno = match.captured(LineNumberIndex).toInt();
+ const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
+ const QString descr = match.captured(DescriptionIndex);
+ const Task task(type, descr, fileName, lineno, Constants::TASK_CATEGORY_COMPILE);
+ newTask(task);
+ return;
+ }
+
+ re.setPattern("^(Error|Fatal error):\\s(.+)$");
+ match = re.match(lne);
+ if (match.hasMatch()) {
+ enum CaptureIndex { MessageTypeIndex = 1, DescriptionIndex };
+ const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
+ const QString descr = match.captured(DescriptionIndex);
+ const Task task(type, descr, {}, -1, Constants::TASK_CATEGORY_COMPILE);
+ newTask(task);
+ return;
+ }
+
+ if (lne.startsWith(QLatin1Char(' '))) {
+ amendDescription(lne);
+ return;
+ }
+
+ doFlush();
+}
+
+void KeilParser::stdOutput(const QString &line)
+{
+ IOutputParser::stdOutput(line);
+
+ const QString lne = rightTrimmed(line);
+
+ QRegularExpression re;
+ QRegularExpressionMatch match;
+
+ // MSC51 compiler specific patterns.
+
+ re.setPattern("^\\*{3} (WARNING|ERROR) (\\w+) IN LINE (\\d+) OF (.+\\.\\S+): (.+)$");
+ match = re.match(lne);
+ if (match.hasMatch()) {
+ enum CaptureIndex { MessageTypeIndex = 1, MessageCodeIndex, LineNumberIndex,
+ FilePathIndex, MessageTextIndex };
+ const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
+ const int lineno = match.captured(LineNumberIndex).toInt();
+ const Utils::FilePath fileName = Utils::FilePath::fromUserInput(
+ match.captured(FilePathIndex));
+ const QString descr = QString("%1: %2").arg(match.captured(MessageCodeIndex),
+ match.captured(MessageTextIndex));
+ const Task task(type, descr, fileName, lineno, Constants::TASK_CATEGORY_COMPILE);
+ newTask(task);
+ }
+
+ re.setPattern("^\\*{3} (WARNING|ERROR) (#\\w+) IN (\\d+) \\((.+), LINE \\d+\\): (.+)$");
+ match = re.match(lne);
+ if (match.hasMatch()) {
+ enum CaptureIndex { MessageTypeIndex = 1, MessageCodeIndex, LineNumberIndex,
+ FilePathIndex, MessageTextIndex };
+ const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
+ const int lineno = match.captured(LineNumberIndex).toInt();
+ const Utils::FilePath fileName = Utils::FilePath::fromUserInput(
+ match.captured(FilePathIndex));
+ const QString descr = QString("%1: %2").arg(match.captured(MessageCodeIndex),
+ match.captured(MessageTextIndex));
+ const Task task(type, descr, fileName, lineno, Constants::TASK_CATEGORY_COMPILE);
+ newTask(task);
+ }
+
+ re.setPattern("^\\*{3} (FATAL ERROR) (.+)$");
+ match = re.match(lne);
+ if (match.hasMatch()) {
+ enum CaptureIndex { MessageTypeIndex = 1, MessageDescriptionIndex };
+ const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
+ const QString descr = match.captured(MessageDescriptionIndex);
+ const Task task(type, descr, {}, -1, Constants::TASK_CATEGORY_COMPILE);
+ newTask(task);
+ return;
+ }
+
+ re.setPattern("^(A|C)51 FATAL[ |-]ERROR");
+ match = re.match(lne);
+ if (match.hasMatch()) {
+ const QString key = match.captured(1);
+ QString descr;
+ if (key == QLatin1Char('A'))
+ descr = "Assembler fatal error";
+ else if (key == QLatin1Char('C'))
+ descr = "Compiler fatal error";
+ const Task task(Task::TaskType::Error, descr, {}, -1,
+ Constants::TASK_CATEGORY_COMPILE);
+ newTask(task);
+ return;
+ }
+
+ if (lne.startsWith(QLatin1Char(' '))) {
+ amendDescription(lne);
+ return;
+ }
+
+ doFlush();
+}
+
+void KeilParser::doFlush()
+{
+ if (m_lastTask.isNull())
+ return;
+
+ Task t = m_lastTask;
+ m_lastTask.clear();
+ emit addTask(t, m_lines, 1);
+ m_lines = 0;
+}
+
+} // namespace Internal
+} // namespace BareMetal
+
+// Unit tests:
+
+#ifdef WITH_TESTS
+#include "baremetalplugin.h"
+#include <projectexplorer/outputparser_test.h>
+#include <QTest>
+
+namespace BareMetal {
+namespace Internal {
+
+void BareMetalPlugin::testKeilOutputParsers_data()
+{
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<OutputParserTester::Channel>("inputChannel");
+ QTest::addColumn<QString>("childStdOutLines");
+ QTest::addColumn<QString>("childStdErrLines");
+ QTest::addColumn<Tasks >("tasks");
+ QTest::addColumn<QString>("outputLines");
+
+ QTest::newRow("pass-through stdout")
+ << "Sometext" << OutputParserTester::STDOUT
+ << "Sometext\n" << QString()
+ << Tasks()
+ << QString();
+ QTest::newRow("pass-through stderr")
+ << "Sometext" << OutputParserTester::STDERR
+ << QString() << "Sometext\n"
+ << Tasks()
+ << QString();
+
+ const Core::Id categoryCompile = Constants::TASK_CATEGORY_COMPILE;
+
+ // ARM compiler specific patterns.
+
+ QTest::newRow("ARM: No details warning")
+ << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Warning: #1234: Some warning")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Warning: #1234: Some warning\n")
+ << (Tasks() << Task(Task::Warning,
+ QLatin1String("#1234: Some warning"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\main.c")),
+ 63,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("ARM: Details warning")
+ << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Warning: #1234: Some warning\n"
+ " int f;\n"
+ " ^")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Warning: #1234: Some warning\n"
+ " int f;\n"
+ " ^\n")
+ << (Tasks() << Task(Task::Warning,
+ QLatin1String("#1234: Some warning\n"
+ " int f;\n"
+ " ^"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\main.c")),
+ 63,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("ARM: No details error")
+ << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Error: #1234: Some error")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Error: #1234: Some error\n")
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("#1234: Some error"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\main.c")),
+ 63,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("ARM: No details error with column")
+ << QString::fromLatin1("\"flash.sct\", line 51 (column 20): Error: L1234: Some error")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("\"flash.sct\", line 51 (column 20): Error: L1234: Some error\n")
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("L1234: Some error"),
+ Utils::FilePath::fromUserInput(QLatin1String("flash.sct")),
+ 51,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("ARM: Details error")
+ << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Error: #1234: Some error\n"
+ " int f;\n"
+ " ^")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Error: #1234: Some error\n"
+ " int f;\n"
+ " ^\n")
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("#1234: Some error\n"
+ " int f;\n"
+ " ^"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\main.c")),
+ 63,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("ARM: At end of source")
+ << QString::fromLatin1("\"c:\\foo\\main.c\", line 71: Error: At end of source: #40: Some error")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("\"c:\\foo\\main.c\", line 71: Error: At end of source: #40: Some error\n")
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("#40: Some error"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\main.c")),
+ 71,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("ARM: Starts with error")
+ << QString::fromLatin1("Error: L6226E: Some error.")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("Error: L6226E: Some error.\n")
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("L6226E: Some error."),
+ Utils::FilePath(),
+ -1,
+ categoryCompile))
+ << QString();
+
+ // MCS51 compiler specific patterns.
+
+ // Assembler messages.
+ QTest::newRow("MCS51: Assembler simple warning")
+ << QString::fromLatin1("*** WARNING #A9 IN 15 (c:\\foo\\dscr.a51, LINE 15): Some warning")
+ << OutputParserTester::STDOUT
+ << QString::fromLatin1("*** WARNING #A9 IN 15 (c:\\foo\\dscr.a51, LINE 15): Some warning\n")
+ << QString()
+ << (Tasks() << Task(Task::Warning,
+ QLatin1String("#A9: Some warning"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\dscr.a51")),
+ 15,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("MCS51: Assembler simple error")
+ << QString::fromLatin1("*** ERROR #A9 IN 15 (c:\\foo\\dscr.a51, LINE 15): Some error")
+ << OutputParserTester::STDOUT
+ << QString::fromLatin1("*** ERROR #A9 IN 15 (c:\\foo\\dscr.a51, LINE 15): Some error\n")
+ << QString()
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("#A9: Some error"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\dscr.a51")),
+ 15,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("MCS51: Assembler fatal error")
+ << QString::fromLatin1("A51 FATAL ERROR -\n"
+ " Some detail 1\n"
+ " Some detail N")
+ << OutputParserTester::STDOUT
+ << QString::fromLatin1("A51 FATAL ERROR -\n"
+ " Some detail 1\n"
+ " Some detail N\n")
+ << QString()
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("Assembler fatal error\n"
+ " Some detail 1\n"
+ " Some detail N"),
+ Utils::FilePath(),
+ -1,
+ categoryCompile))
+ << QString();
+
+ // Compiler messages.
+ QTest::newRow("MCS51: Compiler simple warning")
+ << QString::fromLatin1("*** WARNING C123 IN LINE 13 OF c:\\foo.c: Some warning")
+ << OutputParserTester::STDOUT
+ << QString::fromLatin1("*** WARNING C123 IN LINE 13 OF c:\\foo.c: Some warning\n")
+ << QString()
+ << (Tasks() << Task(Task::Warning,
+ QLatin1String("C123: Some warning"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo.c")),
+ 13,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("MCS51: Compiler extended warning")
+ << QString::fromLatin1("*** WARNING C123 IN LINE 13 OF c:\\foo.c: Some warning : 'extended text'")
+ << OutputParserTester::STDOUT
+ << QString::fromLatin1("*** WARNING C123 IN LINE 13 OF c:\\foo.c: Some warning : 'extended text'\n")
+ << QString()
+ << (Tasks() << Task(Task::Warning,
+ QLatin1String("C123: Some warning : 'extended text'"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo.c")),
+ 13,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("MCS51: Compiler simple error")
+ << QString::fromLatin1("*** ERROR C123 IN LINE 13 OF c:\\foo.c: Some error")
+ << OutputParserTester::STDOUT
+ << QString::fromLatin1("*** ERROR C123 IN LINE 13 OF c:\\foo.c: Some error\n")
+ << QString()
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("C123: Some error"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo.c")),
+ 13,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("MCS51: Compiler extended error")
+ << QString::fromLatin1("*** ERROR C123 IN LINE 13 OF c:\\foo.c: Some error : 'extended text'")
+ << OutputParserTester::STDOUT
+ << QString::fromLatin1("*** ERROR C123 IN LINE 13 OF c:\\foo.c: Some error : 'extended text'\n")
+ << QString()
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("C123: Some error : 'extended text'"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo.c")),
+ 13,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("MCS51: Compiler fatal error")
+ << QString::fromLatin1("C51 FATAL-ERROR -\n"
+ " Some detail 1\n"
+ " Some detail N")
+ << OutputParserTester::STDOUT
+ << QString::fromLatin1("C51 FATAL-ERROR -\n"
+ " Some detail 1\n"
+ " Some detail N\n")
+ << QString()
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("Compiler fatal error\n"
+ " Some detail 1\n"
+ " Some detail N"),
+ Utils::FilePath(),
+ -1,
+ categoryCompile))
+ << QString();
+
+ // Linker messages.
+ QTest::newRow("MCS51: Linker simple fatal error")
+ << QString::fromLatin1("*** FATAL ERROR L456: Some error")
+ << OutputParserTester::STDOUT
+ << QString::fromLatin1("*** FATAL ERROR L456: Some error\n")
+ << QString()
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("L456: Some error"),
+ Utils::FilePath(),
+ -1,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("MCS51: Linker extended fatal error")
+ << QString::fromLatin1("*** FATAL ERROR L456: Some error\n"
+ " Some detail 1\n"
+ " Some detail N")
+ << OutputParserTester::STDOUT
+ << QString::fromLatin1("*** FATAL ERROR L456: Some error\n"
+ " Some detail 1\n"
+ " Some detail N\n")
+ << QString()
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("L456: Some error\n"
+ " Some detail 1\n"
+ " Some detail N"),
+ Utils::FilePath(),
+ -1,
+ categoryCompile))
+ << QString();
+}
+
+void BareMetalPlugin::testKeilOutputParsers()
+{
+ OutputParserTester testbench;
+ testbench.appendOutputParser(new KeilParser);
+ QFETCH(QString, input);
+ QFETCH(OutputParserTester::Channel, inputChannel);
+ QFETCH(Tasks, tasks);
+ QFETCH(QString, childStdOutLines);
+ QFETCH(QString, childStdErrLines);
+ QFETCH(QString, outputLines);
+
+ testbench.testParsing(input, inputChannel,
+ tasks, childStdOutLines, childStdErrLines,
+ outputLines);
+}
+
+} // namespace Internal
+} // namespace BareMetal
+
+#endif // WITH_TESTS
diff --git a/src/plugins/baremetal/baremetaldeviceconfigurationfactory.h b/src/plugins/baremetal/keilparser.h
index 5415491d90..d8e9bdfd7d 100644
--- a/src/plugins/baremetal/baremetaldeviceconfigurationfactory.h
+++ b/src/plugins/baremetal/keilparser.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 Tim Sander <tim@krieglstein.org>
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,20 +25,32 @@
#pragma once
-#include <projectexplorer/devicesupport/idevicefactory.h>
+#include <projectexplorer/ioutputparser.h>
+#include <projectexplorer/task.h>
namespace BareMetal {
namespace Internal {
-class BareMetalDeviceConfigurationFactory
- : public ProjectExplorer::IDeviceFactory
+// KeilParser
+
+class KeilParser final : public ProjectExplorer::IOutputParser
{
Q_OBJECT
public:
- BareMetalDeviceConfigurationFactory();
+ explicit KeilParser();
+ static Core::Id id();
+
+private:
+ void newTask(const ProjectExplorer::Task &task);
+ void amendDescription(const QString &desc);
+
+ void stdError(const QString &line) final;
+ void stdOutput(const QString &line) final;
+ void doFlush() final;
- ProjectExplorer::IDevice::Ptr create() const override;
+ ProjectExplorer::Task m_lastTask;
+ int m_lines = 0;
};
} // namespace Internal
diff --git a/src/plugins/baremetal/keiltoolchain.cpp b/src/plugins/baremetal/keiltoolchain.cpp
new file mode 100644
index 0000000000..303efa3440
--- /dev/null
+++ b/src/plugins/baremetal/keiltoolchain.cpp
@@ -0,0 +1,596 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** 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 "keilparser.h"
+#include "keiltoolchain.h"
+
+#include <projectexplorer/abiwidget.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/projectmacro.h>
+#include <projectexplorer/toolchainmanager.h>
+
+#include <utils/algorithm.h>
+#include <utils/environment.h>
+#include <utils/pathchooser.h>
+#include <utils/qtcassert.h>
+#include <utils/synchronousprocess.h>
+
+#include <QDebug>
+#include <QDir>
+#include <QFileInfo>
+#include <QFormLayout>
+#include <QLineEdit>
+#include <QPlainTextEdit>
+#include <QSettings>
+#include <QTemporaryFile>
+#include <QTextStream>
+
+#include <array>
+
+using namespace ProjectExplorer;
+using namespace Utils;
+
+namespace BareMetal {
+namespace Internal {
+
+// Helpers:
+
+static const char compilerCommandKeyC[] = "BareMetal.KeilToolchain.CompilerPath";
+static const char targetAbiKeyC[] = "BareMetal.KeilToolchain.TargetAbi";
+
+static bool compilerExists(const FilePath &compilerPath)
+{
+ const QFileInfo fi = compilerPath.toFileInfo();
+ return fi.exists() && fi.isExecutable() && fi.isFile();
+}
+
+static Abi::Architecture guessArchitecture(const FilePath &compilerPath)
+{
+ const QFileInfo fi = compilerPath.toFileInfo();
+ const QString bn = fi.baseName().toLower();
+ if (bn == "c51" || bn == "cx51")
+ return Abi::Architecture::Mcs51Architecture;
+ if (bn == "armcc")
+ return Abi::Architecture::ArmArchitecture;
+ return Abi::Architecture::UnknownArchitecture;
+}
+
+// Note: The KEIL 8051 compiler does not support the predefined
+// macros dumping. So, we do it with following trick where we try
+// to compile a temporary file and to parse the console output.
+static Macros dumpC51PredefinedMacros(const FilePath &compiler, const QStringList &env)
+{
+ QTemporaryFile fakeIn;
+ if (!fakeIn.open())
+ return {};
+ fakeIn.write("#define VALUE_TO_STRING(x) #x\n");
+ fakeIn.write("#define VALUE(x) VALUE_TO_STRING(x)\n");
+ fakeIn.write("#define VAR_NAME_VALUE(var) \"\"\"|\"#var\"|\"VALUE(var)\n");
+ fakeIn.write("#ifdef __C51__\n");
+ fakeIn.write("#pragma message(VAR_NAME_VALUE(__C51__))\n");
+ fakeIn.write("#endif\n");
+ fakeIn.write("#ifdef __CX51__\n");
+ fakeIn.write("#pragma message(VAR_NAME_VALUE(__CX51__))\n");
+ fakeIn.write("#endif\n");
+ fakeIn.close();
+
+ SynchronousProcess cpp;
+ cpp.setEnvironment(env);
+ cpp.setTimeoutS(10);
+
+ QStringList arguments;
+ arguments.push_back(fakeIn.fileName());
+
+ const SynchronousProcessResponse response = cpp.runBlocking(compiler.toString(), arguments);
+ if (response.result != SynchronousProcessResponse::Finished
+ || response.exitCode != 0) {
+ qWarning() << response.exitMessage(compiler.toString(), 10);
+ return {};
+ }
+
+ QString output = response.allOutput();
+ Macros macros;
+ QTextStream stream(&output);
+ QString line;
+ while (stream.readLineInto(&line)) {
+ const QStringList parts = line.split("\"|\"");
+ if (parts.count() != 3)
+ continue;
+ macros.push_back({parts.at(1).toUtf8(), parts.at(2).toUtf8()});
+ }
+ return macros;
+}
+
+static Macros dumpArmPredefinedMacros(const FilePath &compiler, const QStringList &env)
+{
+ SynchronousProcess cpp;
+ cpp.setEnvironment(env);
+ cpp.setTimeoutS(10);
+
+ QStringList arguments;
+ arguments.push_back("-E");
+ arguments.push_back("--list-macros");
+
+ const SynchronousProcessResponse response = cpp.runBlocking(compiler.toString(), arguments);
+ if (response.result != SynchronousProcessResponse::Finished
+ || response.exitCode != 0) {
+ qWarning() << response.exitMessage(compiler.toString(), 10);
+ return {};
+ }
+
+ const QByteArray output = response.allOutput().toUtf8();
+ return Macro::toMacros(output);
+}
+
+static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList &env)
+{
+ if (compiler.isEmpty() || !compiler.toFileInfo().isExecutable())
+ return {};
+
+ const Abi::Architecture arch = guessArchitecture(compiler);
+ switch (arch) {
+ case Abi::Architecture::Mcs51Architecture:
+ return dumpC51PredefinedMacros(compiler, env);
+ case Abi::Architecture::ArmArchitecture:
+ return dumpArmPredefinedMacros(compiler, env);
+ default:
+ return {};
+ }
+}
+
+static HeaderPaths dumpHeaderPaths(const FilePath &compiler)
+{
+ if (!compiler.exists())
+ return {};
+
+ QDir toolkitDir(compiler.parentDir().toString());
+ if (!toolkitDir.cdUp())
+ return {};
+
+ HeaderPaths headerPaths;
+
+ const Abi::Architecture arch = guessArchitecture(compiler);
+ if (arch == Abi::Architecture::Mcs51Architecture) {
+ QDir includeDir(toolkitDir);
+ if (includeDir.cd("inc"))
+ headerPaths.push_back({includeDir.canonicalPath(), HeaderPathType::BuiltIn});
+ } else if (arch == Abi::Architecture::ArmArchitecture) {
+ QDir includeDir(toolkitDir);
+ if (includeDir.cd("include"))
+ headerPaths.push_back({includeDir.canonicalPath(), HeaderPathType::BuiltIn});
+ }
+
+ return headerPaths;
+}
+
+static Abi::Architecture guessArchitecture(const Macros &macros)
+{
+ for (const Macro &macro : macros) {
+ if (macro.key == "__CC_ARM")
+ return Abi::Architecture::ArmArchitecture;
+ if (macro.key == "__C51__" || macro.key == "__CX51__")
+ return Abi::Architecture::Mcs51Architecture;
+ }
+ return Abi::Architecture::UnknownArchitecture;
+}
+
+static unsigned char guessWordWidth(const Macros &macros, Abi::Architecture arch)
+{
+ // Check for C51 compiler first.
+ if (arch == Abi::Architecture::Mcs51Architecture)
+ return 16; // C51 always have 16-bit word width.
+
+ const Macro sizeMacro = Utils::findOrDefault(macros, [](const Macro &m) {
+ return m.key == "__sizeof_int";
+ });
+ 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)
+ return Abi::BinaryFormat::OmfFormat;
+ return Abi::BinaryFormat::UnknownFormat;
+}
+
+static Abi guessAbi(const Macros &macros)
+{
+ const auto arch = guessArchitecture(macros);
+ return {arch, Abi::OS::BareMetalOS, Abi::OSFlavor::GenericFlavor,
+ guessFormat(arch), guessWordWidth(macros, arch)};
+}
+
+static QString buildDisplayName(Abi::Architecture arch, Core::Id language,
+ const QString &version)
+{
+ const auto archName = Abi::toString(arch);
+ const auto langName = ToolChainManager::displayNameOfLanguageId(language);
+ return KeilToolchain::tr("KEIL %1 (%2, %3)")
+ .arg(version, langName, archName);
+}
+
+// KeilToolchain
+
+KeilToolchain::KeilToolchain() :
+ ToolChain(Constants::KEIL_TOOLCHAIN_TYPEID)
+{ }
+
+QString KeilToolchain::typeDisplayName() const
+{
+ return Internal::KeilToolchainFactory::tr("KEIL");
+}
+
+void KeilToolchain::setTargetAbi(const Abi &abi)
+{
+ if (abi == m_targetAbi)
+ return;
+ m_targetAbi = abi;
+ toolChainUpdated();
+}
+
+Abi KeilToolchain::targetAbi() const
+{
+ return m_targetAbi;
+}
+
+bool KeilToolchain::isValid() const
+{
+ return true;
+}
+
+ToolChain::MacroInspectionRunner KeilToolchain::createMacroInspectionRunner() const
+{
+ Environment env = Environment::systemEnvironment();
+ addToEnvironment(env);
+
+ const Utils::FilePath compilerCommand = m_compilerCommand;
+ const Core::Id lang = language();
+
+ MacrosCache macroCache = predefinedMacrosCache();
+
+ return [env, compilerCommand, macroCache, lang]
+ (const QStringList &flags) {
+ Q_UNUSED(flags)
+
+ const Macros macros = dumpPredefinedMacros(compilerCommand, env.toStringList());
+ const auto report = MacroInspectionReport{macros, languageVersion(lang, macros)};
+ macroCache->insert({}, report);
+
+ return report;
+ };
+}
+
+Macros KeilToolchain::predefinedMacros(const QStringList &cxxflags) const
+{
+ return createMacroInspectionRunner()(cxxflags).macros;
+}
+
+Utils::LanguageExtensions KeilToolchain::languageExtensions(const QStringList &) const
+{
+ return LanguageExtension::None;
+}
+
+WarningFlags KeilToolchain::warningFlags(const QStringList &cxxflags) const
+{
+ Q_UNUSED(cxxflags);
+ return WarningFlags::Default;
+}
+
+ToolChain::BuiltInHeaderPathsRunner KeilToolchain::createBuiltInHeaderPathsRunner() const
+{
+ const Utils::FilePath compilerCommand = m_compilerCommand;
+
+ HeaderPathsCache headerPaths = headerPathsCache();
+
+ return [compilerCommand,
+ headerPaths](const QStringList &flags, const QString &fileName, const QString &) {
+ Q_UNUSED(flags)
+ Q_UNUSED(fileName)
+
+ const HeaderPaths paths = dumpHeaderPaths(compilerCommand);
+ headerPaths->insert({}, paths);
+
+ return paths;
+ };
+}
+
+HeaderPaths KeilToolchain::builtInHeaderPaths(const QStringList &cxxFlags,
+ const FilePath &fileName) const
+{
+ return createBuiltInHeaderPathsRunner()(cxxFlags, fileName.toString(), "");
+}
+
+void KeilToolchain::addToEnvironment(Environment &env) const
+{
+ if (!m_compilerCommand.isEmpty()) {
+ const FilePath path = m_compilerCommand.parentDir();
+ env.prependOrSetPath(path.toString());
+ }
+}
+
+IOutputParser *KeilToolchain::outputParser() const
+{
+ return new KeilParser;
+}
+
+QVariantMap KeilToolchain::toMap() const
+{
+ QVariantMap data = ToolChain::toMap();
+ data.insert(compilerCommandKeyC, m_compilerCommand.toString());
+ data.insert(targetAbiKeyC, m_targetAbi.toString());
+ return data;
+}
+
+bool KeilToolchain::fromMap(const QVariantMap &data)
+{
+ if (!ToolChain::fromMap(data))
+ return false;
+ m_compilerCommand = FilePath::fromString(data.value(compilerCommandKeyC).toString());
+ m_targetAbi = Abi::fromString(data.value(targetAbiKeyC).toString());
+ return true;
+}
+
+std::unique_ptr<ToolChainConfigWidget> KeilToolchain::createConfigurationWidget()
+{
+ return std::make_unique<KeilToolchainConfigWidget>(this);
+}
+
+bool KeilToolchain::operator ==(const ToolChain &other) const
+{
+ if (!ToolChain::operator ==(other))
+ return false;
+
+ const auto customTc = static_cast<const KeilToolchain *>(&other);
+ return m_compilerCommand == customTc->m_compilerCommand
+ && m_targetAbi == customTc->m_targetAbi
+ ;
+}
+
+void KeilToolchain::setCompilerCommand(const FilePath &file)
+{
+ if (file == m_compilerCommand)
+ return;
+ m_compilerCommand = file;
+ toolChainUpdated();
+}
+
+FilePath KeilToolchain::compilerCommand() const
+{
+ return m_compilerCommand;
+}
+
+FilePath KeilToolchain::makeCommand(const Environment &env) const
+{
+ Q_UNUSED(env)
+ return {};
+}
+
+// KeilToolchainFactory
+
+KeilToolchainFactory::KeilToolchainFactory()
+{
+ setDisplayName(tr("KEIL"));
+ setSupportedToolChainType(Constants::KEIL_TOOLCHAIN_TYPEID);
+ setSupportedLanguages({ProjectExplorer::Constants::C_LANGUAGE_ID,
+ ProjectExplorer::Constants::CXX_LANGUAGE_ID});
+ setToolchainConstructor([] { return new KeilToolchain; });
+ setUserCreatable(true);
+}
+
+QList<ToolChain *> KeilToolchainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
+{
+#ifdef Q_OS_WIN64
+ static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Keil\\Products";
+#else
+ static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Keil\\Products";
+#endif
+
+ struct Entry {
+ QString productKey;
+ QString subExePath;
+ };
+
+ // Dictionary for know toolchains.
+ static const std::array<Entry, 2> knowToolchains = {{
+ {QString("MDK"), QString("\\ARMCC\\bin\\armcc.exe")},
+ {QString("C51"), QString("\\BIN\\c51.exe")},
+ }};
+
+ Candidates candidates;
+
+ QSettings registry(kRegistryNode, QSettings::NativeFormat);
+ const auto productGroups = registry.childGroups();
+ for (const QString &productKey : productGroups) {
+ const Entry entry = Utils::findOrDefault(knowToolchains,
+ [productKey](const Entry &entry) {
+ return entry.productKey == productKey; });
+
+ if (entry.productKey.isEmpty())
+ continue;
+
+ registry.beginGroup(productKey);
+ QString compilerPath = registry.value("Path").toString();
+ if (!compilerPath.isEmpty()) {
+ // Build full compiler path.
+ compilerPath += entry.subExePath;
+ const FilePath fn = FilePath::fromString(compilerPath);
+ if (compilerExists(fn)) {
+ QString version = registry.value("Version").toString();
+ if (version.startsWith('V'))
+ version.remove(0, 1);
+ candidates.push_back({fn, version});
+ }
+ }
+ registry.endGroup();
+ }
+
+ return autoDetectToolchains(candidates, alreadyKnown);
+}
+
+QList<ToolChain *> KeilToolchainFactory::autoDetectToolchains(
+ const Candidates &candidates, const QList<ToolChain *> &alreadyKnown) const
+{
+ QList<ToolChain *> result;
+
+ for (const Candidate &candidate : qAsConst(candidates)) {
+ const QList<ToolChain *> filtered = Utils::filtered(
+ alreadyKnown, [candidate](ToolChain *tc) {
+ return tc->typeId() == Constants::IAREW_TOOLCHAIN_TYPEID
+ && tc->compilerCommand() == candidate.compilerPath
+ && (tc->language() == ProjectExplorer::Constants::C_LANGUAGE_ID
+ || tc->language() == ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ });
+
+ if (!filtered.isEmpty()) {
+ result << filtered;
+ continue;
+ }
+
+ // Create toolchains for both C and C++ languages.
+ result << autoDetectToolchain(candidate, ProjectExplorer::Constants::C_LANGUAGE_ID);
+ result << autoDetectToolchain(candidate, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ }
+
+ return result;
+}
+
+QList<ToolChain *> KeilToolchainFactory::autoDetectToolchain(
+ const Candidate &candidate, Core::Id language) const
+{
+ const auto env = Environment::systemEnvironment();
+ const Macros macros = dumpPredefinedMacros(candidate.compilerPath, env.toStringList());
+ if (macros.isEmpty())
+ return {};
+
+ const Abi abi = guessAbi(macros);
+ const Abi::Architecture arch = abi.architecture();
+ if (arch == Abi::Architecture::Mcs51Architecture
+ && language == ProjectExplorer::Constants::CXX_LANGUAGE_ID) {
+ // KEIL C51 compiler does not support C++ language.
+ return {};
+ }
+
+ const auto tc = new KeilToolchain;
+ tc->setDetection(ToolChain::AutoDetection);
+ tc->setLanguage(language);
+ tc->setCompilerCommand(candidate.compilerPath);
+ tc->setTargetAbi(abi);
+ tc->setDisplayName(buildDisplayName(abi.architecture(), language, candidate.compilerVersion));
+
+ const auto languageVersion = ToolChain::languageVersion(language, macros);
+ tc->predefinedMacrosCache()->insert({}, {macros, languageVersion});
+ return {tc};
+}
+
+// KeilToolchainConfigWidget
+
+KeilToolchainConfigWidget::KeilToolchainConfigWidget(KeilToolchain *tc) :
+ ToolChainConfigWidget(tc),
+ m_compilerCommand(new PathChooser),
+ m_abiWidget(new AbiWidget)
+{
+ m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand);
+ m_compilerCommand->setHistoryCompleter("PE.KEIL.Command.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, &KeilToolchainConfigWidget::handleCompilerCommandChange);
+ connect(m_abiWidget, &AbiWidget::abiChanged,
+ this, &ToolChainConfigWidget::dirty);
+}
+
+void KeilToolchainConfigWidget::applyImpl()
+{
+ if (toolChain()->isAutoDetected())
+ return;
+
+ const auto tc = static_cast<KeilToolchain *>(toolChain());
+ 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->predefinedMacrosCache()->insert({}, {m_macros, languageVersion});
+
+ setFromToolchain();
+}
+
+bool KeilToolchainConfigWidget::isDirtyImpl() const
+{
+ const auto tc = static_cast<KeilToolchain *>(toolChain());
+ return m_compilerCommand->fileName() != tc->compilerCommand()
+ || m_abiWidget->currentAbi() != tc->targetAbi()
+ ;
+}
+
+void KeilToolchainConfigWidget::makeReadOnlyImpl()
+{
+ m_compilerCommand->setReadOnly(true);
+ m_abiWidget->setEnabled(false);
+}
+
+void KeilToolchainConfigWidget::setFromToolchain()
+{
+ const QSignalBlocker blocker(this);
+ const auto tc = static_cast<KeilToolchain *>(toolChain());
+ m_compilerCommand->setFileName(tc->compilerCommand());
+ m_abiWidget->setAbis({}, tc->targetAbi());
+ const bool haveCompiler = compilerExists(m_compilerCommand->fileName());
+ m_abiWidget->setEnabled(haveCompiler && !tc->isAutoDetected());
+}
+
+void KeilToolchainConfigWidget::handleCompilerCommandChange()
+{
+ const FilePath compilerPath = m_compilerCommand->fileName();
+ const bool haveCompiler = compilerExists(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/keiltoolchain.h b/src/plugins/baremetal/keiltoolchain.h
new file mode 100644
index 0000000000..5ccf9e05ff
--- /dev/null
+++ b/src/plugins/baremetal/keiltoolchain.h
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** 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 <projectexplorer/abi.h>
+#include <projectexplorer/toolchain.h>
+#include <projectexplorer/toolchainconfigwidget.h>
+
+QT_BEGIN_NAMESPACE
+class QPlainTextEdit;
+class QPushButton;
+class QTextEdit;
+QT_END_NAMESPACE
+
+namespace Utils {
+class FilePath;
+class PathChooser;
+}
+
+namespace ProjectExplorer { class AbiWidget; }
+
+namespace BareMetal {
+namespace Internal {
+
+// KeilToolchain
+
+class KeilToolchain final : public ProjectExplorer::ToolChain
+{
+ Q_DECLARE_TR_FUNCTIONS(KeilToolchain)
+
+public:
+ QString typeDisplayName() const final;
+
+ void setTargetAbi(const ProjectExplorer::Abi &abi);
+ ProjectExplorer::Abi targetAbi() const final;
+
+ bool isValid() const final;
+
+ MacroInspectionRunner createMacroInspectionRunner() const final;
+ ProjectExplorer::Macros predefinedMacros(const QStringList &cxxflags) const final;
+
+ Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const final;
+ ProjectExplorer::WarningFlags warningFlags(const QStringList &cxxflags) const final;
+
+ BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner() const final;
+ ProjectExplorer::HeaderPaths builtInHeaderPaths(const QStringList &cxxFlags,
+ const Utils::FilePath &) const final;
+ void addToEnvironment(Utils::Environment &env) const final;
+ ProjectExplorer::IOutputParser *outputParser() const final;
+
+ QVariantMap toMap() const final;
+ bool fromMap(const QVariantMap &data) final;
+
+ std::unique_ptr<ProjectExplorer::ToolChainConfigWidget> createConfigurationWidget() final;
+
+ bool operator ==(const ToolChain &other) const final;
+
+ void setCompilerCommand(const Utils::FilePath &file);
+ Utils::FilePath compilerCommand() const final;
+
+ Utils::FilePath makeCommand(const Utils::Environment &env) const final;
+
+private:
+ KeilToolchain();
+
+ ProjectExplorer::Abi m_targetAbi;
+ Utils::FilePath m_compilerCommand;
+
+ friend class KeilToolchainFactory;
+ friend class KeilToolchainConfigWidget;
+};
+
+// KeilToolchainFactory
+
+class KeilToolchainFactory final : public ProjectExplorer::ToolChainFactory
+{
+ Q_OBJECT
+
+public:
+ KeilToolchainFactory();
+
+ QList<ProjectExplorer::ToolChain *> autoDetect(
+ const QList<ProjectExplorer::ToolChain *> &alreadyKnown) final;
+
+private:
+ QList<ProjectExplorer::ToolChain *> autoDetectToolchains(const Candidates &candidates,
+ const QList<ProjectExplorer::ToolChain *> &alreadyKnown) const;
+ QList<ProjectExplorer::ToolChain *> autoDetectToolchain(
+ const Candidate &candidate, Core::Id language) const;
+};
+
+// KeilToolchainConfigWidget
+
+class KeilToolchainConfigWidget final : public ProjectExplorer::ToolChainConfigWidget
+{
+ Q_OBJECT
+
+public:
+ explicit KeilToolchainConfigWidget(KeilToolchain *tc);
+
+private:
+ void applyImpl() final;
+ void discardImpl() final { setFromToolchain(); }
+ bool isDirtyImpl() const final;
+ void makeReadOnlyImpl() final;
+
+ 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/baremetal/openocdgdbserverprovider.cpp b/src/plugins/baremetal/openocdgdbserverprovider.cpp
index 33d05c88a2..b7044defe0 100644
--- a/src/plugins/baremetal/openocdgdbserverprovider.cpp
+++ b/src/plugins/baremetal/openocdgdbserverprovider.cpp
@@ -23,25 +23,26 @@
**
****************************************************************************/
-#include "openocdgdbserverprovider.h"
#include "baremetalconstants.h"
+
#include "gdbserverprovidermanager.h"
+#include "openocdgdbserverprovider.h"
+#include <utils/fileutils.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
-#include <utils/fileutils.h>
#include <utils/qtcprocess.h>
#include <coreplugin/variablechooser.h>
-#include <QString>
+#include <QComboBox>
#include <QFileInfo>
-
#include <QFormLayout>
#include <QLineEdit>
-#include <QComboBox>
#include <QPlainTextEdit>
+using namespace Utils;
+
namespace BareMetal {
namespace Internal {
@@ -52,11 +53,10 @@ const char rootScriptsDirKeyC[] = "BareMetal.OpenOcdGdbServerProvider.RootScript
const char configurationFileKeyC[] = "BareMetal.OpenOcdGdbServerProvider.ConfigurationPath";
const char additionalArgumentsKeyC[] = "BareMetal.OpenOcdGdbServerProvider.AdditionalArguments";
+// OpenOcdGdbServerProvider
+
OpenOcdGdbServerProvider::OpenOcdGdbServerProvider()
: GdbServerProvider(QLatin1String(Constants::OPENOCD_PROVIDER_ID))
- , m_host(QLatin1String("localhost"))
- , m_port(3333)
- , m_executableFile(QLatin1String("openocd"))
{
setInitCommands(defaultInitCommands());
setResetCommands(defaultResetCommands());
@@ -93,48 +93,43 @@ QString OpenOcdGdbServerProvider::channel() const
// Just return as "host:port" form.
return m_host + QLatin1Char(':') + QString::number(m_port);
case StartupOnPipe: {
- QStringList args;
// In the pipe mode need to add quotes to each item of arguments;
// otherwise running will be stuck.
- foreach (const QString &a, arguments()) {
- if (a.startsWith(QLatin1Char('\"')) && a.endsWith(QLatin1Char('\"')))
- continue;
- args << (QLatin1Char('\"') + a + QLatin1Char('\"'));
+ CommandLine cmd = command();
+ QStringList args = {"|", cmd.executable().toString()};
+ for (const QString &a : QtcProcess::splitArgs(cmd.arguments())) {
+ if (a.startsWith('\"') && a.endsWith('\"'))
+ args << a;
+ else
+ args << ('\"' + a + '\"');
}
- args.prepend(executable());
- args.prepend(QLatin1String("|"));
- return args.join(QLatin1Char(' '));
+ return args.join(' ');
}
default: // wrong
- return QString();
+ return {};
}
}
-QString OpenOcdGdbServerProvider::executable() const
-{
- return m_executableFile;
-}
-
-QStringList OpenOcdGdbServerProvider::arguments() const
+CommandLine OpenOcdGdbServerProvider::command() const
{
- QStringList args;
+ CommandLine cmd{m_executableFile, {}};
- args << QLatin1String("-c");
+ cmd.addArg("-c");
if (startupMode() == StartupOnPipe)
- args << QLatin1String("gdb_port pipe");
+ cmd.addArg("gdb_port pipe");
else
- args << (QLatin1String("gdb_port ") + QString::number(m_port));
+ cmd.addArg("gdb_port " + QString::number(m_port));
if (!m_rootScriptsDir.isEmpty())
- args << QLatin1String("-s") << m_rootScriptsDir;
+ cmd.addArgs({"-s", m_rootScriptsDir});
if (!m_configurationFile.isEmpty())
- args << QLatin1String("-f") << m_configurationFile;
+ cmd.addArgs({"-f", m_configurationFile});
if (!m_additionalArguments.isEmpty())
- args << Utils::QtcProcess::splitArgs(m_additionalArguments);
+ cmd.addArgs(m_additionalArguments);
- return args;
+ return cmd;
}
bool OpenOcdGdbServerProvider::canStartupMode(StartupMode m) const
@@ -172,7 +167,7 @@ QVariantMap OpenOcdGdbServerProvider::toMap() const
QVariantMap data = GdbServerProvider::toMap();
data.insert(QLatin1String(hostKeyC), m_host);
data.insert(QLatin1String(portKeyC), m_port);
- data.insert(QLatin1String(executableFileKeyC), m_executableFile);
+ data.insert(QLatin1String(executableFileKeyC), m_executableFile.toVariant());
data.insert(QLatin1String(rootScriptsDirKeyC), m_rootScriptsDir);
data.insert(QLatin1String(configurationFileKeyC), m_configurationFile);
data.insert(QLatin1String(additionalArgumentsKeyC), m_additionalArguments);
@@ -186,7 +181,7 @@ bool OpenOcdGdbServerProvider::fromMap(const QVariantMap &data)
m_host = data.value(QLatin1String(hostKeyC)).toString();
m_port = data.value(QLatin1String(portKeyC)).toInt();
- m_executableFile = data.value(QLatin1String(executableFileKeyC)).toString();
+ m_executableFile = FilePath::fromVariant(data.value(QLatin1String(executableFileKeyC)));
m_rootScriptsDir = data.value(QLatin1String(rootScriptsDirKeyC)).toString();
m_configurationFile = data.value(QLatin1String(configurationFileKeyC)).toString();
m_additionalArguments = data.value(QLatin1String(additionalArgumentsKeyC)).toString();
@@ -212,6 +207,8 @@ GdbServerProviderConfigWidget *OpenOcdGdbServerProvider::configurationWidget()
return new OpenOcdGdbServerProviderConfigWidget(this);
}
+// OpenOcdGdbServerProviderFactory
+
OpenOcdGdbServerProviderFactory::OpenOcdGdbServerProviderFactory()
{
setId(QLatin1String(Constants::OPENOCD_PROVIDER_ID));
@@ -232,14 +229,16 @@ bool OpenOcdGdbServerProviderFactory::canRestore(const QVariantMap &data) const
GdbServerProvider *OpenOcdGdbServerProviderFactory::restore(const QVariantMap &data)
{
- auto p = new OpenOcdGdbServerProvider;
- auto updated = data;
+ const auto p = new OpenOcdGdbServerProvider;
+ const auto updated = data;
if (p->fromMap(updated))
return p;
delete p;
return nullptr;
}
+// OpenOcdGdbServerProviderConfigWidget
+
OpenOcdGdbServerProviderConfigWidget::OpenOcdGdbServerProviderConfigWidget(
OpenOcdGdbServerProvider *p)
: GdbServerProviderConfigWidget(p)
@@ -276,7 +275,7 @@ OpenOcdGdbServerProviderConfigWidget::OpenOcdGdbServerProviderConfigWidget(
addErrorLabel();
setFromProvider();
- auto chooser = new Core::VariableChooser(this);
+ const auto chooser = new Core::VariableChooser(this);
chooser->addSupportedWidget(m_initCommandsTextEdit);
chooser->addSupportedWidget(m_resetCommandsTextEdit);
@@ -295,7 +294,7 @@ OpenOcdGdbServerProviderConfigWidget::OpenOcdGdbServerProviderConfigWidget(
connect(m_resetCommandsTextEdit, &QPlainTextEdit::textChanged,
this, &GdbServerProviderConfigWidget::dirty);
- connect(m_startupModeComboBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ connect(m_startupModeComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &OpenOcdGdbServerProviderConfigWidget::startupModeChanged);
}
@@ -318,12 +317,12 @@ void OpenOcdGdbServerProviderConfigWidget::startupModeChanged()
void OpenOcdGdbServerProviderConfigWidget::applyImpl()
{
- auto p = static_cast<OpenOcdGdbServerProvider *>(provider());
+ const auto p = static_cast<OpenOcdGdbServerProvider *>(provider());
Q_ASSERT(p);
p->m_host = m_hostWidget->host();
p->m_port = m_hostWidget->port();
- p->m_executableFile = m_executableFileChooser->fileName().toString();
+ p->m_executableFile = m_executableFileChooser->fileName();
p->m_rootScriptsDir = m_rootScriptsDirChooser->fileName().toString();
p->m_configurationFile = m_configurationFileChooser->fileName().toString();
p->m_additionalArguments = m_additionalArgumentsLineEdit->text();
@@ -341,13 +340,13 @@ void OpenOcdGdbServerProviderConfigWidget::setFromProvider()
const auto p = static_cast<OpenOcdGdbServerProvider *>(provider());
Q_ASSERT(p);
- QSignalBlocker blocker(this);
+ const QSignalBlocker blocker(this);
startupModeChanged();
m_hostWidget->setHost(p->m_host);
m_hostWidget->setPort(p->m_port);
- m_executableFileChooser->setFileName(Utils::FileName::fromString(p->m_executableFile));
- m_rootScriptsDirChooser->setFileName(Utils::FileName::fromString(p->m_rootScriptsDir));
- m_configurationFileChooser->setFileName(Utils::FileName::fromString(p->m_configurationFile));
+ m_executableFileChooser->setFileName(p->m_executableFile);
+ m_rootScriptsDirChooser->setFileName(Utils::FilePath::fromString(p->m_rootScriptsDir));
+ m_configurationFileChooser->setFileName(Utils::FilePath::fromString(p->m_configurationFile));
m_additionalArgumentsLineEdit->setText(p->m_additionalArguments);
m_initCommandsTextEdit->setPlainText(p->initCommands());
m_resetCommandsTextEdit->setPlainText(p->resetCommands());
diff --git a/src/plugins/baremetal/openocdgdbserverprovider.h b/src/plugins/baremetal/openocdgdbserverprovider.h
index 94481775ed..229b12bf61 100644
--- a/src/plugins/baremetal/openocdgdbserverprovider.h
+++ b/src/plugins/baremetal/openocdgdbserverprovider.h
@@ -35,7 +35,9 @@ namespace Internal {
class OpenOcdGdbServerProviderConfigWidget;
class OpenOcdGdbServerProviderFactory;
-class OpenOcdGdbServerProvider : public GdbServerProvider
+// OpenOcdGdbServerProvider
+
+class OpenOcdGdbServerProvider final : public GdbServerProvider
{
public:
QString typeDisplayName() const final;
@@ -49,8 +51,7 @@ public:
GdbServerProvider *clone() const final;
QString channel() const final;
- QString executable() const final;
- QStringList arguments() const final;
+ Utils::CommandLine command() const final;
bool canStartupMode(StartupMode mode) const final;
bool isValid() const final;
@@ -62,9 +63,9 @@ private:
static QString defaultInitCommands();
static QString defaultResetCommands();
- QString m_host;
- quint16 m_port;
- QString m_executableFile;
+ QString m_host = QLatin1String("localhost");
+ quint16 m_port = 3333;
+ Utils::FilePath m_executableFile = Utils::FilePath::fromString("openocd");
QString m_rootScriptsDir;
QString m_configurationFile;
QString m_additionalArguments;
@@ -73,7 +74,9 @@ private:
friend class OpenOcdGdbServerProviderFactory;
};
-class OpenOcdGdbServerProviderFactory : public GdbServerProviderFactory
+// OpenOcdGdbServerProviderFactory
+
+class OpenOcdGdbServerProviderFactory final : public GdbServerProviderFactory
{
Q_OBJECT
@@ -88,7 +91,9 @@ public:
GdbServerProviderConfigWidget *configurationWidget(GdbServerProvider *);
};
-class OpenOcdGdbServerProviderConfigWidget : public GdbServerProviderConfigWidget
+// OpenOcdGdbServerProviderConfigWidget
+
+class OpenOcdGdbServerProviderConfigWidget final : public GdbServerProviderConfigWidget
{
Q_OBJECT
@@ -103,13 +108,13 @@ private:
void setFromProvider();
- HostWidget *m_hostWidget;
- Utils::PathChooser *m_executableFileChooser;
- Utils::PathChooser *m_rootScriptsDirChooser;
- Utils::PathChooser *m_configurationFileChooser;
- QLineEdit *m_additionalArgumentsLineEdit;
- QPlainTextEdit *m_initCommandsTextEdit;
- QPlainTextEdit *m_resetCommandsTextEdit;
+ HostWidget *m_hostWidget = nullptr;
+ Utils::PathChooser *m_executableFileChooser = nullptr;
+ Utils::PathChooser *m_rootScriptsDirChooser = nullptr;
+ Utils::PathChooser *m_configurationFileChooser = nullptr;
+ QLineEdit *m_additionalArgumentsLineEdit = nullptr;
+ QPlainTextEdit *m_initCommandsTextEdit = nullptr;
+ QPlainTextEdit *m_resetCommandsTextEdit = nullptr;
};
} // namespace Internal
diff --git a/src/plugins/baremetal/sdccparser.cpp b/src/plugins/baremetal/sdccparser.cpp
new file mode 100644
index 0000000000..e84021dd7b
--- /dev/null
+++ b/src/plugins/baremetal/sdccparser.cpp
@@ -0,0 +1,339 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** 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 "sdccparser.h"
+
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/task.h>
+
+#include <texteditor/fontsettings.h>
+#include <texteditor/texteditorsettings.h>
+
+#include <QRegularExpression>
+
+using namespace ProjectExplorer;
+
+namespace BareMetal {
+namespace Internal {
+
+// Helpers:
+
+static Task::TaskType taskType(const QString &msgType)
+{
+ if (msgType == "warning" || msgType == "Warning") {
+ return Task::TaskType::Warning;
+ } else if (msgType == "error" || msgType == "Error"
+ || msgType == "syntax error") {
+ return Task::TaskType::Error;
+ }
+ return Task::TaskType::Unknown;
+}
+
+// SdccParser
+
+SdccParser::SdccParser()
+{
+ setObjectName("SdccParser");
+}
+
+Core::Id SdccParser::id()
+{
+ return "BareMetal.OutputParser.Sdcc";
+}
+
+void SdccParser::newTask(const Task &task)
+{
+ doFlush();
+ m_lastTask = task;
+ m_lines = 1;
+}
+
+void SdccParser::amendDescription(const QString &desc)
+{
+ const int start = m_lastTask.description.count() + 1;
+ m_lastTask.description.append(QLatin1Char('\n'));
+ m_lastTask.description.append(desc);
+
+ QTextLayout::FormatRange fr;
+ fr.start = start;
+ fr.length = m_lastTask.description.count() + 1;
+ fr.format.setFont(TextEditor::TextEditorSettings::fontSettings().font());
+ fr.format.setFontStyleHint(QFont::Monospace);
+ m_lastTask.formats.append(fr);
+
+ ++m_lines;
+}
+
+void SdccParser::stdError(const QString &line)
+{
+ IOutputParser::stdError(line);
+
+ const QString lne = rightTrimmed(line);
+
+ QRegularExpression re;
+ QRegularExpressionMatch match;
+
+ re.setPattern("^(.+\\.\\S+):(\\d+): (warning|error) (\\d+): (.+)$");
+ match = re.match(lne);
+ if (match.hasMatch()) {
+ enum CaptureIndex { FilePathIndex = 1, LineNumberIndex,
+ MessageTypeIndex, MessageCodeIndex, MessageTextIndex };
+ const Utils::FilePath fileName = Utils::FilePath::fromUserInput(
+ match.captured(FilePathIndex));
+ const int lineno = match.captured(LineNumberIndex).toInt();
+ const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
+ const QString descr = match.captured(MessageTextIndex);
+ const Task task(type, descr, fileName, lineno, Constants::TASK_CATEGORY_COMPILE);
+ newTask(task);
+ return;
+ }
+
+ re.setPattern("^(.+\\.\\S+):(\\d+): (syntax error): (.+)$");
+ match = re.match(lne);
+ if (match.hasMatch()) {
+ enum CaptureIndex { FilePathIndex = 1, LineNumberIndex,
+ MessageTypeIndex, MessageTextIndex };
+ const Utils::FilePath fileName = Utils::FilePath::fromUserInput(
+ match.captured(FilePathIndex));
+ const int lineno = match.captured(LineNumberIndex).toInt();
+ const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
+ const QString descr = match.captured(MessageTextIndex);
+ const Task task(type, descr, fileName, lineno, Constants::TASK_CATEGORY_COMPILE);
+ newTask(task);
+ return;
+ }
+
+ re.setPattern("^at (\\d+): (error) \\d+: (.+)$");
+ match = re.match(lne);
+ if (match.hasMatch()) {
+ enum CaptureIndex { MessageCodeIndex = 1, MessageTypeIndex, MessageTextIndex };
+ const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
+ const QString descr = match.captured(MessageTextIndex);
+ const Task task(type, descr, {}, -1, Constants::TASK_CATEGORY_COMPILE);
+ newTask(task);
+ return;
+ }
+
+ re.setPattern("^\\?ASlink-(Warning|Error)-(.+)$");
+ match = re.match(lne);
+ if (match.hasMatch()) {
+ enum CaptureIndex { MessageTypeIndex = 1, MessageTextIndex };
+ const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
+ const QString descr = match.captured(MessageTextIndex);
+ const Task task(type, descr, {}, -1, Constants::TASK_CATEGORY_COMPILE);
+ newTask(task);
+ return;
+ }
+
+ if (!m_lastTask.isNull()) {
+ amendDescription(lne);
+ return;
+ }
+
+ doFlush();
+}
+
+void SdccParser::stdOutput(const QString &line)
+{
+ IOutputParser::stdOutput(line);
+}
+
+void SdccParser::doFlush()
+{
+ if (m_lastTask.isNull())
+ return;
+
+ Task t = m_lastTask;
+ m_lastTask.clear();
+ emit addTask(t, m_lines, 1);
+ m_lines = 0;
+}
+
+} // namespace Internal
+} // namespace BareMetal
+
+// Unit tests:
+
+#ifdef WITH_TESTS
+#include "baremetalplugin.h"
+#include <projectexplorer/outputparser_test.h>
+#include <QTest>
+
+namespace BareMetal {
+namespace Internal {
+
+void BareMetalPlugin::testSdccOutputParsers_data()
+{
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<OutputParserTester::Channel>("inputChannel");
+ QTest::addColumn<QString>("childStdOutLines");
+ QTest::addColumn<QString>("childStdErrLines");
+ QTest::addColumn<Tasks >("tasks");
+ QTest::addColumn<QString>("outputLines");
+
+ QTest::newRow("pass-through stdout")
+ << "Sometext" << OutputParserTester::STDOUT
+ << "Sometext\n" << QString()
+ << Tasks()
+ << QString();
+ QTest::newRow("pass-through stderr")
+ << "Sometext" << OutputParserTester::STDERR
+ << QString() << "Sometext\n"
+ << Tasks()
+ << QString();
+
+ const Core::Id categoryCompile = Constants::TASK_CATEGORY_COMPILE;
+
+ // Compiler messages.
+
+ QTest::newRow("Compiler single line warning")
+ << QString::fromLatin1("c:\\foo\\main.c:63: warning 123: Some warning")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("c:\\foo\\main.c:63: warning 123: Some warning\n")
+ << (Tasks() << Task(Task::Warning,
+ QLatin1String("Some warning"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\main.c")),
+ 63,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("Compiler multi line warning")
+ << QString::fromLatin1("c:\\foo\\main.c:63: warning 123: Some warning\n"
+ "details #1\n"
+ " details #2")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("c:\\foo\\main.c:63: warning 123: Some warning\n"
+ "details #1\n"
+ " details #2\n")
+ << (Tasks() << Task(Task::Warning,
+ QLatin1String("Some warning\n"
+ "details #1\n"
+ " details #2"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\main.c")),
+ 63,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("Compiler single line error")
+ << QString::fromLatin1("c:\\foo\\main.c:63: error 123: Some error")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("c:\\foo\\main.c:63: error 123: Some error\n")
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("Some error"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\main.c")),
+ 63,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("Compiler multi line error")
+ << QString::fromLatin1("c:\\foo\\main.c:63: error 123: Some error\n"
+ "details #1\n"
+ " details #2")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("c:\\foo\\main.c:63: error 123: Some error\n"
+ "details #1\n"
+ " details #2\n")
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("Some error\n"
+ "details #1\n"
+ " details #2"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\main.c")),
+ 63,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("Compiler syntax error")
+ << QString::fromLatin1("c:\\foo\\main.c:63: syntax error: Some error")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("c:\\foo\\main.c:63: syntax error: Some error\n")
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("Some error"),
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\foo\\main.c")),
+ 63,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("Compiler bad option error")
+ << QString::fromLatin1("at 1: error 123: Some error")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("at 1: error 123: Some error\n")
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("Some error"),
+ Utils::FilePath(),
+ -1,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("Linker warning")
+ << QString::fromLatin1("?ASlink-Warning-Couldn't find library 'foo.lib'")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("?ASlink-Warning-Couldn't find library 'foo.lib'\n")
+ << (Tasks() << Task(Task::Warning,
+ QLatin1String("Couldn't find library 'foo.lib'"),
+ Utils::FilePath(),
+ -1,
+ categoryCompile))
+ << QString();
+
+ QTest::newRow("Linker error")
+ << QString::fromLatin1("?ASlink-Error-<cannot open> : \"foo.rel\"")
+ << OutputParserTester::STDERR
+ << QString()
+ << QString::fromLatin1("?ASlink-Error-<cannot open> : \"foo.rel\"\n")
+ << (Tasks() << Task(Task::Error,
+ QLatin1String("<cannot open> : \"foo.rel\""),
+ Utils::FilePath(),
+ -1,
+ categoryCompile))
+ << QString();
+}
+
+void BareMetalPlugin::testSdccOutputParsers()
+{
+ OutputParserTester testbench;
+ testbench.appendOutputParser(new SdccParser);
+ QFETCH(QString, input);
+ QFETCH(OutputParserTester::Channel, inputChannel);
+ QFETCH(Tasks, tasks);
+ QFETCH(QString, childStdOutLines);
+ QFETCH(QString, childStdErrLines);
+ QFETCH(QString, outputLines);
+
+ testbench.testParsing(input, inputChannel,
+ tasks, childStdOutLines, childStdErrLines,
+ outputLines);
+}
+
+} // namespace Internal
+} // namespace BareMetal
+
+#endif // WITH_TESTS
diff --git a/src/plugins/baremetal/sdccparser.h b/src/plugins/baremetal/sdccparser.h
new file mode 100644
index 0000000000..fb7866c879
--- /dev/null
+++ b/src/plugins/baremetal/sdccparser.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** 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 <projectexplorer/ioutputparser.h>
+#include <projectexplorer/task.h>
+
+namespace BareMetal {
+namespace Internal {
+
+// SdccParser
+
+class SdccParser final : public ProjectExplorer::IOutputParser
+{
+ Q_OBJECT
+
+public:
+ explicit SdccParser();
+ static Core::Id id();
+
+private:
+ void newTask(const ProjectExplorer::Task &task);
+ void amendDescription(const QString &desc);
+
+ void stdError(const QString &line) final;
+ void stdOutput(const QString &line) final;
+ void doFlush() final;
+
+ ProjectExplorer::Task m_lastTask;
+ int m_lines = 0;
+};
+
+} // namespace Internal
+} // namespace BareMetal
diff --git a/src/plugins/baremetal/sdcctoolchain.cpp b/src/plugins/baremetal/sdcctoolchain.cpp
new file mode 100644
index 0000000000..b839a68fe8
--- /dev/null
+++ b/src/plugins/baremetal/sdcctoolchain.cpp
@@ -0,0 +1,564 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** 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 "sdccparser.h"
+#include "sdcctoolchain.h"
+
+#include <projectexplorer/abiwidget.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/projectmacro.h>
+#include <projectexplorer/toolchainmanager.h>
+
+#include <utils/algorithm.h>
+#include <utils/environment.h>
+#include <utils/pathchooser.h>
+#include <utils/qtcassert.h>
+#include <utils/synchronousprocess.h>
+
+#include <QDebug>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QFormLayout>
+#include <QLineEdit>
+#include <QPlainTextEdit>
+#include <QSettings>
+#include <QTemporaryFile>
+#include <QTextStream>
+
+using namespace ProjectExplorer;
+using namespace Utils;
+
+namespace BareMetal {
+namespace Internal {
+
+// Helpers:
+
+static const char compilerCommandKeyC[] = "BareMetal.SdccToolChain.CompilerPath";
+static const char targetAbiKeyC[] = "BareMetal.SdccToolChain.TargetAbi";
+
+static bool compilerExists(const FilePath &compilerPath)
+{
+ const QFileInfo fi = compilerPath.toFileInfo();
+ return fi.exists() && fi.isExecutable() && fi.isFile();
+}
+
+static QString compilerTargetFlag(const Abi &abi)
+{
+ switch (abi.architecture()) {
+ case Abi::Architecture::Mcs51Architecture:
+ return QString("-mmcs51");
+ default:
+ return {};
+ }
+}
+
+static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList &env,
+ const Abi &abi)
+{
+ if (compiler.isEmpty() || !compiler.toFileInfo().isExecutable())
+ return {};
+
+ QTemporaryFile fakeIn("XXXXXX.c");
+ if (!fakeIn.open())
+ return {};
+ fakeIn.close();
+
+ SynchronousProcess cpp;
+ cpp.setEnvironment(env);
+ cpp.setTimeoutS(10);
+
+ QStringList arguments;
+ arguments.push_back(compilerTargetFlag(abi));
+ arguments.push_back("-dM");
+ arguments.push_back("-E");
+ arguments.push_back(fakeIn.fileName());
+
+ const SynchronousProcessResponse response = cpp.runBlocking(compiler.toString(), arguments);
+ if (response.result != SynchronousProcessResponse::Finished
+ || response.exitCode != 0) {
+ qWarning() << response.exitMessage(compiler.toString(), 10);
+ return {};
+ }
+
+ const QByteArray output = response.allOutput().toUtf8();
+ return Macro::toMacros(output);
+}
+
+static HeaderPaths dumpHeaderPaths(const FilePath &compiler, const QStringList &env,
+ const Abi &abi)
+{
+ if (!compiler.exists())
+ return {};
+
+ SynchronousProcess cpp;
+ cpp.setEnvironment(env);
+ cpp.setTimeoutS(10);
+
+ QStringList arguments;
+ arguments.push_back(compilerTargetFlag(abi));
+ arguments.push_back("--print-search-dirs");
+
+ const SynchronousProcessResponse response = cpp.runBlocking(compiler.toString(), arguments);
+ if (response.result != SynchronousProcessResponse::Finished
+ || response.exitCode != 0) {
+ qWarning() << response.exitMessage(compiler.toString(), 10);
+ return {};
+ }
+
+ QString output = response.allOutput();
+ HeaderPaths headerPaths;
+ QTextStream in(&output);
+ QString line;
+ bool synchronized = false;
+ while (in.readLineInto(&line)) {
+ if (!synchronized) {
+ if (line.startsWith("includedir:"))
+ synchronized = true;
+ } else {
+ if (line.startsWith("programs:") || line.startsWith("datadir:")
+ || line.startsWith("libdir:") || line.startsWith("libpath:")) {
+ break;
+ } else {
+ const QString headerPath = QFileInfo(line.trimmed())
+ .canonicalFilePath();
+ headerPaths.append({headerPath, HeaderPathType::BuiltIn});
+ }
+ }
+ }
+ return headerPaths;
+}
+
+static QString findMacroValue(const Macros &macros, const QByteArray &key)
+{
+ for (const Macro &macro : macros) {
+ if (macro.key == key)
+ return QString::fromLocal8Bit(macro.value);
+ }
+ return {};
+}
+
+static QString guessVersion(const Macros &macros)
+{
+ const QString major = findMacroValue(macros, "__SDCC_VERSION_MAJOR");
+ const QString minor = findMacroValue(macros, "__SDCC_VERSION_MINOR");
+ const QString patch = findMacroValue(macros, "__SDCC_VERSION_PATCH");
+ return QString("%1.%2.%3").arg(major, minor, patch);
+}
+
+static Abi::Architecture guessArchitecture(const Macros &macros)
+{
+ for (const Macro &macro : macros) {
+ if (macro.key == "__SDCC_mcs51")
+ return Abi::Architecture::Mcs51Architecture;
+ }
+ return Abi::Architecture::UnknownArchitecture;
+}
+
+static unsigned char guessWordWidth(const Macros &macros)
+{
+ Q_UNUSED(macros)
+ // SDCC always have 16-bit word width.
+ return 16;
+}
+
+static Abi::BinaryFormat guessFormat(Abi::Architecture arch)
+{
+ Q_UNUSED(arch)
+ return Abi::BinaryFormat::UnknownFormat;
+}
+
+static Abi guessAbi(const Macros &macros)
+{
+ const auto arch = guessArchitecture(macros);
+ return {arch, Abi::OS::BareMetalOS, Abi::OSFlavor::GenericFlavor,
+ guessFormat(arch), guessWordWidth(macros)};
+}
+
+static QString buildDisplayName(Abi::Architecture arch, Core::Id language,
+ const QString &version)
+{
+ const auto archName = Abi::toString(arch);
+ const auto langName = ToolChainManager::displayNameOfLanguageId(language);
+ return SdccToolChain::tr("SDCC %1 (%2, %3)")
+ .arg(version, langName, archName);
+}
+
+static Utils::FilePath compilerPathFromEnvironment(const QString &compilerName)
+{
+ const Environment systemEnvironment = Environment::systemEnvironment();
+ return systemEnvironment.searchInPath(compilerName);
+}
+
+// SdccToolChain
+
+SdccToolChain::SdccToolChain() :
+ ToolChain(Constants::SDCC_TOOLCHAIN_TYPEID)
+{ }
+
+QString SdccToolChain::typeDisplayName() const
+{
+ return Internal::SdccToolChainFactory::tr("SDCC");
+}
+
+void SdccToolChain::setTargetAbi(const Abi &abi)
+{
+ if (abi == m_targetAbi)
+ return;
+ m_targetAbi = abi;
+ toolChainUpdated();
+}
+
+Abi SdccToolChain::targetAbi() const
+{
+ return m_targetAbi;
+}
+
+bool SdccToolChain::isValid() const
+{
+ return true;
+}
+
+ToolChain::MacroInspectionRunner SdccToolChain::createMacroInspectionRunner() const
+{
+ Environment env = Environment::systemEnvironment();
+ addToEnvironment(env);
+
+ const Utils::FilePath compilerCommand = m_compilerCommand;
+ const Core::Id lang = language();
+ const Abi abi = m_targetAbi;
+
+ MacrosCache macrosCache = predefinedMacrosCache();
+
+ return [env, compilerCommand, macrosCache, lang, abi]
+ (const QStringList &flags) {
+ Q_UNUSED(flags)
+
+ const Macros macros = dumpPredefinedMacros(compilerCommand, env.toStringList(),
+ abi);
+ const auto report = MacroInspectionReport{macros, languageVersion(lang, macros)};
+ macrosCache->insert({}, report);
+
+ return report;
+ };
+}
+
+Macros SdccToolChain::predefinedMacros(const QStringList &cxxflags) const
+{
+ return createMacroInspectionRunner()(cxxflags).macros;
+}
+
+Utils::LanguageExtensions SdccToolChain::languageExtensions(const QStringList &) const
+{
+ return LanguageExtension::None;
+}
+
+WarningFlags SdccToolChain::warningFlags(const QStringList &cxxflags) const
+{
+ Q_UNUSED(cxxflags);
+ return WarningFlags::Default;
+}
+
+ToolChain::BuiltInHeaderPathsRunner SdccToolChain::createBuiltInHeaderPathsRunner() const
+{
+ Environment env = Environment::systemEnvironment();
+ addToEnvironment(env);
+
+ const Utils::FilePath compilerCommand = m_compilerCommand;
+ const Core::Id languageId = language();
+ const Abi abi = m_targetAbi;
+
+ HeaderPathsCache headerPaths = headerPathsCache();
+
+ return [env, compilerCommand, headerPaths, languageId, abi](const QStringList &flags,
+ const QString &fileName,
+ const QString &) {
+ Q_UNUSED(flags)
+ Q_UNUSED(fileName)
+
+ const HeaderPaths paths = dumpHeaderPaths(compilerCommand, env.toStringList(), abi);
+ headerPaths->insert({}, paths);
+
+ return paths;
+ };
+}
+
+HeaderPaths SdccToolChain::builtInHeaderPaths(const QStringList &cxxFlags,
+ const FilePath &fileName) const
+{
+ return createBuiltInHeaderPathsRunner()(cxxFlags, fileName.toString(), "");
+}
+
+void SdccToolChain::addToEnvironment(Environment &env) const
+{
+ if (!m_compilerCommand.isEmpty()) {
+ const FilePath path = m_compilerCommand.parentDir();
+ env.prependOrSetPath(path.toString());
+ }
+}
+
+IOutputParser *SdccToolChain::outputParser() const
+{
+ return new SdccParser;
+}
+
+QVariantMap SdccToolChain::toMap() const
+{
+ QVariantMap data = ToolChain::toMap();
+ data.insert(compilerCommandKeyC, m_compilerCommand.toString());
+ data.insert(targetAbiKeyC, m_targetAbi.toString());
+ return data;
+}
+
+bool SdccToolChain::fromMap(const QVariantMap &data)
+{
+ if (!ToolChain::fromMap(data))
+ return false;
+ m_compilerCommand = FilePath::fromString(data.value(compilerCommandKeyC).toString());
+ m_targetAbi = Abi::fromString(data.value(targetAbiKeyC).toString());
+ return true;
+}
+
+std::unique_ptr<ToolChainConfigWidget> SdccToolChain::createConfigurationWidget()
+{
+ return std::make_unique<SdccToolChainConfigWidget>(this);
+}
+
+bool SdccToolChain::operator==(const ToolChain &other) const
+{
+ if (!ToolChain::operator==(other))
+ return false;
+
+ const auto customTc = static_cast<const SdccToolChain *>(&other);
+ return m_compilerCommand == customTc->m_compilerCommand
+ && m_targetAbi == customTc->m_targetAbi
+ ;
+}
+
+void SdccToolChain::setCompilerCommand(const FilePath &file)
+{
+ if (file == m_compilerCommand)
+ return;
+ m_compilerCommand = file;
+ toolChainUpdated();
+}
+
+FilePath SdccToolChain::compilerCommand() const
+{
+ return m_compilerCommand;
+}
+
+FilePath SdccToolChain::makeCommand(const Environment &env) const
+{
+ Q_UNUSED(env)
+ return {};
+}
+
+// SdccToolChainFactory
+
+SdccToolChainFactory::SdccToolChainFactory()
+{
+ setDisplayName(tr("SDCC"));
+ setSupportedToolChainType(Constants::SDCC_TOOLCHAIN_TYPEID);
+ setSupportedLanguages({ProjectExplorer::Constants::C_LANGUAGE_ID});
+ setToolchainConstructor([] { return new SdccToolChain; });
+ setUserCreatable(true);
+}
+
+QList<ToolChain *> SdccToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
+{
+ Candidates candidates;
+
+ if (Utils::HostOsInfo::isWindowsHost()) {
+
+#ifdef Q_OS_WIN64
+ static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\SDCC";
+#else
+ static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\SDCC";
+#endif
+
+ QSettings registry(kRegistryNode, QSettings::NativeFormat);
+ QString compilerPath = registry.value("Default").toString();
+ if (!compilerPath.isEmpty()) {
+ // Build full compiler path.
+ compilerPath += "\\bin\\sdcc.exe";
+ const FilePath fn = FilePath::fromString(
+ QFileInfo(compilerPath).absoluteFilePath());
+ if (compilerExists(fn)) {
+ // Build compiler version.
+ const QString version = QString("%1.%2.%3").arg(
+ registry.value("VersionMajor").toString(),
+ registry.value("VersionMinor").toString(),
+ registry.value("VersionRevision").toString());
+ candidates.push_back({fn, version});
+ }
+ }
+ }
+
+ const FilePath fn = compilerPathFromEnvironment("sdcc");
+ if (fn.exists()) {
+ const auto env = Environment::systemEnvironment();
+ const auto macros = dumpPredefinedMacros(fn, env.toStringList(), {});
+ const QString version = guessVersion(macros);
+ const Candidate candidate = {fn, version};
+ if (!candidates.contains(candidate))
+ candidates.push_back(candidate);
+ }
+
+ return autoDetectToolchains(candidates, alreadyKnown);
+}
+
+QList<ToolChain *> SdccToolChainFactory::autoDetectToolchains(
+ const Candidates &candidates, const QList<ToolChain *> &alreadyKnown) const
+{
+ QList<ToolChain *> result;
+
+ for (const Candidate &candidate : qAsConst(candidates)) {
+ const QList<ToolChain *> filtered = Utils::filtered(
+ alreadyKnown, [candidate](ToolChain *tc) {
+ return tc->typeId() == Constants::SDCC_TOOLCHAIN_TYPEID
+ && tc->compilerCommand() == candidate.compilerPath
+ && (tc->language() == ProjectExplorer::Constants::C_LANGUAGE_ID);
+ });
+
+ if (!filtered.isEmpty()) {
+ result << filtered;
+ continue;
+ }
+
+ // Create toolchain only for C language (because SDCC does not support C++).
+ result << autoDetectToolchain(candidate, ProjectExplorer::Constants::C_LANGUAGE_ID);
+ }
+
+ return result;
+}
+
+QList<ToolChain *> SdccToolChainFactory::autoDetectToolchain(
+ const Candidate &candidate, Core::Id language) const
+{
+ const auto env = Environment::systemEnvironment();
+ const Macros macros = dumpPredefinedMacros(candidate.compilerPath, env.toStringList(), {});
+ if (macros.isEmpty())
+ return {};
+ const Abi abi = guessAbi(macros);
+
+ const auto tc = new SdccToolChain;
+ tc->setDetection(ToolChain::AutoDetection);
+ tc->setLanguage(language);
+ tc->setCompilerCommand(candidate.compilerPath);
+ tc->setTargetAbi(abi);
+ tc->setDisplayName(buildDisplayName(abi.architecture(), language, candidate.compilerVersion));
+
+ const auto languageVersion = ToolChain::languageVersion(language, macros);
+ tc->predefinedMacrosCache()->insert({}, {macros, languageVersion});
+ return {tc};
+}
+
+// SdccToolChainConfigWidget
+
+SdccToolChainConfigWidget::SdccToolChainConfigWidget(SdccToolChain *tc) :
+ ToolChainConfigWidget(tc),
+ m_compilerCommand(new PathChooser),
+ m_abiWidget(new AbiWidget)
+{
+ m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand);
+ m_compilerCommand->setHistoryCompleter("PE.SDCC.Command.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, &SdccToolChainConfigWidget::handleCompilerCommandChange);
+ connect(m_abiWidget, &AbiWidget::abiChanged,
+ this, &ToolChainConfigWidget::dirty);
+}
+
+void SdccToolChainConfigWidget::applyImpl()
+{
+ if (toolChain()->isAutoDetected())
+ return;
+
+ const auto tc = static_cast<SdccToolChain *>(toolChain());
+ 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->predefinedMacrosCache()->insert({}, {m_macros, languageVersion});
+
+ setFromToolchain();
+}
+
+bool SdccToolChainConfigWidget::isDirtyImpl() const
+{
+ const auto tc = static_cast<SdccToolChain *>(toolChain());
+ return m_compilerCommand->fileName() != tc->compilerCommand()
+ || m_abiWidget->currentAbi() != tc->targetAbi()
+ ;
+}
+
+void SdccToolChainConfigWidget::makeReadOnlyImpl()
+{
+ m_compilerCommand->setReadOnly(true);
+ m_abiWidget->setEnabled(false);
+}
+
+void SdccToolChainConfigWidget::setFromToolchain()
+{
+ const QSignalBlocker blocker(this);
+ const auto tc = static_cast<SdccToolChain *>(toolChain());
+ m_compilerCommand->setFileName(tc->compilerCommand());
+ m_abiWidget->setAbis({}, tc->targetAbi());
+ const bool haveCompiler = compilerExists(m_compilerCommand->fileName());
+ m_abiWidget->setEnabled(haveCompiler && !tc->isAutoDetected());
+}
+
+void SdccToolChainConfigWidget::handleCompilerCommandChange()
+{
+ const FilePath compilerPath = m_compilerCommand->fileName();
+ const bool haveCompiler = compilerExists(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/sdcctoolchain.h b/src/plugins/baremetal/sdcctoolchain.h
new file mode 100644
index 0000000000..15ed599524
--- /dev/null
+++ b/src/plugins/baremetal/sdcctoolchain.h
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** 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 <projectexplorer/abi.h>
+#include <projectexplorer/toolchain.h>
+#include <projectexplorer/toolchainconfigwidget.h>
+
+QT_BEGIN_NAMESPACE
+class QPlainTextEdit;
+class QPushButton;
+class QTextEdit;
+QT_END_NAMESPACE
+
+namespace Utils {
+class FilePath;
+class PathChooser;
+}
+
+namespace ProjectExplorer { class AbiWidget; }
+
+namespace BareMetal {
+namespace Internal {
+
+// SdccToolChain
+
+class SdccToolChain final : public ProjectExplorer::ToolChain
+{
+ Q_DECLARE_TR_FUNCTIONS(SdccToolChain)
+
+public:
+ QString typeDisplayName() const final;
+
+ void setTargetAbi(const ProjectExplorer::Abi &abi);
+ ProjectExplorer::Abi targetAbi() const final;
+
+ bool isValid() const final;
+
+ MacroInspectionRunner createMacroInspectionRunner() const final;
+ ProjectExplorer::Macros predefinedMacros(const QStringList &cxxflags) const final;
+
+ Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const final;
+ ProjectExplorer::WarningFlags warningFlags(const QStringList &cxxflags) const final;
+
+ BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner() const final;
+ ProjectExplorer::HeaderPaths builtInHeaderPaths(const QStringList &cxxFlags,
+ const Utils::FilePath &) const final;
+ void addToEnvironment(Utils::Environment &env) const final;
+ ProjectExplorer::IOutputParser *outputParser() const final;
+
+ QVariantMap toMap() const final;
+ bool fromMap(const QVariantMap &data) final;
+
+ std::unique_ptr<ProjectExplorer::ToolChainConfigWidget> createConfigurationWidget() final;
+
+ bool operator ==(const ToolChain &other) const final;
+
+ void setCompilerCommand(const Utils::FilePath &file);
+ Utils::FilePath compilerCommand() const final;
+
+ Utils::FilePath makeCommand(const Utils::Environment &env) const final;
+
+private:
+ SdccToolChain();
+
+ ProjectExplorer::Abi m_targetAbi;
+ Utils::FilePath m_compilerCommand;
+
+ friend class SdccToolChainFactory;
+ friend class SdccToolChainConfigWidget;
+};
+
+// SdccToolChainFactory
+
+class SdccToolChainFactory final : public ProjectExplorer::ToolChainFactory
+{
+ Q_OBJECT
+
+public:
+ SdccToolChainFactory();
+
+ QList<ProjectExplorer::ToolChain *> autoDetect(
+ const QList<ProjectExplorer::ToolChain *> &alreadyKnown) final;
+
+private:
+ QList<ProjectExplorer::ToolChain *> autoDetectToolchains(const Candidates &candidates,
+ const QList<ProjectExplorer::ToolChain *> &alreadyKnown) const;
+ QList<ProjectExplorer::ToolChain *> autoDetectToolchain(
+ const Candidate &candidate, Core::Id language) const;
+};
+
+// SdccToolChainConfigWidget
+
+class SdccToolChainConfigWidget final : public ProjectExplorer::ToolChainConfigWidget
+{
+ Q_OBJECT
+
+public:
+ explicit SdccToolChainConfigWidget(SdccToolChain *tc);
+
+private:
+ void applyImpl() final;
+ void discardImpl() final { setFromToolchain(); }
+ bool isDirtyImpl() const final;
+ void makeReadOnlyImpl() final;
+
+ 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/baremetal/stlinkutilgdbserverprovider.cpp b/src/plugins/baremetal/stlinkutilgdbserverprovider.cpp
index 146f826e26..552f890c80 100644
--- a/src/plugins/baremetal/stlinkutilgdbserverprovider.cpp
+++ b/src/plugins/baremetal/stlinkutilgdbserverprovider.cpp
@@ -23,25 +23,26 @@
**
****************************************************************************/
-#include "stlinkutilgdbserverprovider.h"
#include "baremetalconstants.h"
+
#include "gdbserverprovidermanager.h"
+#include "stlinkutilgdbserverprovider.h"
+#include <utils/fileutils.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
-#include <utils/fileutils.h>
#include <coreplugin/variablechooser.h>
-#include <QString>
+#include <QCheckBox>
+#include <QComboBox>
#include <QFileInfo>
-
#include <QFormLayout>
#include <QLineEdit>
-#include <QComboBox>
-#include <QSpinBox>
-#include <QCheckBox>
#include <QPlainTextEdit>
+#include <QSpinBox>
+
+using namespace Utils;
namespace BareMetal {
namespace Internal {
@@ -54,15 +55,10 @@ const char extendedModeKeyC[] = "BareMetal.StLinkUtilGdbServerProvider.ExtendedM
const char resetBoardKeyC[] = "BareMetal.StLinkUtilGdbServerProvider.ResetBoard";
const char transportLayerKeyC[] = "BareMetal.StLinkUtilGdbServerProvider.TransportLayer";
+// StLinkUtilGdbServerProvider
+
StLinkUtilGdbServerProvider::StLinkUtilGdbServerProvider()
: GdbServerProvider(QLatin1String(Constants::STLINK_UTIL_PROVIDER_ID))
- , m_host(QLatin1String("localhost"))
- , m_port(4242)
- , m_executableFile(QLatin1String("st-util"))
- , m_verboseLevel(0)
- , m_extendedMode(false)
- , m_resetBoard(true)
- , m_transport(RawUsb)
{
setInitCommands(defaultInitCommands());
setResetCommands(defaultResetCommands());
@@ -88,7 +84,7 @@ QString StLinkUtilGdbServerProvider::defaultInitCommands()
QString StLinkUtilGdbServerProvider::defaultResetCommands()
{
- return QLatin1String("");
+ return {};
}
QString StLinkUtilGdbServerProvider::typeDisplayName() const
@@ -106,32 +102,27 @@ QString StLinkUtilGdbServerProvider::channel() const
return m_host + QLatin1Char(':') + QString::number(m_port);
case StartupOnPipe:
// Unsupported mode
- return QString();
+ return {};
default: // wrong
- return QString();
+ return {};
}
}
-QString StLinkUtilGdbServerProvider::executable() const
-{
- return m_executableFile;
-}
-
-QStringList StLinkUtilGdbServerProvider::arguments() const
+CommandLine StLinkUtilGdbServerProvider::command() const
{
- QStringList args;
+ CommandLine cmd{m_executableFile, {}};
if (m_extendedMode)
- args << QLatin1String("--multi");
+ cmd.addArg("--multi");
if (!m_resetBoard)
- args << QLatin1String("--no-reset");
+ cmd.addArg("--no-reset");
- args << (QLatin1String("--stlink_version=") + QString::number(m_transport));
- args << (QLatin1String("--listen_port=") + QString::number(m_port));
- args << (QLatin1String("--verbose=") + QString::number(m_verboseLevel));
+ cmd.addArg("--stlink_version=" + QString::number(m_transport));
+ cmd.addArg("--listen_port=" + QString::number(m_port));
+ cmd.addArg("--verbose=" + QString::number(m_verboseLevel));
- return args;
+ return cmd;
}
bool StLinkUtilGdbServerProvider::canStartupMode(StartupMode m) const
@@ -169,7 +160,7 @@ QVariantMap StLinkUtilGdbServerProvider::toMap() const
QVariantMap data = GdbServerProvider::toMap();
data.insert(QLatin1String(hostKeyC), m_host);
data.insert(QLatin1String(portKeyC), m_port);
- data.insert(QLatin1String(executableFileKeyC), m_executableFile);
+ data.insert(QLatin1String(executableFileKeyC), m_executableFile.toVariant());
data.insert(QLatin1String(verboseLevelKeyC), m_verboseLevel);
data.insert(QLatin1String(extendedModeKeyC), m_extendedMode);
data.insert(QLatin1String(resetBoardKeyC), m_resetBoard);
@@ -184,7 +175,7 @@ bool StLinkUtilGdbServerProvider::fromMap(const QVariantMap &data)
m_host = data.value(QLatin1String(hostKeyC)).toString();
m_port = data.value(QLatin1String(portKeyC)).toInt();
- m_executableFile = data.value(QLatin1String(executableFileKeyC)).toString();
+ m_executableFile = FileName::fromVariant(data.value(QLatin1String(executableFileKeyC)));
m_verboseLevel = data.value(QLatin1String(verboseLevelKeyC)).toInt();
m_extendedMode = data.value(QLatin1String(extendedModeKeyC)).toBool();
m_resetBoard = data.value(QLatin1String(resetBoardKeyC)).toBool();
@@ -213,6 +204,8 @@ GdbServerProviderConfigWidget *StLinkUtilGdbServerProvider::configurationWidget(
return new StLinkUtilGdbServerProviderConfigWidget(this);
}
+// StLinkUtilGdbServerProviderFactory
+
StLinkUtilGdbServerProviderFactory::StLinkUtilGdbServerProviderFactory()
{
setId(QLatin1String(Constants::STLINK_UTIL_PROVIDER_ID));
@@ -233,14 +226,16 @@ bool StLinkUtilGdbServerProviderFactory::canRestore(const QVariantMap &data) con
GdbServerProvider *StLinkUtilGdbServerProviderFactory::restore(const QVariantMap &data)
{
- auto p = new StLinkUtilGdbServerProvider;
- auto updated = data;
+ const auto p = new StLinkUtilGdbServerProvider;
+ const auto updated = data;
if (p->fromMap(updated))
return p;
delete p;
return nullptr;
}
+// StLinkUtilGdbServerProviderConfigWidget
+
StLinkUtilGdbServerProviderConfigWidget::StLinkUtilGdbServerProviderConfigWidget(
StLinkUtilGdbServerProvider *p)
: GdbServerProviderConfigWidget(p)
@@ -283,7 +278,7 @@ StLinkUtilGdbServerProviderConfigWidget::StLinkUtilGdbServerProviderConfigWidget
addErrorLabel();
setFromProvider();
- auto chooser = new Core::VariableChooser(this);
+ const auto chooser = new Core::VariableChooser(this);
chooser->addSupportedWidget(m_initCommandsTextEdit);
chooser->addSupportedWidget(m_resetCommandsTextEdit);
@@ -293,14 +288,14 @@ StLinkUtilGdbServerProviderConfigWidget::StLinkUtilGdbServerProviderConfigWidget
this, &GdbServerProviderConfigWidget::dirty);
connect(m_verboseLevelSpinBox,
- static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged),
+ QOverload<int>::of(&QSpinBox::valueChanged),
this, &GdbServerProviderConfigWidget::dirty);
connect(m_extendedModeCheckBox, &QAbstractButton::clicked,
this, &GdbServerProviderConfigWidget::dirty);
connect(m_resetBoardCheckBox, &QAbstractButton::clicked,
this, &GdbServerProviderConfigWidget::dirty);
connect(m_transportLayerComboBox,
- static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &GdbServerProviderConfigWidget::dirty);
connect(m_initCommandsTextEdit, &QPlainTextEdit::textChanged,
@@ -309,11 +304,10 @@ StLinkUtilGdbServerProviderConfigWidget::StLinkUtilGdbServerProviderConfigWidget
this, &GdbServerProviderConfigWidget::dirty);
connect(m_startupModeComboBox,
- static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &StLinkUtilGdbServerProviderConfigWidget::startupModeChanged);
}
-
void StLinkUtilGdbServerProviderConfigWidget::startupModeChanged()
{
const GdbServerProvider::StartupMode m = startupMode();
@@ -332,12 +326,12 @@ void StLinkUtilGdbServerProviderConfigWidget::startupModeChanged()
void StLinkUtilGdbServerProviderConfigWidget::applyImpl()
{
- auto p = static_cast<StLinkUtilGdbServerProvider *>(provider());
+ const auto p = static_cast<StLinkUtilGdbServerProvider *>(provider());
Q_ASSERT(p);
p->m_host = m_hostWidget->host();
p->m_port = m_hostWidget->port();
- p->m_executableFile = m_executableFileChooser->fileName().toString();
+ p->m_executableFile = m_executableFileChooser->fileName();
p->m_verboseLevel = m_verboseLevelSpinBox->value();
p->m_extendedMode = m_extendedModeCheckBox->isChecked();
p->m_resetBoard = m_resetBoardCheckBox->isChecked();
@@ -391,11 +385,11 @@ void StLinkUtilGdbServerProviderConfigWidget::setFromProvider()
const auto p = static_cast<StLinkUtilGdbServerProvider *>(provider());
Q_ASSERT(p);
- QSignalBlocker blocker(this);
+ const QSignalBlocker blocker(this);
startupModeChanged();
m_hostWidget->setHost(p->m_host);
m_hostWidget->setPort(p->m_port);
- m_executableFileChooser->setFileName(Utils::FileName::fromString(p->m_executableFile));
+ m_executableFileChooser->setFileName(p->m_executableFile);
m_verboseLevelSpinBox->setValue(p->m_verboseLevel);
m_extendedModeCheckBox->setChecked(p->m_extendedMode);
m_resetBoardCheckBox->setChecked(p->m_resetBoard);
diff --git a/src/plugins/baremetal/stlinkutilgdbserverprovider.h b/src/plugins/baremetal/stlinkutilgdbserverprovider.h
index 900e408028..18b75ad405 100644
--- a/src/plugins/baremetal/stlinkutilgdbserverprovider.h
+++ b/src/plugins/baremetal/stlinkutilgdbserverprovider.h
@@ -39,7 +39,9 @@ namespace Internal {
class StLinkUtilGdbServerProviderConfigWidget;
class StLinkUtilGdbServerProviderFactory;
-class StLinkUtilGdbServerProvider : public GdbServerProvider
+// StLinkUtilGdbServerProvider
+
+class StLinkUtilGdbServerProvider final : public GdbServerProvider
{
public:
enum TransportLayer { ScsiOverUsb = 1, RawUsb = 2 };
@@ -54,8 +56,7 @@ public:
GdbServerProvider *clone() const final;
QString channel() const final;
- QString executable() const final;
- QStringList arguments() const final;
+ Utils::CommandLine command() const final;
bool canStartupMode(StartupMode mode) const final;
bool isValid() const final;
@@ -67,19 +68,21 @@ private:
static QString defaultInitCommands();
static QString defaultResetCommands();
- QString m_host;
- quint16 m_port;
- QString m_executableFile;
- int m_verboseLevel; // 0..99
- bool m_extendedMode; // Listening for connections after disconnect
- bool m_resetBoard;
- TransportLayer m_transport;
+ QString m_host = QLatin1String("localhost");
+ quint16 m_port = 4242;
+ Utils::FilePath m_executableFile = Utils::FilePath::fromString("st-util");
+ int m_verboseLevel = 0; // 0..99
+ bool m_extendedMode = false; // Listening for connections after disconnect
+ bool m_resetBoard = true;
+ TransportLayer m_transport = RawUsb;
friend class StLinkUtilGdbServerProviderConfigWidget;
friend class StLinkUtilGdbServerProviderFactory;
};
-class StLinkUtilGdbServerProviderFactory : public GdbServerProviderFactory
+// StLinkUtilGdbServerProviderFactory
+
+class StLinkUtilGdbServerProviderFactory final : public GdbServerProviderFactory
{
Q_OBJECT
@@ -94,7 +97,10 @@ public:
GdbServerProviderConfigWidget *configurationWidget(GdbServerProvider *);
};
-class StLinkUtilGdbServerProviderConfigWidget : public GdbServerProviderConfigWidget
+// StLinkUtilGdbServerProviderConfigWidget
+
+class StLinkUtilGdbServerProviderConfigWidget final
+ : public GdbServerProviderConfigWidget
{
Q_OBJECT
@@ -114,14 +120,14 @@ private:
void populateTransportLayers();
void setFromProvider();
- HostWidget *m_hostWidget;
- Utils::PathChooser *m_executableFileChooser;
- QSpinBox *m_verboseLevelSpinBox;
- QCheckBox *m_extendedModeCheckBox;
- QCheckBox *m_resetBoardCheckBox;
- QComboBox *m_transportLayerComboBox;
- QPlainTextEdit *m_initCommandsTextEdit;
- QPlainTextEdit *m_resetCommandsTextEdit;
+ HostWidget *m_hostWidget = nullptr;
+ Utils::PathChooser *m_executableFileChooser = nullptr;
+ QSpinBox *m_verboseLevelSpinBox = nullptr;
+ QCheckBox *m_extendedModeCheckBox = nullptr;
+ QCheckBox *m_resetBoardCheckBox = nullptr;
+ QComboBox *m_transportLayerComboBox = nullptr;
+ QPlainTextEdit *m_initCommandsTextEdit = nullptr;
+ QPlainTextEdit *m_resetCommandsTextEdit = nullptr;
};
} // namespace Internal