From 071f99875ef572922961b328441e915384d7d4d7 Mon Sep 17 00:00:00 2001 From: Denis Shienkov Date: Mon, 18 May 2020 19:03:55 +0300 Subject: [PATCH] BareMetal: Tune Keil ARM compiler using 'platform codegen flags' feature Previously, to generate macros, we always passed by default one target CPU as 'cortex-m0'. Right now we have added the new text field in the Keil compiler settings page, called "Platform codegen flags". In this field we can specify the desired CPU target flags. A new auto-or-manual created compiler still has the '--cpu=cortex-m0' flag as before. The user can modify this flag for a manually added compiler. Also, the deprecated '-cpu' syntax replaced with the actual '--cpu' syntax. Change-Id: I25fb3e28460606b98ea56f1f30fe8563306a8736 Reviewed-by: hjk --- src/plugins/baremetal/keiltoolchain.cpp | 93 ++++++++++++++++++++++--- src/plugins/baremetal/keiltoolchain.h | 8 +++ 2 files changed, 93 insertions(+), 8 deletions(-) diff --git a/src/plugins/baremetal/keiltoolchain.cpp b/src/plugins/baremetal/keiltoolchain.cpp index fc94639367d..1a13d47fd4c 100644 --- a/src/plugins/baremetal/keiltoolchain.cpp +++ b/src/plugins/baremetal/keiltoolchain.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -276,13 +277,16 @@ static Macros dumpC166PredefinedMacros(const FilePath &compiler, const QStringLi return macros; } -static Macros dumpArmPredefinedMacros(const FilePath &compiler, const QStringList &env) +static Macros dumpArmPredefinedMacros(const FilePath &compiler, const QStringList &extraArgs, const QStringList &env) { SynchronousProcess cpp; cpp.setEnvironment(env); cpp.setTimeoutS(10); - const CommandLine cmd(compiler, {"-E", "--list-macros", "-cpu=cortex-m0"}); + QStringList args = extraArgs; + args.push_back("-E"); + args.push_back("--list-macros"); + const CommandLine cmd(compiler, args); const SynchronousProcessResponse response = cpp.runBlocking(cmd); if (response.result != SynchronousProcessResponse::Finished @@ -311,7 +315,7 @@ static bool isArmArchitecture(Abi::Architecture arch) return arch == Abi::Architecture::ArmArchitecture; } -static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList &env) +static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList &args, const QStringList &env) { if (compiler.isEmpty() || !compiler.toFileInfo().isExecutable()) return {}; @@ -322,7 +326,7 @@ static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList & if (isC166Architecture(arch)) return dumpC166PredefinedMacros(compiler, env); if (isArmArchitecture(arch)) - return dumpArmPredefinedMacros(compiler, env); + return dumpArmPredefinedMacros(compiler, args, env); return {}; } @@ -408,6 +412,20 @@ static QString buildDisplayName(Abi::Architecture arch, Core::Id language, .arg(version, langName, archName); } +static void addDefaultCpuArgs(const FilePath &compiler, QStringList &extraArgs) +{ + const Abi::Architecture arch = guessArchitecture(compiler); + if (!isArmArchitecture(arch)) + return; + + const auto extraArgsIt = std::find_if(std::begin(extraArgs), std::end(extraArgs), + [](const QString &extraArg) { + return extraArg.contains("-cpu") || extraArg.contains("--cpu"); + }); + if (extraArgsIt == std::end(extraArgs)) + extraArgs.push_back("--cpu=cortex-m0"); +} + // KeilToolchain KeilToolChain::KeilToolChain() : @@ -443,12 +461,13 @@ ToolChain::MacroInspectionRunner KeilToolChain::createMacroInspectionRunner() co const Core::Id lang = language(); MacrosCache macroCache = predefinedMacrosCache(); + const QStringList extraArgs = m_extraCodeModelFlags; - return [env, compilerCommand, macroCache, lang] + return [env, compilerCommand, extraArgs, macroCache, lang] (const QStringList &flags) { Q_UNUSED(flags) - const Macros macros = dumpPredefinedMacros(compilerCommand, env.toStringList()); + const Macros macros = dumpPredefinedMacros(compilerCommand, extraArgs, env.toStringList()); const auto report = MacroInspectionReport{macros, languageVersion(lang, macros)}; macroCache->insert({}, report); @@ -541,6 +560,7 @@ bool KeilToolChain::operator ==(const ToolChain &other) const const auto customTc = static_cast(&other); return m_compilerCommand == customTc->m_compilerCommand && m_targetAbi == customTc->m_targetAbi + && m_extraCodeModelFlags == customTc->m_extraCodeModelFlags ; } @@ -557,6 +577,19 @@ FilePath KeilToolChain::compilerCommand() const return m_compilerCommand; } +void KeilToolChain::setExtraCodeModelFlags(const QStringList &flags) +{ + if (flags == m_extraCodeModelFlags) + return; + m_extraCodeModelFlags = flags; + toolChainUpdated(); +} + +QStringList KeilToolChain::extraCodeModelFlags() const +{ + return m_extraCodeModelFlags; +} + FilePath KeilToolChain::makeCommand(const Environment &env) const { Q_UNUSED(env) @@ -701,7 +734,10 @@ QList KeilToolChainFactory::autoDetectToolchain( const Candidate &candidate, Core::Id language) const { const auto env = Environment::systemEnvironment(); - const Macros macros = dumpPredefinedMacros(candidate.compilerPath, env.toStringList()); + + QStringList extraArgs; + addDefaultCpuArgs(candidate.compilerPath, extraArgs); + const Macros macros = dumpPredefinedMacros(candidate.compilerPath, extraArgs, env.toStringList()); if (macros.isEmpty()) return {}; @@ -717,6 +753,7 @@ QList KeilToolChainFactory::autoDetectToolchain( tc->setDetection(ToolChain::AutoDetection); tc->setLanguage(language); tc->setCompilerCommand(candidate.compilerPath); + tc->setExtraCodeModelFlags(extraArgs); tc->setTargetAbi(abi); tc->setDisplayName(buildDisplayName(abi.architecture(), language, candidate.compilerVersion)); @@ -735,6 +772,9 @@ KeilToolChainConfigWidget::KeilToolChainConfigWidget(KeilToolChain *tc) : m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand); m_compilerCommand->setHistoryCompleter("PE.KEIL.Command.History"); m_mainLayout->addRow(tr("&Compiler path:"), m_compilerCommand); + m_platformCodeGenFlagsLineEdit = new QLineEdit(this); + m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(tc->extraCodeModelFlags())); + m_mainLayout->addRow(tr("Platform codegen flags:"), m_platformCodeGenFlagsLineEdit); m_mainLayout->addRow(tr("&ABI:"), m_abiWidget); m_abiWidget->setEnabled(false); @@ -744,6 +784,8 @@ KeilToolChainConfigWidget::KeilToolChainConfigWidget(KeilToolChain *tc) : connect(m_compilerCommand, &PathChooser::rawPathChanged, this, &KeilToolChainConfigWidget::handleCompilerCommandChange); + connect(m_platformCodeGenFlagsLineEdit, &QLineEdit::editingFinished, + this, &KeilToolChainConfigWidget::handlePlatformCodeGenFlagsChange); connect(m_abiWidget, &AbiWidget::abiChanged, this, &ToolChainConfigWidget::dirty); } @@ -756,6 +798,7 @@ void KeilToolChainConfigWidget::applyImpl() const auto tc = static_cast(toolChain()); const QString displayName = tc->displayName(); tc->setCompilerCommand(m_compilerCommand->filePath()); + tc->setExtraCodeModelFlags(splitString(m_platformCodeGenFlagsLineEdit->text())); tc->setTargetAbi(m_abiWidget->currentAbi()); tc->setDisplayName(displayName); @@ -772,6 +815,7 @@ bool KeilToolChainConfigWidget::isDirtyImpl() const { const auto tc = static_cast(toolChain()); return m_compilerCommand->filePath() != tc->compilerCommand() + || m_platformCodeGenFlagsLineEdit->text() != QtcProcess::joinArgs(tc->extraCodeModelFlags()) || m_abiWidget->currentAbi() != tc->targetAbi() ; } @@ -779,6 +823,7 @@ bool KeilToolChainConfigWidget::isDirtyImpl() const void KeilToolChainConfigWidget::makeReadOnlyImpl() { m_compilerCommand->setReadOnly(true); + m_platformCodeGenFlagsLineEdit->setEnabled(false); m_abiWidget->setEnabled(false); } @@ -787,6 +832,7 @@ void KeilToolChainConfigWidget::setFromToolChain() const QSignalBlocker blocker(this); const auto tc = static_cast(toolChain()); m_compilerCommand->setFilePath(tc->compilerCommand()); + m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(tc->extraCodeModelFlags())); m_abiWidget->setAbis({}, tc->targetAbi()); const bool haveCompiler = compilerExists(m_compilerCommand->filePath()); m_abiWidget->setEnabled(haveCompiler && !tc->isAutoDetected()); @@ -798,7 +844,12 @@ void KeilToolChainConfigWidget::handleCompilerCommandChange() const bool haveCompiler = compilerExists(compilerPath); if (haveCompiler) { const auto env = Environment::systemEnvironment(); - m_macros = dumpPredefinedMacros(compilerPath, env.toStringList()); + const QStringList prevExtraArgs = splitString(m_platformCodeGenFlagsLineEdit->text()); + QStringList newExtraArgs = prevExtraArgs; + addDefaultCpuArgs(compilerPath, newExtraArgs); + if (prevExtraArgs != newExtraArgs) + m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(newExtraArgs)); + m_macros = dumpPredefinedMacros(compilerPath, newExtraArgs, env.toStringList()); const Abi guessed = guessAbi(m_macros); m_abiWidget->setAbis({}, guessed); } @@ -807,5 +858,31 @@ void KeilToolChainConfigWidget::handleCompilerCommandChange() emit dirty(); } +void KeilToolChainConfigWidget::handlePlatformCodeGenFlagsChange() +{ + const QString str1 = m_platformCodeGenFlagsLineEdit->text(); + const QString str2 = QtcProcess::joinArgs(splitString(str1)); + if (str1 != str2) + m_platformCodeGenFlagsLineEdit->setText(str2); + else + handleCompilerCommandChange(); +} + +QStringList KeilToolChainConfigWidget::splitString(const QString &s) const +{ + QtcProcess::SplitError splitError; + const OsType osType = HostOsInfo::hostOs(); + QStringList res = QtcProcess::splitArgs(s, osType, false, &splitError); + if (splitError != QtcProcess::SplitOk){ + res = QtcProcess::splitArgs(s + '\\', osType, false, &splitError); + if (splitError != QtcProcess::SplitOk){ + res = QtcProcess::splitArgs(s + '"', osType, false, &splitError); + if (splitError != QtcProcess::SplitOk) + res = QtcProcess::splitArgs(s + '\'', osType, false, &splitError); + } + } + return res; +} + } // namespace Internal } // namespace BareMetal diff --git a/src/plugins/baremetal/keiltoolchain.h b/src/plugins/baremetal/keiltoolchain.h index 3fd36d67962..1e7dc09da90 100644 --- a/src/plugins/baremetal/keiltoolchain.h +++ b/src/plugins/baremetal/keiltoolchain.h @@ -30,6 +30,7 @@ #include QT_BEGIN_NAMESPACE +class QLineEdit; class QPlainTextEdit; class QPushButton; class QTextEdit; @@ -81,6 +82,9 @@ public: void setCompilerCommand(const Utils::FilePath &file); Utils::FilePath compilerCommand() const final; + void setExtraCodeModelFlags(const QStringList &flags); + QStringList extraCodeModelFlags() const final; + Utils::FilePath makeCommand(const Utils::Environment &env) const final; private: @@ -88,6 +92,7 @@ private: ProjectExplorer::Abi m_targetAbi; Utils::FilePath m_compilerCommand; + QStringList m_extraCodeModelFlags; friend class KeilToolChainFactory; friend class KeilToolChainConfigWidget; @@ -127,9 +132,12 @@ private: void setFromToolChain(); void handleCompilerCommandChange(); + void handlePlatformCodeGenFlagsChange(); + QStringList splitString(const QString &s) const; Utils::PathChooser *m_compilerCommand = nullptr; ProjectExplorer::AbiWidget *m_abiWidget = nullptr; + QLineEdit *m_platformCodeGenFlagsLineEdit = nullptr; ProjectExplorer::Macros m_macros; };