diff options
Diffstat (limited to 'src/plugins/baremetal')
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 ¯os) +{ + for (const Macro ¯o : macros) { + if (macro.key == "__ICCARM__") + return Abi::Architecture::ArmArchitecture; + if (macro.key == "__ICC8051__") + return Abi::Architecture::Mcs51Architecture; + if (macro.key == "__ICCAVR__") + return Abi::Architecture::AvrArchitecture; + } + return Abi::Architecture::UnknownArchitecture; +} + +static unsigned char guessWordWidth(const Macros ¯os) +{ + const Macro sizeMacro = Utils::findOrDefault(macros, [](const Macro &m) { + return m.key == "__INT_SIZE__"; + }); + if (sizeMacro.isValid() && sizeMacro.type == MacroType::Define) + return sizeMacro.value.toInt() * 8; + return 0; +} + +static Abi::BinaryFormat guessFormat(Abi::Architecture arch) +{ + if (arch == Abi::Architecture::ArmArchitecture) + return Abi::BinaryFormat::ElfFormat; + if (arch == Abi::Architecture::Mcs51Architecture + || arch == Abi::Architecture::AvrArchitecture) { + return Abi::BinaryFormat::UbrofFormat; + } + return Abi::BinaryFormat::UnknownFormat; +} + +static Abi guessAbi(const Macros ¯os) +{ + const auto arch = guessArchitecture(macros); + return {arch, Abi::OS::BareMetalOS, Abi::OSFlavor::GenericFlavor, + guessFormat(arch), guessWordWidth(macros)}; +} + +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 ¯os) +{ + for (const Macro ¯o : 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 ¯os, 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 ¯os) +{ + 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 ¯os, const QByteArray &key) +{ + for (const Macro ¯o : macros) { + if (macro.key == key) + return QString::fromLocal8Bit(macro.value); + } + return {}; +} + +static QString guessVersion(const Macros ¯os) +{ + 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 ¯os) +{ + for (const Macro ¯o : macros) { + if (macro.key == "__SDCC_mcs51") + return Abi::Architecture::Mcs51Architecture; + } + return Abi::Architecture::UnknownArchitecture; +} + +static unsigned char guessWordWidth(const Macros ¯os) +{ + 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 ¯os) +{ + 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 |