diff options
author | Denis Shienkov <denis.shienkov@gmail.com> | 2019-03-19 22:45:36 +0300 |
---|---|---|
committer | Denis Shienkov <denis.shienkov@gmail.com> | 2019-04-15 16:35:22 +0000 |
commit | 8f8ff686dfef45bbb7590bea67ed517ecc48099d (patch) | |
tree | 47a66c3584df9dda81e487c36e6eb883497860e1 /src | |
parent | 31517f00bb75c4be2ed61e67399471df9bd23b30 (diff) | |
download | qt-creator-8f8ff686dfef45bbb7590bea67ed517ecc48099d.tar.gz |
bare-metal: Add support for SDCC toolchain
This patch adds support for the SDCC toolchain:
* http://sdcc.sourceforge.net/
Now QtC's compiler page have additional 'SDCC' selector which
allows to user to choose a desired compiler. Main point is that
the SDCC supports only the C-language, so the C++ selector is
not available.
When the compiler is added, the QtC will tries to detect the
compiler ABI.
Also it is implemented the compiler auto-detection; each toolchain
is displayed with its detected version.
Currently is supported the following architecture:
* 8051 (aka MCS51)
In addition, were added changes to the QBS Project Manager
plugin to make it work with QBS .
So, now do not need to do an additional 'hacks' into the
'qbs.toolchain' property of QtC SDCC kit.
Following features are not implemented yet:
* Debugger integration.
* Compile output parsers.
* Support for other architectures (z80, ds390 and etc) .
Change-Id: I92b97a81152d94cabf569e2013fc7260b8d7b953
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/baremetal/baremetal.pro | 2 | ||||
-rw-r--r-- | src/plugins/baremetal/baremetal.qbs | 1 | ||||
-rw-r--r-- | src/plugins/baremetal/baremetalconstants.h | 1 | ||||
-rw-r--r-- | src/plugins/baremetal/baremetalplugin.cpp | 2 | ||||
-rw-r--r-- | src/plugins/baremetal/sdcctoolchain.cpp | 605 | ||||
-rw-r--r-- | src/plugins/baremetal/sdcctoolchain.h | 166 | ||||
-rw-r--r-- | src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp | 2 |
7 files changed, 779 insertions, 0 deletions
diff --git a/src/plugins/baremetal/baremetal.pro b/src/plugins/baremetal/baremetal.pro index 495ddf3acd..922ff50fe4 100644 --- a/src/plugins/baremetal/baremetal.pro +++ b/src/plugins/baremetal/baremetal.pro @@ -22,6 +22,7 @@ SOURCES += baremetalplugin.cpp \ stlinkutilgdbserverprovider.cpp \ iarewtoolchain.cpp \ keiltoolchain.cpp \ + sdcctoolchain.cpp \ iarewparser.cpp \ keilparser.cpp \ @@ -45,6 +46,7 @@ HEADERS += baremetalplugin.h \ stlinkutilgdbserverprovider.h \ iarewtoolchain.h \ keiltoolchain.h \ + sdcctoolchain.h \ iarewparser.h \ keilparser.h \ diff --git a/src/plugins/baremetal/baremetal.qbs b/src/plugins/baremetal/baremetal.qbs index 9bd07ab0e5..5c7694a8e8 100644 --- a/src/plugins/baremetal/baremetal.qbs +++ b/src/plugins/baremetal/baremetal.qbs @@ -34,6 +34,7 @@ QtcPlugin { "stlinkutilgdbserverprovider.cpp", "stlinkutilgdbserverprovider.h", "iarewtoolchain.cpp", "iarewtoolchain.h", "keiltoolchain.cpp", "keiltoolchain.h", + "sdcctoolchain.cpp", "sdcctoolchain.h", "iarewparser.cpp", "iarewparser.h", "keilparser.cpp", "keilparser.h", ] diff --git a/src/plugins/baremetal/baremetalconstants.h b/src/plugins/baremetal/baremetalconstants.h index 13ecbbf965..9f8a08cc50 100644 --- a/src/plugins/baremetal/baremetalconstants.h +++ b/src/plugins/baremetal/baremetalconstants.h @@ -44,6 +44,7 @@ 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/baremetalplugin.cpp b/src/plugins/baremetal/baremetalplugin.cpp index 45875859bb..be394a04e0 100644 --- a/src/plugins/baremetal/baremetalplugin.cpp +++ b/src/plugins/baremetal/baremetalplugin.cpp @@ -36,6 +36,7 @@ #include "iarewtoolchain.h" #include "keiltoolchain.h" +#include "sdcctoolchain.h" #include <coreplugin/icore.h> #include <coreplugin/icontext.h> @@ -54,6 +55,7 @@ class BareMetalPluginPrivate public: IarToolChainFactory iarToolChainFactory; KeilToolchainFactory keilToolChainFactory; + SdccToolChainFactory sdccToolChainFactory; BareMetalDeviceFactory deviceFactory; BareMetalRunConfigurationFactory runConfigurationFactory; BareMetalCustomRunConfigurationFactory customRunConfigurationFactory; diff --git a/src/plugins/baremetal/sdcctoolchain.cpp b/src/plugins/baremetal/sdcctoolchain.cpp new file mode 100644 index 0000000000..496ba70d8e --- /dev/null +++ b/src/plugins/baremetal/sdcctoolchain.cpp @@ -0,0 +1,605 @@ +/**************************************************************************** +** +** 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 "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 FileName &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 "-mmcs51"; + default: + return {}; + } +} + +static Macros dumpPredefinedMacros(const FileName &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 FileName &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) +{ + return SdccToolChain::tr("SDCC %1 (%2, %3)") + .arg(version, language.toString(), Abi::toString(arch)); +} + +static Utils::FileName compilerPathFromEnvironment(const QString &compilerName) +{ + const Environment systemEnvironment = Environment::systemEnvironment(); + return systemEnvironment.searchInPath(compilerName); +} + +// SdccToolChain + +SdccToolChain::SdccToolChain(Detection d) : + ToolChain(Constants::SDCC_TOOLCHAIN_TYPEID, d), + m_predefinedMacrosCache(std::make_shared<Cache<MacroInspectionReport, 64>>()), + m_headerPathsCache(std::make_shared<HeaderPathsCache>()) +{ } + +SdccToolChain::SdccToolChain(Core::Id language, Detection d) : + SdccToolChain(d) +{ + setLanguage(language); +} + +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::FileName compilerCommand = m_compilerCommand; + const Core::Id lang = language(); + const Abi abi = m_targetAbi; + + MacrosCache macrosCache = m_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::FileName compilerCommand = m_compilerCommand; + const Core::Id languageId = language(); + const Abi abi = m_targetAbi; + + HeaderPathsCachePtr headerPathsCache = m_headerPathsCache; + + return [env, compilerCommand, headerPathsCache, languageId, abi] + (const QStringList &flags, const QString &fileName) { + Q_UNUSED(flags) + Q_UNUSED(fileName) + + const HeaderPaths paths = dumpHeaderPaths(compilerCommand, env.toStringList(), + abi); + headerPathsCache->insert({}, paths); + + return paths; + }; +} + +HeaderPaths SdccToolChain::builtInHeaderPaths(const QStringList &cxxFlags, + const FileName &fileName) const +{ + return createBuiltInHeaderPathsRunner()(cxxFlags, fileName.toString()); +} + +void SdccToolChain::addToEnvironment(Environment &env) const +{ + if (!m_compilerCommand.isEmpty()) { + const FileName path = m_compilerCommand.parentDir(); + env.prependOrSetPath(path.toString()); + } +} + +IOutputParser *SdccToolChain::outputParser() const +{ + return nullptr; +} + +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 = FileName::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 FileName &file) +{ + if (file == m_compilerCommand) + return; + m_compilerCommand = file; + toolChainUpdated(); +} + +FileName SdccToolChain::compilerCommand() const +{ + return m_compilerCommand; +} + +QString SdccToolChain::makeCommand(const Environment &env) const +{ + Q_UNUSED(env) + return {}; +} + +ToolChain *SdccToolChain::clone() const +{ + return new SdccToolChain(*this); +} + +void SdccToolChain::toolChainUpdated() +{ + m_predefinedMacrosCache->invalidate(); + m_headerPathsCache->invalidate(); + ToolChain::toolChainUpdated(); +} + +// SdccToolChainFactory + +SdccToolChainFactory::SdccToolChainFactory() +{ + setDisplayName(tr("SDCC")); +} + +QSet<Core::Id> SdccToolChainFactory::supportedLanguages() const +{ + return {ProjectExplorer::Constants::C_LANGUAGE_ID}; +} + +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 FileName fn = FileName::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 FileName 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); +} + +bool SdccToolChainFactory::canCreate() +{ + return true; +} + +ToolChain *SdccToolChainFactory::create(Core::Id language) +{ + return new SdccToolChain(language, ToolChain::ManualDetection); +} + +bool SdccToolChainFactory::canRestore(const QVariantMap &data) +{ + return typeIdFromMap(data) == Constants::SDCC_TOOLCHAIN_TYPEID; +} + +ToolChain *SdccToolChainFactory::restore(const QVariantMap &data) +{ + const auto tc = new SdccToolChain(ToolChain::ManualDetection); + if (tc->fromMap(data)) + return tc; + + delete tc; + return nullptr; +} + +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.first + && (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.first, env.toStringList(), {}); + if (macros.isEmpty()) + return {}; + const Abi abi = guessAbi(macros); + + const auto tc = new SdccToolChain(ToolChain::AutoDetection); + tc->setLanguage(language); + tc->setCompilerCommand(candidate.first); + tc->setTargetAbi(abi); + tc->setDisplayName(buildDisplayName(abi.architecture(), language, candidate.second)); + + const auto languageVersion = ToolChain::languageVersion(language, macros); + tc->m_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->m_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 FileName 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..718fd7b443 --- /dev/null +++ b/src/plugins/baremetal/sdcctoolchain.h @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** 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/toolchaincache.h> +#include <projectexplorer/toolchainconfigwidget.h> + +QT_BEGIN_NAMESPACE +class QPlainTextEdit; +class QPushButton; +class QTextEdit; +QT_END_NAMESPACE + +namespace Utils { +class FileName; +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 override; + + void setTargetAbi(const ProjectExplorer::Abi &abi); + ProjectExplorer::Abi targetAbi() const override; + + bool isValid() const override; + + MacroInspectionRunner createMacroInspectionRunner() const override; + ProjectExplorer::Macros predefinedMacros(const QStringList &cxxflags) const override; + + Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const override; + ProjectExplorer::WarningFlags warningFlags(const QStringList &cxxflags) const override; + + BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner() const override; + ProjectExplorer::HeaderPaths builtInHeaderPaths(const QStringList &cxxFlags, + const Utils::FileName &) const override; + void addToEnvironment(Utils::Environment &env) const override; + ProjectExplorer::IOutputParser *outputParser() const override; + + QVariantMap toMap() const override; + bool fromMap(const QVariantMap &data) override; + + std::unique_ptr<ProjectExplorer::ToolChainConfigWidget> createConfigurationWidget() override; + + bool operator ==(const ToolChain &other) const override; + + void setCompilerCommand(const Utils::FileName &file); + Utils::FileName compilerCommand() const override; + + QString makeCommand(const Utils::Environment &env) const override; + + ToolChain *clone() const override; + + void toolChainUpdated() override; + +protected: + SdccToolChain(const SdccToolChain &tc) = default; + +private: + explicit SdccToolChain(Detection d); + explicit SdccToolChain(Core::Id language, Detection d); + + ProjectExplorer::Abi m_targetAbi; + Utils::FileName m_compilerCommand; + + using MacrosCache = std::shared_ptr<ProjectExplorer::Cache<MacroInspectionReport, 64>>; + mutable MacrosCache m_predefinedMacrosCache; + + using HeaderPathsCache = ProjectExplorer::Cache<ProjectExplorer::HeaderPaths>; + using HeaderPathsCachePtr = std::shared_ptr<HeaderPathsCache>; + mutable HeaderPathsCachePtr m_headerPathsCache; + + friend class SdccToolChainFactory; + friend class SdccToolChainConfigWidget; +}; + +// SdccToolChainFactory + +class SdccToolChainFactory final : public ProjectExplorer::ToolChainFactory +{ + Q_OBJECT + +public: + SdccToolChainFactory(); + QSet<Core::Id> supportedLanguages() const override; + + QList<ProjectExplorer::ToolChain *> autoDetect( + const QList<ProjectExplorer::ToolChain *> &alreadyKnown) override; + + bool canCreate() override; + ProjectExplorer::ToolChain *create(Core::Id language) override; + + bool canRestore(const QVariantMap &data) override; + ProjectExplorer::ToolChain *restore(const QVariantMap &data) override; + +private: + // File path + version. + using Candidate = QPair<Utils::FileName, QString>; + using Candidates = QVector<Candidate>; + + 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() override; + void discardImpl() override { setFromToolchain(); } + bool isDirtyImpl() const override; + void makeReadOnlyImpl() override; + + void setFromToolchain(); + void handleCompilerCommandChange(); + + Utils::PathChooser *m_compilerCommand = nullptr; + ProjectExplorer::AbiWidget *m_abiWidget = nullptr; + ProjectExplorer::Macros m_macros; +}; + +} // namespace Internal +} // namespace BareMetal diff --git a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp index 32a65b1516..071de5fc22 100644 --- a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp +++ b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp @@ -135,6 +135,8 @@ static QStringList toolchainList(const ProjectExplorer::ToolChain *tc) list << QLatin1String("iar"); else if (tc->typeId() == BareMetal::Constants::KEIL_TOOLCHAIN_TYPEID) list << QLatin1String("keil"); + else if (tc->typeId() == BareMetal::Constants::SDCC_TOOLCHAIN_TYPEID) + list << QLatin1String("sdcc"); return list; } |