diff options
27 files changed, 1279 insertions, 668 deletions
diff --git a/src/plugins/android/androidtoolchain.cpp b/src/plugins/android/androidtoolchain.cpp index 5bb5aa4ddea..02da5692eff 100644 --- a/src/plugins/android/androidtoolchain.cpp +++ b/src/plugins/android/androidtoolchain.cpp @@ -10,6 +10,7 @@ #include <projectexplorer/toolchainmanager.h> #include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorerconstants.h> +#include <projectexplorer/toolchainconfigwidget.h> #include <utils/environment.h> @@ -246,6 +247,18 @@ public: ProjectExplorer::Constants::CXX_LANGUAGE_ID}); setToolchainConstructor([] { return new AndroidToolchain; }); } + +private: + std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget( + const ToolchainBundle &bundle) const final + { + return GccToolchain::createConfigurationWidget(bundle); + } + + FilePath correspondingCompilerCommand(const FilePath &srcPath, Id targetLang) const override + { + return GccToolchain::correspondingCompilerCommand(srcPath, targetLang, "clang", "clang++"); + } }; void setupAndroidToolchain() diff --git a/src/plugins/baremetal/iarewtoolchain.cpp b/src/plugins/baremetal/iarewtoolchain.cpp index d5029c78788..198af3a0203 100644 --- a/src/plugins/baremetal/iarewtoolchain.cpp +++ b/src/plugins/baremetal/iarewtoolchain.cpp @@ -253,12 +253,10 @@ static QString buildDisplayName(Abi::Architecture arch, Utils::Id language, // IarToolchainConfigWidget -class IarToolchain; - class IarToolchainConfigWidget final : public ToolchainConfigWidget { public: - explicit IarToolchainConfigWidget(IarToolchain *tc); + explicit IarToolchainConfigWidget(const ProjectExplorer::ToolchainBundle &bundle); private: void applyImpl() final; @@ -267,13 +265,13 @@ private: void makeReadOnlyImpl() final; void setFromToolchain(); - void handleCompilerCommandChange(); + void handleCompilerCommandChange(Id language); void handlePlatformCodeGenFlagsChange(); - PathChooser *m_compilerCommand = nullptr; AbiWidget *m_abiWidget = nullptr; QLineEdit *m_platformCodeGenFlagsLineEdit = nullptr; - Macros m_macros; + Macros m_cMacros; + Macros m_cxxMacros; }; // IarToolchain @@ -301,8 +299,6 @@ public: void addToEnvironment(Environment &env) const final; QList<OutputLineParser *> createOutputParsers() const final { return {new IarParser()}; } - std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget() final; - bool operator==(const Toolchain &other) const final; QStringList extraCodeModelFlags() const final { return m_extraCodeModelFlags(); } @@ -386,11 +382,6 @@ void IarToolchain::addToEnvironment(Environment &env) const env.prependOrSetPath(compilerCommand().parentDir()); } -std::unique_ptr<ToolchainConfigWidget> IarToolchain::createConfigurationWidget() -{ - return std::make_unique<IarToolchainConfigWidget>(this); -} - bool IarToolchain::operator==(const Toolchain &other) const { if (!Toolchain::operator==(other)) @@ -401,7 +392,6 @@ bool IarToolchain::operator==(const Toolchain &other) const && m_extraCodeModelFlags() == customTc->m_extraCodeModelFlags(); } - // IarToolchainFactory class IarToolchainFactory final : public ToolchainFactory @@ -419,6 +409,8 @@ public: Toolchains autoDetect(const ToolchainDetector &detector) const final; Toolchains detectForImport(const ToolchainDescription &tcd) const final; + std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget( + const ProjectExplorer::ToolchainBundle &bundle) const final; private: Toolchains autoDetectToolchains(const Candidates &candidates, @@ -509,6 +501,12 @@ Toolchains IarToolchainFactory::detectForImport(const ToolchainDescription &tcd) return { autoDetectToolchain({tcd.compilerPath, {}}, tcd.language) }; } +std::unique_ptr<ToolchainConfigWidget> IarToolchainFactory::createConfigurationWidget( + const ToolchainBundle &bundle) const +{ + return std::make_unique<IarToolchainConfigWidget>(bundle); +} + Toolchains IarToolchainFactory::autoDetectToolchains( const Candidates &candidates, const Toolchains &alreadyKnown) const { @@ -562,16 +560,12 @@ Toolchains IarToolchainFactory::autoDetectToolchain(const Candidate &candidate, // IarToolchainConfigWidget -IarToolchainConfigWidget::IarToolchainConfigWidget(IarToolchain *tc) : - ToolchainConfigWidget(tc), - m_compilerCommand(new PathChooser), +IarToolchainConfigWidget::IarToolchainConfigWidget(const ToolchainBundle &bundle) : + ToolchainConfigWidget(bundle), m_abiWidget(new AbiWidget) { - m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand); - m_compilerCommand->setHistoryCompleter("PE.IAREW.Command.History"); - m_mainLayout->addRow(Tr::tr("&Compiler path:"), m_compilerCommand); m_platformCodeGenFlagsLineEdit = new QLineEdit(this); - m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->extraCodeModelFlags())); + m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(bundle.extraCodeModelFlags())); m_mainLayout->addRow(Tr::tr("Platform codegen flags:"), m_platformCodeGenFlagsLineEdit); m_mainLayout->addRow(Tr::tr("&ABI:"), m_abiWidget); @@ -580,7 +574,7 @@ IarToolchainConfigWidget::IarToolchainConfigWidget(IarToolchain *tc) : addErrorLabel(); setFromToolchain(); - connect(m_compilerCommand, &PathChooser::rawPathChanged, + connect(this, &ToolchainConfigWidget::compilerCommandChanged, this, &IarToolchainConfigWidget::handleCompilerCommandChange); connect(m_platformCodeGenFlagsLineEdit, &QLineEdit::editingFinished, this, &IarToolchainConfigWidget::handlePlatformCodeGenFlagsChange); @@ -590,39 +584,36 @@ IarToolchainConfigWidget::IarToolchainConfigWidget(IarToolchain *tc) : void IarToolchainConfigWidget::applyImpl() { - if (toolchain()->isAutoDetected()) + if (bundle().isAutoDetected()) return; - const auto tc = static_cast<IarToolchain *>(toolchain()); - const QString displayName = tc->displayName(); - tc->setCompilerCommand(m_compilerCommand->filePath()); - - tc->m_extraCodeModelFlags.setValue(splitString(m_platformCodeGenFlagsLineEdit->text())); - - tc->setTargetAbi(m_abiWidget->currentAbi()); - tc->setDisplayName(displayName); + bundle().forEach<IarToolchain>([this](IarToolchain &tc) { + tc.m_extraCodeModelFlags.setValue(splitString(m_platformCodeGenFlagsLineEdit->text())); + }); + bundle().setTargetAbi(m_abiWidget->currentAbi()); - if (m_macros.isEmpty()) + if (m_cMacros.isEmpty() && m_cxxMacros.isEmpty()) return; - const auto languageVersion = Toolchain::languageVersion(tc->language(), m_macros); - tc->predefinedMacrosCache()->insert({}, {m_macros, languageVersion}); + bundle().forEach<IarToolchain>([this](IarToolchain &tc) { + const Macros ¯os = tc.language() == ProjectExplorer::Constants::C_LANGUAGE_ID + ? m_cMacros : m_cxxMacros; + const auto languageVersion = Toolchain::languageVersion(tc.language(), macros); + tc.predefinedMacrosCache()->insert({}, {macros, languageVersion}); + }); setFromToolchain(); } bool IarToolchainConfigWidget::isDirtyImpl() const { - const auto tc = static_cast<IarToolchain *>(toolchain()); - return m_compilerCommand->filePath() != tc->compilerCommand() - || m_platformCodeGenFlagsLineEdit->text() != ProcessArgs::joinArgs(tc->extraCodeModelFlags()) - || m_abiWidget->currentAbi() != tc->targetAbi() - ; + return m_platformCodeGenFlagsLineEdit->text() + != ProcessArgs::joinArgs(bundle().extraCodeModelFlags()) + || m_abiWidget->currentAbi() != bundle().targetAbi(); } void IarToolchainConfigWidget::makeReadOnlyImpl() { - m_compilerCommand->setReadOnly(true); m_platformCodeGenFlagsLineEdit->setEnabled(false); m_abiWidget->setEnabled(false); } @@ -630,28 +621,25 @@ void IarToolchainConfigWidget::makeReadOnlyImpl() void IarToolchainConfigWidget::setFromToolchain() { const QSignalBlocker blocker(this); - const auto tc = static_cast<IarToolchain *>(toolchain()); - m_compilerCommand->setFilePath(tc->compilerCommand()); - m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->extraCodeModelFlags())); - m_abiWidget->setAbis({}, tc->targetAbi()); - const bool haveCompiler = m_compilerCommand->filePath().isExecutableFile(); - m_abiWidget->setEnabled(haveCompiler && !tc->isAutoDetected()); + m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(bundle().extraCodeModelFlags())); + m_abiWidget->setAbis({}, bundle().targetAbi()); + m_abiWidget->setEnabled(hasAnyCompiler() && !bundle().isAutoDetected()); } -void IarToolchainConfigWidget::handleCompilerCommandChange() +void IarToolchainConfigWidget::handleCompilerCommandChange(Id language) { - const FilePath compilerPath = m_compilerCommand->filePath(); + const bool isC = language == ProjectExplorer::Constants::C_LANGUAGE_ID; + const FilePath compilerPath = compilerCommand(language); + Macros ¯os = isC ? m_cMacros : m_cxxMacros; const bool haveCompiler = compilerPath.isExecutableFile(); if (haveCompiler) { const auto env = Environment::systemEnvironment(); const QStringList extraArgs = splitString(m_platformCodeGenFlagsLineEdit->text()); - const Id languageId = toolchain()->language(); - m_macros = dumpPredefinedMacros(compilerPath, extraArgs, languageId, env); - const Abi guessed = guessAbi(m_macros); + macros = dumpPredefinedMacros(compilerPath, extraArgs, language, env); + const Abi guessed = guessAbi(macros); m_abiWidget->setAbis({}, guessed); } - - m_abiWidget->setEnabled(haveCompiler); + m_abiWidget->setEnabled(hasAnyCompiler() && !bundle().isAutoDetected()); emit dirty(); } @@ -659,10 +647,12 @@ void IarToolchainConfigWidget::handlePlatformCodeGenFlagsChange() { const QString str1 = m_platformCodeGenFlagsLineEdit->text(); const QString str2 = ProcessArgs::joinArgs(splitString(str1)); - if (str1 != str2) + if (str1 != str2) { m_platformCodeGenFlagsLineEdit->setText(str2); - else - handleCompilerCommandChange(); + } else { + handleCompilerCommandChange(ProjectExplorer::Constants::C_LANGUAGE_ID); + handleCompilerCommandChange(ProjectExplorer::Constants::CXX_LANGUAGE_ID); + } } } // BareMetal::Internal diff --git a/src/plugins/baremetal/keiltoolchain.cpp b/src/plugins/baremetal/keiltoolchain.cpp index bc260130b2b..0bc91e7b2fe 100644 --- a/src/plugins/baremetal/keiltoolchain.cpp +++ b/src/plugins/baremetal/keiltoolchain.cpp @@ -391,7 +391,7 @@ class KeilToolchain; class KeilToolchainConfigWidget final : public ToolchainConfigWidget { public: - explicit KeilToolchainConfigWidget(KeilToolchain *tc); + explicit KeilToolchainConfigWidget(const ToolchainBundle &bundle); private: void applyImpl() final; @@ -400,10 +400,9 @@ private: void makeReadOnlyImpl() final; void setFromToolchain(); - void handleCompilerCommandChange(); + void handleCompilerCommandChange(Id language); void handlePlatformCodeGenFlagsChange(); - PathChooser *m_compilerCommand = nullptr; AbiWidget *m_abiWidget = nullptr; QLineEdit *m_platformCodeGenFlagsLineEdit = nullptr; Macros m_macros; @@ -436,8 +435,6 @@ public: QList<OutputLineParser *> createOutputParsers() const final { return {new KeilParser}; } - std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget() final; - bool operator==(const Toolchain &other) const final; QStringList extraCodeModelFlags() const final; @@ -508,11 +505,6 @@ void KeilToolchain::addToEnvironment(Environment &env) const env.prependOrSetPath(compilerCommand().parentDir()); } -std::unique_ptr<ToolchainConfigWidget> KeilToolchain::createConfigurationWidget() -{ - return std::make_unique<KeilToolchainConfigWidget>(this); -} - bool KeilToolchain::operator ==(const Toolchain &other) const { if (!Toolchain::operator ==(other)) @@ -545,6 +537,11 @@ public: } Toolchains autoDetect(const ToolchainDetector &detector) const final; + std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget( + const ToolchainBundle &bundle) const final + { + return std::make_unique<KeilToolchainConfigWidget>(bundle); + } private: Toolchains autoDetectToolchains(const Candidates &candidates, @@ -717,16 +714,11 @@ Toolchains KeilToolchainFactory::autoDetectToolchain(const Candidate &candidate, // KeilToolchainConfigWidget -KeilToolchainConfigWidget::KeilToolchainConfigWidget(KeilToolchain *tc) : - ToolchainConfigWidget(tc), - m_compilerCommand(new PathChooser), +KeilToolchainConfigWidget::KeilToolchainConfigWidget(const ToolchainBundle &bundle) : + ToolchainConfigWidget(bundle), m_abiWidget(new AbiWidget) { - m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand); - m_compilerCommand->setHistoryCompleter("PE.KEIL.Command.History"); - m_mainLayout->addRow(Tr::tr("&Compiler path:"), m_compilerCommand); m_platformCodeGenFlagsLineEdit = new QLineEdit(this); - m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->extraCodeModelFlags())); m_mainLayout->addRow(Tr::tr("Platform codegen flags:"), m_platformCodeGenFlagsLineEdit); m_mainLayout->addRow(Tr::tr("&ABI:"), m_abiWidget); @@ -735,7 +727,7 @@ KeilToolchainConfigWidget::KeilToolchainConfigWidget(KeilToolchain *tc) : addErrorLabel(); setFromToolchain(); - connect(m_compilerCommand, &PathChooser::rawPathChanged, + connect(this, &ToolchainConfigWidget::compilerCommandChanged, this, &KeilToolchainConfigWidget::handleCompilerCommandChange); connect(m_platformCodeGenFlagsLineEdit, &QLineEdit::editingFinished, this, &KeilToolchainConfigWidget::handlePlatformCodeGenFlagsChange); @@ -745,37 +737,34 @@ KeilToolchainConfigWidget::KeilToolchainConfigWidget(KeilToolchain *tc) : void KeilToolchainConfigWidget::applyImpl() { - if (toolchain()->isAutoDetected()) + if (bundle().isAutoDetected()) return; - const auto tc = static_cast<KeilToolchain *>(toolchain()); - const QString displayName = tc->displayName(); - tc->setCompilerCommand(m_compilerCommand->filePath()); - tc->m_extraCodeModelFlags.setValue(splitString(m_platformCodeGenFlagsLineEdit->text())); - tc->setTargetAbi(m_abiWidget->currentAbi()); - tc->setDisplayName(displayName); + bundle().setTargetAbi(m_abiWidget->currentAbi()); + bundle().forEach<KeilToolchain>([this](KeilToolchain &tc) { + tc.m_extraCodeModelFlags.setValue(splitString(m_platformCodeGenFlagsLineEdit->text())); + }); if (m_macros.isEmpty()) return; - const auto languageVersion = Toolchain::languageVersion(tc->language(), m_macros); - tc->predefinedMacrosCache()->insert({}, {m_macros, languageVersion}); + bundle().forEach<KeilToolchain>([this](KeilToolchain &tc) { + 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->filePath() != tc->compilerCommand() - || m_platformCodeGenFlagsLineEdit->text() != ProcessArgs::joinArgs(tc->extraCodeModelFlags()) - || m_abiWidget->currentAbi() != tc->targetAbi() - ; + return m_platformCodeGenFlagsLineEdit->text() + != ProcessArgs::joinArgs(bundle().extraCodeModelFlags()) + || m_abiWidget->currentAbi() != bundle().targetAbi(); } void KeilToolchainConfigWidget::makeReadOnlyImpl() { - m_compilerCommand->setReadOnly(true); m_platformCodeGenFlagsLineEdit->setEnabled(false); m_abiWidget->setEnabled(false); } @@ -783,19 +772,15 @@ void KeilToolchainConfigWidget::makeReadOnlyImpl() void KeilToolchainConfigWidget::setFromToolchain() { const QSignalBlocker blocker(this); - const auto tc = static_cast<KeilToolchain *>(toolchain()); - m_compilerCommand->setFilePath(tc->compilerCommand()); - m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->extraCodeModelFlags())); - m_abiWidget->setAbis({}, tc->targetAbi()); - const bool haveCompiler = m_compilerCommand->filePath().isExecutableFile(); - m_abiWidget->setEnabled(haveCompiler && !tc->isAutoDetected()); + m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(bundle().extraCodeModelFlags())); + m_abiWidget->setAbis({}, bundle().targetAbi()); + m_abiWidget->setEnabled(hasAnyCompiler() && !bundle().isAutoDetected()); } -void KeilToolchainConfigWidget::handleCompilerCommandChange() +void KeilToolchainConfigWidget::handleCompilerCommandChange(Id language) { - const FilePath compilerPath = m_compilerCommand->filePath(); - const bool haveCompiler = compilerPath.isExecutableFile(); - if (haveCompiler) { + const FilePath compilerPath = compilerCommand(language); + if (compilerPath.isExecutableFile()) { const auto env = Environment::systemEnvironment(); const QStringList prevExtraArgs = splitString(m_platformCodeGenFlagsLineEdit->text()); QStringList newExtraArgs = prevExtraArgs; @@ -807,7 +792,7 @@ void KeilToolchainConfigWidget::handleCompilerCommandChange() m_abiWidget->setAbis({}, guessed); } - m_abiWidget->setEnabled(haveCompiler); + m_abiWidget->setEnabled(hasAnyCompiler()); emit dirty(); } @@ -815,10 +800,12 @@ void KeilToolchainConfigWidget::handlePlatformCodeGenFlagsChange() { const QString str1 = m_platformCodeGenFlagsLineEdit->text(); const QString str2 = ProcessArgs::joinArgs(splitString(str1)); - if (str1 != str2) + if (str1 != str2) { m_platformCodeGenFlagsLineEdit->setText(str2); - else - handleCompilerCommandChange(); + } else { + handleCompilerCommandChange(ProjectExplorer::Constants::C_LANGUAGE_ID); + handleCompilerCommandChange(ProjectExplorer::Constants::CXX_LANGUAGE_ID); + } } } // BareMetal::Internal diff --git a/src/plugins/baremetal/sdcctoolchain.cpp b/src/plugins/baremetal/sdcctoolchain.cpp index 971fd9f13a8..82a881b8880 100644 --- a/src/plugins/baremetal/sdcctoolchain.cpp +++ b/src/plugins/baremetal/sdcctoolchain.cpp @@ -179,7 +179,7 @@ class SdccToolchain; class SdccToolchainConfigWidget final : public ToolchainConfigWidget { public: - explicit SdccToolchainConfigWidget(SdccToolchain *tc); + explicit SdccToolchainConfigWidget(const ToolchainBundle &bundle); private: void applyImpl() final; @@ -190,7 +190,6 @@ private: void setFromToolchain(); void handleCompilerCommandChange(); - PathChooser *m_compilerCommand = nullptr; AbiWidget *m_abiWidget = nullptr; Macros m_macros; }; @@ -216,8 +215,6 @@ public: void addToEnvironment(Environment &env) const final; QList<OutputLineParser *> createOutputParsers() const final { return {new SdccParser}; } - std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget() final; - bool operator==(const Toolchain &other) const final; FilePath makeCommand(const Environment &) const final { return {}; } @@ -281,11 +278,6 @@ void SdccToolchain::addToEnvironment(Environment &env) const env.prependOrSetPath(compilerCommand().parentDir()); } -std::unique_ptr<ToolchainConfigWidget> SdccToolchain::createConfigurationWidget() -{ - return std::make_unique<SdccToolchainConfigWidget>(this); -} - bool SdccToolchain::operator==(const Toolchain &other) const { if (!Toolchain::operator==(other)) @@ -311,6 +303,11 @@ public: } Toolchains autoDetect(const ToolchainDetector &detector) const final; + std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget( + const ToolchainBundle &bundle) const final + { + return std::make_unique<SdccToolchainConfigWidget>(bundle); + } private: Toolchains autoDetectToolchains(const Candidates &candidates, @@ -445,14 +442,10 @@ Toolchains SdccToolchainFactory::autoDetectToolchain(const Candidate &candidate, // SdccToolchainConfigWidget -SdccToolchainConfigWidget::SdccToolchainConfigWidget(SdccToolchain *tc) : - ToolchainConfigWidget(tc), - m_compilerCommand(new PathChooser), +SdccToolchainConfigWidget::SdccToolchainConfigWidget(const ToolchainBundle &bundle) : + ToolchainConfigWidget(bundle), m_abiWidget(new AbiWidget) { - m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand); - m_compilerCommand->setHistoryCompleter("PE.SDCC.Command.History"); - m_mainLayout->addRow(Tr::tr("&Compiler path:"), m_compilerCommand); m_mainLayout->addRow(Tr::tr("&ABI:"), m_abiWidget); m_abiWidget->setEnabled(false); @@ -460,7 +453,7 @@ SdccToolchainConfigWidget::SdccToolchainConfigWidget(SdccToolchain *tc) : addErrorLabel(); setFromToolchain(); - connect(m_compilerCommand, &PathChooser::rawPathChanged, + connect(this, &ToolchainConfigWidget::compilerCommandChanged, this, &SdccToolchainConfigWidget::handleCompilerCommandChange); connect(m_abiWidget, &AbiWidget::abiChanged, this, &ToolchainConfigWidget::dirty); @@ -468,51 +461,42 @@ SdccToolchainConfigWidget::SdccToolchainConfigWidget(SdccToolchain *tc) : void SdccToolchainConfigWidget::applyImpl() { - if (toolchain()->isAutoDetected()) + if (bundle().isAutoDetected()) return; - const auto tc = static_cast<SdccToolchain *>(toolchain()); - const QString displayName = tc->displayName(); - tc->setCompilerCommand(m_compilerCommand->filePath()); - tc->setTargetAbi(m_abiWidget->currentAbi()); - tc->setDisplayName(displayName); - + bundle().setTargetAbi(m_abiWidget->currentAbi()); if (m_macros.isEmpty()) return; - const auto languageVersion = Toolchain::languageVersion(tc->language(), m_macros); - tc->predefinedMacrosCache()->insert({}, {m_macros, languageVersion}); - + bundle().forEach<SdccToolchain>([this](SdccToolchain &tc) { + 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->filePath() != tc->compilerCommand() - || m_abiWidget->currentAbi() != tc->targetAbi() - ; + return m_abiWidget->currentAbi() != bundle().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->setFilePath(tc->compilerCommand()); - m_abiWidget->setAbis({}, tc->targetAbi()); - const bool haveCompiler = m_compilerCommand->filePath().isExecutableFile(); - m_abiWidget->setEnabled(haveCompiler && !tc->isAutoDetected()); + m_abiWidget->setAbis({}, bundle().targetAbi()); + const bool haveCompiler + = compilerCommand(ProjectExplorer::Constants::C_LANGUAGE_ID).isExecutableFile(); + m_abiWidget->setEnabled(haveCompiler && !bundle().isAutoDetected()); } void SdccToolchainConfigWidget::handleCompilerCommandChange() { - const FilePath compilerPath = m_compilerCommand->filePath(); + const FilePath compilerPath = compilerCommand(ProjectExplorer::Constants::C_LANGUAGE_ID); const bool haveCompiler = compilerPath.isExecutableFile(); if (haveCompiler) { const auto env = Environment::systemEnvironment(); diff --git a/src/plugins/cppeditor/projectinfo_test.cpp b/src/plugins/cppeditor/projectinfo_test.cpp index 19c869c148b..3536c139106 100644 --- a/src/plugins/cppeditor/projectinfo_test.cpp +++ b/src/plugins/cppeditor/projectinfo_test.cpp @@ -344,10 +344,7 @@ private: void addToEnvironment(Utils::Environment &) const override {} Utils::FilePath makeCommand(const Utils::Environment &) const override { return {}; } QList<Utils::OutputLineParser *> createOutputParsers() const override { return {}; } - std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget() override - { - return {}; - }; + bool canShareBundleImpl(const Toolchain &) const override { return false; } }; class ProjectInfoGeneratorTestHelper diff --git a/src/plugins/ios/iosconfigurations.cpp b/src/plugins/ios/iosconfigurations.cpp index 6d7d559d488..ce66978151e 100644 --- a/src/plugins/ios/iosconfigurations.cpp +++ b/src/plugins/ios/iosconfigurations.cpp @@ -20,6 +20,7 @@ #include <projectexplorer/toolchain.h> #include <projectexplorer/gcctoolchain.h> #include <projectexplorer/projectexplorerconstants.h> +#include <projectexplorer/toolchainconfigwidget.h> #include <debugger/debuggeritemmanager.h> #include <debugger/debuggeritem.h> @@ -555,6 +556,12 @@ public: } Toolchains autoDetect(const ToolchainDetector &detector) const final; + + std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget( + const ToolchainBundle &bundle) const override + { + return GccToolchain::createConfigurationWidget(bundle); + } }; Toolchains IosToolchainFactory::autoDetect(const ToolchainDetector &detector) const diff --git a/src/plugins/mcusupport/test/unittest.cpp b/src/plugins/mcusupport/test/unittest.cpp index c2bf0a9dd95..c64e196cbc3 100644 --- a/src/plugins/mcusupport/test/unittest.cpp +++ b/src/plugins/mcusupport/test/unittest.cpp @@ -213,7 +213,6 @@ auto expandTargetsAndPackages = [](Targets &targets, Packages &packages) { void verifyIarToolchain(const McuToolchainPackagePtr &iarToolchainPackage) { - ProjectExplorer::ToolchainFactory toolchainFactory; Id iarId{BareMetal::Constants::IAREW_TOOLCHAIN_TYPEID}; Toolchain *iarToolchain{ProjectExplorer::ToolchainFactory::createToolchain(iarId)}; iarToolchain->setLanguage(cxxLanguageId); @@ -236,7 +235,6 @@ void verifyIarToolchain(const McuToolchainPackagePtr &iarToolchainPackage) void verifyArmGccToolchain(const McuToolchainPackagePtr &armGccPackage, const QStringList &versions) { //Fake register and fake detect compiler. - ProjectExplorer::ToolchainFactory toolchainFactory; Id armGccId{ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID}; Toolchain *armToolchain{ProjectExplorer::ToolchainFactory::createToolchain(armGccId)}; diff --git a/src/plugins/nim/project/nimtoolchain.cpp b/src/plugins/nim/project/nimtoolchain.cpp index 701883de0c0..d333e618537 100644 --- a/src/plugins/nim/project/nimtoolchain.cpp +++ b/src/plugins/nim/project/nimtoolchain.cpp @@ -123,16 +123,12 @@ bool NimToolchain::parseVersion(const FilePath &path, std::tuple<int, int, int> class NimToolchainConfigWidget : public ToolchainConfigWidget { public: - explicit NimToolchainConfigWidget(NimToolchain *tc) - : ToolchainConfigWidget(tc) - , m_compilerCommand(new PathChooser) + explicit NimToolchainConfigWidget(const ToolchainBundle &bundle) + : ToolchainConfigWidget(bundle) , m_compilerVersion(new QLineEdit) { // Create ui - const auto gnuVersionArgs = QStringList("--version"); - m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand); - m_compilerCommand->setCommandVersionArguments(gnuVersionArgs); - m_mainLayout->addRow(Tr::tr("&Compiler path:"), m_compilerCommand); + setCommandVersionArguments({"--version"}); m_compilerVersion->setReadOnly(true); m_mainLayout->addRow(Tr::tr("&Compiler version:"), m_compilerVersion); @@ -140,11 +136,9 @@ public: fillUI(); // Connect - connect(m_compilerCommand, &PathChooser::validChanged, this, [this] { - const FilePath path = m_compilerCommand->unexpandedFilePath(); - auto tc = static_cast<NimToolchain *>(toolchain()); - QTC_ASSERT(tc, return); - tc->setCompilerCommand(path); + connect(this, &ToolchainConfigWidget::compilerCommandChanged, this, [this] { + const FilePath path = compilerCommand(Constants::C_NIMLANGUAGE_ID); + this->bundle().setCompilerCommand(Constants::C_NIMLANGUAGE_ID, path); fillUI(); }); } @@ -158,47 +152,22 @@ protected: private: void fillUI(); - Utils::PathChooser *m_compilerCommand; QLineEdit *m_compilerVersion; }; -void NimToolchainConfigWidget::applyImpl() -{ - auto tc = static_cast<NimToolchain *>(toolchain()); - Q_ASSERT(tc); - if (tc->isAutoDetected()) - return; - tc->setCompilerCommand(m_compilerCommand->filePath()); -} +void NimToolchainConfigWidget::applyImpl() {} void NimToolchainConfigWidget::discardImpl() { fillUI(); } -bool NimToolchainConfigWidget::isDirtyImpl() const -{ - auto tc = static_cast<NimToolchain *>(toolchain()); - Q_ASSERT(tc); - return tc->compilerCommand() != m_compilerCommand->filePath(); -} - -void NimToolchainConfigWidget::makeReadOnlyImpl() -{ - m_compilerCommand->setReadOnly(true); -} +bool NimToolchainConfigWidget::isDirtyImpl() const { return false; } +void NimToolchainConfigWidget::makeReadOnlyImpl() {} void NimToolchainConfigWidget::fillUI() { - auto tc = static_cast<NimToolchain *>(toolchain()); - Q_ASSERT(tc); - m_compilerCommand->setFilePath(tc->compilerCommand()); - m_compilerVersion->setText(tc->compilerVersion()); -} - -std::unique_ptr<ToolchainConfigWidget> NimToolchain::createConfigurationWidget() -{ - return std::make_unique<NimToolchainConfigWidget>(this); + m_compilerVersion->setText(bundle().get(&NimToolchain::compilerVersion)); } // NimToolchainFactory @@ -247,4 +216,10 @@ Toolchains NimToolchainFactory::detectForImport(const ToolchainDescription &tcd) return result; } +std::unique_ptr<ToolchainConfigWidget> NimToolchainFactory::createConfigurationWidget( + const ProjectExplorer::ToolchainBundle &bundle) const +{ + return std::make_unique<NimToolchainConfigWidget>(bundle); +} + } // Nim diff --git a/src/plugins/nim/project/nimtoolchain.h b/src/plugins/nim/project/nimtoolchain.h index 6304143d8b8..a97225d702f 100644 --- a/src/plugins/nim/project/nimtoolchain.h +++ b/src/plugins/nim/project/nimtoolchain.h @@ -24,7 +24,6 @@ public: Utils::FilePath makeCommand(const Utils::Environment &env) const final; QString compilerVersion() const; QList<Utils::OutputLineParser *> createOutputParsers() const final; - std::unique_ptr<ProjectExplorer::ToolchainConfigWidget> createConfigurationWidget() final; void fromMap(const Utils::Store &data) final; @@ -41,6 +40,8 @@ public: ProjectExplorer::Toolchains autoDetect(const ProjectExplorer::ToolchainDetector &detector) const final; ProjectExplorer::Toolchains detectForImport(const ProjectExplorer::ToolchainDescription &tcd) const final; + std::unique_ptr<ProjectExplorer::ToolchainConfigWidget> createConfigurationWidget( + const ProjectExplorer::ToolchainBundle &bundle) const final; }; } // Nim diff --git a/src/plugins/projectexplorer/customtoolchain.cpp b/src/plugins/projectexplorer/customtoolchain.cpp index bb92eeb027d..5680e823227 100644 --- a/src/plugins/projectexplorer/customtoolchain.cpp +++ b/src/plugins/projectexplorer/customtoolchain.cpp @@ -6,6 +6,7 @@ #include "abiwidget.h" #include "gccparser.h" #include "clangparser.h" +#include "gcctoolchain.h" #include "linuxiccparser.h" #include "msvcparser.h" #include "customparser.h" @@ -80,8 +81,6 @@ public: void toMap(Store &data) const override; void fromMap(const Store &data) override; - std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget() override; - bool operator ==(const Toolchain &) const override; void setMakeCommand(const FilePath &); @@ -385,7 +384,7 @@ public: class CustomToolchainConfigWidget final : public ToolchainConfigWidget { public: - explicit CustomToolchainConfigWidget(CustomToolchain *); + explicit CustomToolchainConfigWidget(const ToolchainBundle &bundle); private: void updateSummaries(TextEditDetailsWidget *detailsWidget); @@ -398,7 +397,6 @@ private: void setFromToolchain(); - PathChooser *m_compilerCommand; PathChooser *m_makeCommand; AbiWidget *m_abiWidget; QPlainTextEdit *m_predefinedMacros; @@ -410,9 +408,8 @@ private: QComboBox *m_errorParserComboBox; }; -CustomToolchainConfigWidget::CustomToolchainConfigWidget(CustomToolchain *tc) : - ToolchainConfigWidget(tc), - m_compilerCommand(new PathChooser), +CustomToolchainConfigWidget::CustomToolchainConfigWidget(const ToolchainBundle &bundle) : + ToolchainConfigWidget(bundle), m_makeCommand(new PathChooser), m_abiWidget(new AbiWidget), m_predefinedMacros(new QPlainTextEdit), @@ -423,8 +420,6 @@ CustomToolchainConfigWidget::CustomToolchainConfigWidget(CustomToolchain *tc) : m_mkspecs(new QLineEdit), m_errorParserComboBox(new QComboBox) { - Q_ASSERT(tc); - const QList<CustomToolchain::Parser> parsers = CustomToolchain::parsers(); for (const auto &parser : parsers) m_errorParserComboBox->addItem(parser.displayName, parser.parserId.toString()); @@ -441,11 +436,8 @@ CustomToolchainConfigWidget::CustomToolchainConfigWidget(CustomToolchain *tc) : m_headerPaths->setToolTip(Tr::tr("Each line adds a global header lookup path.")); m_cxx11Flags->setToolTip(Tr::tr("Comma-separated list of flags that turn on C++11 support.")); m_mkspecs->setToolTip(Tr::tr("Comma-separated list of mkspecs.")); - m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand); - m_compilerCommand->setHistoryCompleter("PE.ToolChainCommand.History"); m_makeCommand->setExpectedKind(PathChooser::ExistingCommand); m_makeCommand->setHistoryCompleter("PE.MakeCommand.History"); - m_mainLayout->addRow(Tr::tr("&Compiler path:"), m_compilerCommand); m_mainLayout->addRow(Tr::tr("&Make path:"), m_makeCommand); m_mainLayout->addRow(Tr::tr("&ABI:"), m_abiWidget); m_mainLayout->addRow(Tr::tr("&Predefined macros:"), m_predefinedDetails); @@ -460,7 +452,6 @@ CustomToolchainConfigWidget::CustomToolchainConfigWidget(CustomToolchain *tc) : m_predefinedDetails->updateSummaryText(); m_headerDetails->updateSummaryText(); - connect(m_compilerCommand, &PathChooser::rawPathChanged, this, &ToolchainConfigWidget::dirty); connect(m_makeCommand, &PathChooser::rawPathChanged, this, &ToolchainConfigWidget::dirty); connect(m_abiWidget, &AbiWidget::abiChanged, this, &ToolchainConfigWidget::dirty); connect(m_predefinedMacros, &QPlainTextEdit::textChanged, @@ -487,62 +478,59 @@ void CustomToolchainConfigWidget::errorParserChanged(int ) void CustomToolchainConfigWidget::applyImpl() { - if (toolchain()->isAutoDetected()) + if (bundle().isAutoDetected()) return; - auto tc = static_cast<CustomToolchain *>(toolchain()); - Q_ASSERT(tc); - QString displayName = tc->displayName(); - tc->setCompilerCommand(m_compilerCommand->filePath()); - tc->setMakeCommand(m_makeCommand->filePath()); - tc->setTargetAbi(m_abiWidget->currentAbi()); - Macros macros = Utils::transform<QVector>( - m_predefinedDetails->text().split('\n', Qt::SkipEmptyParts), - [](const QString &m) { - return Macro::fromKeyValue(m); + bundle().setTargetAbi(m_abiWidget->currentAbi()); + const Macros macros = Utils::transform<QVector>( + m_predefinedDetails->text().split('\n', Qt::SkipEmptyParts), + [](const QString &m) { + return Macro::fromKeyValue(m); + }); + bundle().forEach<CustomToolchain>([&](CustomToolchain &tc) { + tc.setMakeCommand(m_makeCommand->filePath()); + tc.setPredefinedMacros(macros); + tc.setHeaderPaths(m_headerDetails->entries()); + tc.setCxx11Flags(m_cxx11Flags->text().split(QLatin1Char(','))); + tc.setMkspecs(m_mkspecs->text()); + tc.setOutputParserId(Id::fromSetting(m_errorParserComboBox->currentData())); }); - tc->setPredefinedMacros(macros); - tc->setHeaderPaths(m_headerDetails->entries()); - tc->setCxx11Flags(m_cxx11Flags->text().split(QLatin1Char(','))); - tc->setMkspecs(m_mkspecs->text()); - tc->setDisplayName(displayName); // reset display name - tc->setOutputParserId(Id::fromSetting(m_errorParserComboBox->currentData())); - setFromToolchain(); // Refresh with actual data from the toolchain. This shows what e.g. the - // macro parser did with the input. + // Refresh with actual data from the toolchain. This shows what e.g. the + // macro parser did with the input. + setFromToolchain(); } void CustomToolchainConfigWidget::setFromToolchain() { // subwidgets are not yet connected! QSignalBlocker blocker(this); - auto tc = static_cast<CustomToolchain *>(toolchain()); - m_compilerCommand->setFilePath(tc->compilerCommand()); - m_makeCommand->setFilePath(tc->makeCommand(Environment())); - m_abiWidget->setAbis(Abis(), tc->targetAbi()); - const QStringList macroLines = Utils::transform<QList>(tc->rawPredefinedMacros(), [](const Macro &m) { - return QString::fromUtf8(m.toKeyValue(QByteArray())); - }); + m_makeCommand->setFilePath(bundle().makeCommand(Environment())); + m_abiWidget->setAbis(Abis(), bundle().targetAbi()); + const QStringList macroLines = Utils::transform<QList>( + bundle().get(&CustomToolchain::rawPredefinedMacros), + [](const Macro &m) { return QString::fromUtf8(m.toKeyValue(QByteArray())); }); m_predefinedMacros->setPlainText(macroLines.join('\n')); - m_headerPaths->setPlainText(tc->headerPathsList().join('\n')); - m_cxx11Flags->setText(tc->cxx11Flags().join(QLatin1Char(','))); - m_mkspecs->setText(tc->mkspecs()); - int index = m_errorParserComboBox->findData(tc->outputParserId().toSetting()); + m_headerPaths->setPlainText(bundle().get(&CustomToolchain::headerPathsList).join('\n')); + m_cxx11Flags->setText(bundle().get(&CustomToolchain::cxx11Flags).join(QLatin1Char(','))); + m_mkspecs->setText(bundle().get(&CustomToolchain::mkspecs)); + const int index = m_errorParserComboBox->findData( + bundle().get(&CustomToolchain::outputParserId).toSetting()); m_errorParserComboBox->setCurrentIndex(index); } bool CustomToolchainConfigWidget::isDirtyImpl() const { - auto tc = static_cast<CustomToolchain *>(toolchain()); - Q_ASSERT(tc); - return m_compilerCommand->filePath() != tc->compilerCommand() - || m_makeCommand->filePath().toString() != tc->makeCommand(Environment()).toString() - || m_abiWidget->currentAbi() != tc->targetAbi() - || Macro::toMacros(m_predefinedDetails->text().toUtf8()) != tc->rawPredefinedMacros() - || m_headerDetails->entries() != tc->headerPathsList() - || m_cxx11Flags->text().split(QLatin1Char(',')) != tc->cxx11Flags() - || m_mkspecs->text() != tc->mkspecs() - || Id::fromSetting(m_errorParserComboBox->currentData()) == tc->outputParserId(); + return m_makeCommand->filePath() != bundle().makeCommand({}) + || m_abiWidget->currentAbi() != bundle().targetAbi() + || Macro::toMacros(m_predefinedDetails->text().toUtf8()) + != bundle().get(&CustomToolchain::rawPredefinedMacros) + || m_headerDetails->entries() != bundle().get(&CustomToolchain::headerPathsList) + || m_cxx11Flags->text().split(QLatin1Char(',')) + != bundle().get(&CustomToolchain::cxx11Flags) + || m_mkspecs->text() != bundle().get(&CustomToolchain::mkspecs) + || Id::fromSetting(m_errorParserComboBox->currentData()) + == bundle().get(&CustomToolchain::outputParserId); } void CustomToolchainConfigWidget::makeReadOnlyImpl() @@ -550,11 +538,6 @@ void CustomToolchainConfigWidget::makeReadOnlyImpl() m_mainLayout->setEnabled(false); } -std::unique_ptr<ToolchainConfigWidget> CustomToolchain::createConfigurationWidget() -{ - return std::make_unique<CustomToolchainConfigWidget>(this); -} - // CustomToolchainFactory class CustomToolchainFactory final : public ToolchainFactory @@ -568,6 +551,27 @@ public: setToolchainConstructor([] { return new CustomToolchain; }); setUserCreatable(true); } + +private: + std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget( + const ToolchainBundle &bundle) const override + { + return std::make_unique<CustomToolchainConfigWidget>(bundle); + } + + FilePath correspondingCompilerCommand(const FilePath &srcPath, Id targetLang) const override + { + static const std::pair<QString, QString> patternPairs[] + = {{"gcc", "g++"}, {"clang", "clang++"}, {"icc", "icpc"}}; + for (const auto &[cPattern, cxxPattern] : patternPairs) { + if (const FilePath &targetPath = GccToolchain::correspondingCompilerCommand( + srcPath, targetLang, cPattern, cxxPattern); + targetPath != srcPath) { + return targetPath; + } + } + return srcPath; + } }; void setupCustomToolchain() diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index d3a74b5fa50..4a19b2cbf5c 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -107,10 +107,10 @@ class TargetTripleWidget; class GccToolchainConfigWidget : public ToolchainConfigWidget { public: - explicit GccToolchainConfigWidget(GccToolchain *tc); + explicit GccToolchainConfigWidget(const ToolchainBundle &bundle); private: - void handleCompilerCommandChange(); + void handleCompilerCommandChange(Id language); void handlePlatformCodeGenFlagsChange(); void handlePlatformLinkerFlagsChange(); @@ -122,12 +122,13 @@ private: void setFromToolchain(); void updateParentToolchainComboBox(); // Clang + Id bundleIdFromId(const QByteArray &parentId); + Toolchain *toolchainFromBundleId(Id bundleId, Id language); AbiWidget *m_abiWidget; GccToolchain::SubType m_subType = GccToolchain::RealGcc; - PathChooser *m_compilerCommand; QLineEdit *m_platformCodeGenFlagsLineEdit; QLineEdit *m_platformLinkerFlagsLineEdit; TargetTripleWidget * const m_targetTripleWidget; @@ -385,6 +386,12 @@ GccToolchain::~GccToolchain() } } +std::unique_ptr<ToolchainConfigWidget> GccToolchain::createConfigurationWidget( + const ToolchainBundle &bundle) +{ + return std::make_unique<GccToolchainConfigWidget>(bundle); +} + void GccToolchain::setSupportedAbis(const Abis &abis) { if (m_supportedAbis == abis) @@ -403,6 +410,20 @@ void GccToolchain::setOriginalTargetTriple(const QString &targetTriple) toolChainUpdated(); } +FilePath GccToolchain::correspondingCompilerCommand( + const Utils::FilePath &srcPath, + Utils::Id targetLang, + const QString &cPattern, + const QString &cxxPattern) +{ + QString outFileName = srcPath.fileName(); + if (targetLang == Constants::CXX_LANGUAGE_ID) + outFileName.replace(cPattern, cxxPattern); + else + outFileName.replace(cxxPattern, cPattern); + return srcPath.parentDir().pathAppended(outFileName); +} + void GccToolchain::setInstallDir(const FilePath &installDir) { if (m_installDir == installDir) @@ -1067,11 +1088,6 @@ bool GccToolchain::operator ==(const Toolchain &other) const && m_platformLinkerFlags == gccTc->m_platformLinkerFlags; } -std::unique_ptr<ToolchainConfigWidget> GccToolchain::createConfigurationWidget() -{ - return std::make_unique<GccToolchainConfigWidget>(this); -} - void GccToolchain::updateSupportedAbis() const { if (m_supportedAbis.isEmpty()) { @@ -1315,6 +1331,9 @@ public: Toolchains autoDetect(const ToolchainDetector &detector) const final; Toolchains detectForImport(const ToolchainDescription &tcd) const final; + std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget( + const ToolchainBundle &bundle) const final; + FilePath correspondingCompilerCommand(const FilePath &srcPath, Id targetLang) const final; private: static Toolchains autoDetectToolchains(const FilePaths &compilerPaths, @@ -1558,6 +1577,26 @@ Toolchains GccToolchainFactory::detectForImport(const ToolchainDescription &tcd) return result; } +std::unique_ptr<ToolchainConfigWidget> GccToolchainFactory::createConfigurationWidget( + const ToolchainBundle &bundle) const +{ + return GccToolchain::createConfigurationWidget(bundle); +} + +FilePath GccToolchainFactory::correspondingCompilerCommand( + const FilePath &srcPath, Id targetLang) const +{ + if (supportedToolchainType() == Constants::GCC_TOOLCHAIN_TYPEID + || supportedToolchainType() == Constants::MINGW_TOOLCHAIN_TYPEID) { + return GccToolchain::correspondingCompilerCommand(srcPath, targetLang, "gcc", "g++"); + } + if (supportedToolchainType() == Constants::CLANG_TOOLCHAIN_TYPEID) + return GccToolchain::correspondingCompilerCommand(srcPath, targetLang, "clang", "clang++"); + if (supportedToolchainType() == Constants::LINUXICC_TOOLCHAIN_TYPEID) + return GccToolchain::correspondingCompilerCommand(srcPath, targetLang, "icc", "icpc"); + return {}; +} + Toolchains GccToolchainFactory::autoDetectSdkClangToolchain(const Toolchains &known) { const FilePath compilerPath = Core::ICore::clangExecutable(CLANG_BINDIR); @@ -1678,7 +1717,7 @@ class TargetTripleWidget : public QWidget Q_OBJECT public: - TargetTripleWidget(const Toolchain *toolchain) + TargetTripleWidget(const ToolchainBundle &bundle) { const auto layout = new QHBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); @@ -1694,8 +1733,8 @@ public: connect(&m_overrideCheckBox, &QCheckBox::toggled, &m_tripleLineEdit, &QLineEdit::setEnabled); - m_tripleLineEdit.setText(toolchain->effectiveCodeModelTargetTriple()); - m_overrideCheckBox.setChecked(!toolchain->explicitCodeModelTargetTriple().isEmpty()); + m_tripleLineEdit.setText(bundle.get(&Toolchain::effectiveCodeModelTargetTriple)); + m_overrideCheckBox.setChecked(!bundle.get(&Toolchain::explicitCodeModelTargetTriple).isEmpty()); } QString explicitCodeModelTargetTriple() const @@ -1714,24 +1753,18 @@ private: }; } -GccToolchainConfigWidget::GccToolchainConfigWidget(GccToolchain *tc) : - ToolchainConfigWidget(tc), +GccToolchainConfigWidget::GccToolchainConfigWidget(const ToolchainBundle &bundle) : + ToolchainConfigWidget(bundle), m_abiWidget(new AbiWidget), - m_subType(tc->m_subType), - m_compilerCommand(new PathChooser), - m_targetTripleWidget(new TargetTripleWidget(tc)) -{ - const QStringList gnuVersionArgs = QStringList("--version"); - m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand); - m_compilerCommand->setCommandVersionArguments(gnuVersionArgs); - m_compilerCommand->setHistoryCompleter("PE.Gcc.Command.History"); - m_compilerCommand->setAllowPathFromDevice(true); - m_mainLayout->addRow(Tr::tr("&Compiler path:"), m_compilerCommand); + m_subType(bundle.get(&GccToolchain::subType)), + m_targetTripleWidget(new TargetTripleWidget(bundle)) +{ + setCommandVersionArguments({"--version"}); m_platformCodeGenFlagsLineEdit = new QLineEdit(this); - m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->platformCodeGenFlags())); + m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(bundle.extraCodeModelFlags())); m_mainLayout->addRow(Tr::tr("Platform codegen flags:"), m_platformCodeGenFlagsLineEdit); m_platformLinkerFlagsLineEdit = new QLineEdit(this); - m_platformLinkerFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->platformLinkerFlags())); + m_platformLinkerFlagsLineEdit->setText(ProcessArgs::joinArgs(bundle.get(&GccToolchain::platformLinkerFlags))); m_mainLayout->addRow(Tr::tr("Platform linker flags:"), m_platformLinkerFlagsLineEdit); m_mainLayout->addRow(Tr::tr("&ABI:"), m_abiWidget); m_mainLayout->addRow(Tr::tr("Target triple:"), m_targetTripleWidget); @@ -1741,7 +1774,7 @@ GccToolchainConfigWidget::GccToolchainConfigWidget(GccToolchain *tc) : setFromToolchain(); - connect(m_compilerCommand, &PathChooser::rawPathChanged, + connect(this, &ToolchainConfigWidget::compilerCommandChanged, this, &GccToolchainConfigWidget::handleCompilerCommandChange); connect(m_platformCodeGenFlagsLineEdit, &QLineEdit::editingFinished, this, &GccToolchainConfigWidget::handlePlatformCodeGenFlagsChange); @@ -1752,7 +1785,7 @@ GccToolchainConfigWidget::GccToolchainConfigWidget(GccToolchain *tc) : this, &ToolchainConfigWidget::dirty); if (m_subType == GccToolchain::Clang) { - if (!HostOsInfo::isWindowsHost() || tc->typeId() != Constants::CLANG_TOOLCHAIN_TYPEID) + if (!HostOsInfo::isWindowsHost() || bundle.type() != Constants::CLANG_TOOLCHAIN_TYPEID) return; // Remove m_abiWidget row because the parent toolchain abi is going to be used. @@ -1760,6 +1793,8 @@ GccToolchainConfigWidget::GccToolchainConfigWidget(GccToolchain *tc) : m_abiWidget = nullptr; m_parentToolchainCombo = new QComboBox(this); + connect(m_parentToolchainCombo, &QComboBox::currentIndexChanged, + this, &ToolchainConfigWidget::dirty); m_mainLayout->insertRow(m_mainLayout->rowCount() - 1, Tr::tr("Parent toolchain:"), m_parentToolchainCombo); @@ -1779,12 +1814,13 @@ GccToolchainConfigWidget::GccToolchainConfigWidget(GccToolchain *tc) : updateParentToolchainComboBox(); } })); - m_parentToolchainConnections.append( - connect(tcManager, &ToolchainManager::toolchainsDeregistered, this, - [this](const Toolchains &toolchains) { + m_parentToolchainConnections.append(connect( + tcManager, &ToolchainManager::toolchainsDeregistered, this, [this, bundle](const Toolchains &toolchains) { bool updateParentComboBox = false; for (Toolchain * const tc : toolchains) { - if (tc->id() == toolchain()->id()) { + if (Utils::contains(bundle.toolchains(), [tc](const Toolchain *elem) { + return elem->id() == tc->id(); + })) { for (QMetaObject::Connection &connection : m_parentToolchainConnections) QObject::disconnect(connection); return; @@ -1795,71 +1831,60 @@ GccToolchainConfigWidget::GccToolchainConfigWidget(GccToolchain *tc) : if (updateParentComboBox) updateParentToolchainComboBox(); })); - updateParentToolchainComboBox(); } } void GccToolchainConfigWidget::applyImpl() { - if (toolchain()->isAutoDetected()) + if (bundle().isAutoDetected()) return; - auto tc = static_cast<GccToolchain *>(toolchain()); - Q_ASSERT(tc); - QString displayName = tc->displayName(); - tc->setCompilerCommand(m_compilerCommand->filePath()); - if (m_abiWidget) { - tc->setSupportedAbis(m_abiWidget->supportedAbis()); - tc->setTargetAbi(m_abiWidget->currentAbi()); - } - tc->setInstallDir(tc->detectInstallDir()); - tc->setOriginalTargetTriple(tc->detectSupportedAbis().originalTargetTriple); - tc->setExplicitCodeModelTargetTriple(m_targetTripleWidget->explicitCodeModelTargetTriple()); - tc->setDisplayName(displayName); // reset display name - tc->setPlatformCodeGenFlags(splitString(m_platformCodeGenFlagsLineEdit->text())); - tc->setPlatformLinkerFlags(splitString(m_platformLinkerFlagsLineEdit->text())); - - if (m_macros.isEmpty()) - return; - - tc->predefinedMacrosCache() - ->insert(tc->platformCodeGenFlags(), - Toolchain::MacroInspectionReport{m_macros, - Toolchain::languageVersion(tc->language(), - m_macros)}); - - if (m_subType == GccToolchain::Clang && m_parentToolchainCombo) { - - tc->m_parentToolchainId.clear(); - - const QByteArray parentId = m_parentToolchainCombo->currentData().toByteArray(); - if (!parentId.isEmpty()) { - for (const Toolchain *mingwTC : mingwToolchains()) { - if (parentId == mingwTC->id()) { - tc->m_parentToolchainId = mingwTC->id(); - tc->setTargetAbi(mingwTC->targetAbi()); - tc->setSupportedAbis(mingwTC->supportedAbis()); - break; - } + const Id parentBundleId = m_parentToolchainCombo + ? Id::fromSetting(m_parentToolchainCombo->currentData()) + : Id(); + bundle().forEach<GccToolchain>([&](GccToolchain &tc) { + tc.setCompilerCommand(compilerCommand(tc.language())); + if (m_abiWidget) { + tc.setSupportedAbis(m_abiWidget->supportedAbis()); + tc.setTargetAbi(m_abiWidget->currentAbi()); + } + tc.setInstallDir(tc.detectInstallDir()); + tc.setOriginalTargetTriple(tc.detectSupportedAbis().originalTargetTriple); + tc.setExplicitCodeModelTargetTriple(m_targetTripleWidget->explicitCodeModelTargetTriple()); + tc.setPlatformCodeGenFlags(splitString(m_platformCodeGenFlagsLineEdit->text())); + tc.setPlatformLinkerFlags(splitString(m_platformLinkerFlagsLineEdit->text())); + + tc.m_parentToolchainId.clear(); + if (parentBundleId.isValid()) { + if (const Toolchain * const parentTc + = toolchainFromBundleId(parentBundleId, tc.language())) { + tc.m_parentToolchainId = parentTc->id(); + tc.setTargetAbi(parentTc->targetAbi()); + tc.setSupportedAbis(parentTc->supportedAbis()); } } - } + + if (!m_macros.isEmpty()) { + tc.predefinedMacrosCache()->insert( + tc.platformCodeGenFlags(), + Toolchain::MacroInspectionReport{m_macros, Toolchain::languageVersion( + tc.language(), m_macros)}); + } + }); } void GccToolchainConfigWidget::setFromToolchain() { // subwidgets are not yet connected! QSignalBlocker blocker(this); - auto tc = static_cast<GccToolchain *>(toolchain()); - m_compilerCommand->setFilePath(tc->compilerCommand()); - m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->platformCodeGenFlags(), - HostOsInfo::hostOs())); - m_platformLinkerFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->platformLinkerFlags(), - HostOsInfo::hostOs())); + m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs( + bundle().get(&GccToolchain::platformCodeGenFlags), HostOsInfo::hostOs())); + m_platformLinkerFlagsLineEdit->setText( + ProcessArgs::joinArgs(bundle().get(&GccToolchain::platformLinkerFlags), HostOsInfo::hostOs())); if (m_abiWidget) { - m_abiWidget->setAbis(tc->supportedAbis(), tc->targetAbi()); - if (!m_isReadOnly && !m_compilerCommand->filePath().toString().isEmpty()) + m_abiWidget->setAbis(bundle().supportedAbis(), bundle().targetAbi()); + if (!m_isReadOnly && hasAnyCompiler()) m_abiWidget->setEnabled(true); } @@ -1869,30 +1894,25 @@ void GccToolchainConfigWidget::setFromToolchain() bool GccToolchainConfigWidget::isDirtyImpl() const { - auto tc = static_cast<GccToolchain *>(toolchain()); - - if (m_compilerCommand->filePath() != tc->compilerCommand() - || m_platformCodeGenFlagsLineEdit->text() - != ProcessArgs::joinArgs(tc->platformCodeGenFlags()) - || m_platformLinkerFlagsLineEdit->text() - != ProcessArgs::joinArgs(tc->platformLinkerFlags()) - || m_targetTripleWidget->explicitCodeModelTargetTriple() - != tc->explicitCodeModelTargetTriple() - || (m_abiWidget && m_abiWidget->currentAbi() != tc->targetAbi())) { + if (m_platformCodeGenFlagsLineEdit->text() != ProcessArgs::joinArgs(bundle().get(&GccToolchain::platformCodeGenFlags)) + || m_platformLinkerFlagsLineEdit->text() != ProcessArgs::joinArgs(bundle().get(&GccToolchain::platformLinkerFlags)) + || m_targetTripleWidget->explicitCodeModelTargetTriple() + != bundle().get(&GccToolchain::explicitCodeModelTargetTriple) + || (m_abiWidget && m_abiWidget->currentAbi() != bundle().targetAbi())) { return true; } if (!m_parentToolchainCombo) return false; - const GccToolchain *parentTC = mingwToolchainFromId(tc->m_parentToolchainId); - const QByteArray parentId = parentTC ? parentTC->id() : QByteArray(); - return parentId != m_parentToolchainCombo->currentData(); + const GccToolchain *parentTC = mingwToolchainFromId( + bundle().get(&GccToolchain::parentToolchainId)); + const Id parentBundleId = parentTC ? parentTC->bundleId() : Id(); + return parentBundleId.toSetting() != m_parentToolchainCombo->currentData(); } void GccToolchainConfigWidget::makeReadOnlyImpl() { - m_compilerCommand->setReadOnly(true); if (m_abiWidget) m_abiWidget->setEnabled(false); m_platformCodeGenFlagsLineEdit->setEnabled(false); @@ -1904,7 +1924,7 @@ void GccToolchainConfigWidget::makeReadOnlyImpl() m_parentToolchainCombo->setEnabled(false); } -void GccToolchainConfigWidget::handleCompilerCommandChange() +void GccToolchainConfigWidget::handleCompilerCommandChange(Id language) { if (!m_abiWidget) return; @@ -1912,7 +1932,7 @@ void GccToolchainConfigWidget::handleCompilerCommandChange() bool haveCompiler = false; Abi currentAbi = m_abiWidget->currentAbi(); bool customAbi = m_abiWidget->isCustomAbi() && m_abiWidget->isEnabled(); - FilePath path = m_compilerCommand->filePath(); + FilePath path = compilerCommand(language); Abis abiList; if (!path.isEmpty()) { @@ -1946,7 +1966,7 @@ void GccToolchainConfigWidget::handlePlatformCodeGenFlagsChange() if (str1 != str2) m_platformCodeGenFlagsLineEdit->setText(str2); else - handleCompilerCommandChange(); + handleCompilerCommandChange(Constants::C_LANGUAGE_ID); } void GccToolchainConfigWidget::handlePlatformLinkerFlagsChange() @@ -2011,8 +2031,10 @@ void GccToolchain::syncAutodetectedWithParentToolchains() if (tc == this) { QObject::disconnect(m_thisToolchainRemovedConnection); QObject::disconnect(m_mingwToolchainAddedConnection); + break; } else if (m_parentToolchainId == tc->id()) { updateParentId = true; + break; } } if (updateParentId) { @@ -2056,33 +2078,57 @@ QString GccToolchain::sysRoot() const return {}; } +bool GccToolchain::canShareBundleImpl(const Toolchain &other) const +{ + return platformLinkerFlags() == static_cast<const GccToolchain &>(other).platformLinkerFlags(); +} + void GccToolchainConfigWidget::updateParentToolchainComboBox() { QTC_ASSERT(m_parentToolchainCombo, return); - auto *tc = static_cast<GccToolchain *>(toolchain()); - QByteArray parentId = m_parentToolchainCombo->currentData().toByteArray(); - if (tc->isAutoDetected() || m_parentToolchainCombo->count() == 0) - parentId = tc->m_parentToolchainId; - - const GccToolchain *parentTC = mingwToolchainFromId(parentId); + Id parentBundleId = Id::fromSetting(m_parentToolchainCombo->currentData()); + if (bundle().isAutoDetected() || m_parentToolchainCombo->count() == 0) + parentBundleId = bundleIdFromId(bundle().get(&GccToolchain::parentToolchainId)); + const QList<ToolchainBundle> mingwBundles + = Utils::filtered(ToolchainBundle::collectBundles(), [](const ToolchainBundle &b) { + return b.type() == Constants::MINGW_TOOLCHAIN_TYPEID; + }); + const auto parentBundle + = Utils::findOr(mingwBundles, std::nullopt, [parentBundleId](const ToolchainBundle &b) { + return b.bundleId() == parentBundleId; + }); m_parentToolchainCombo->clear(); - m_parentToolchainCombo->addItem(parentTC ? parentTC->displayName() : QString(), - parentTC ? parentId : QByteArray()); + m_parentToolchainCombo->addItem(parentBundle ? parentBundle->displayName() : QString(), + parentBundle ? parentBundleId.toSetting() : QVariant()); - if (tc->isAutoDetected()) + if (bundle().isAutoDetected()) return; - for (const Toolchain *mingwTC : mingwToolchains()) { - if (mingwTC->id() == parentId) - continue; - if (mingwTC->language() != tc->language()) - continue; - m_parentToolchainCombo->addItem(mingwTC->displayName(), mingwTC->id()); + for (const ToolchainBundle &mingwBundle : mingwBundles) { + if (mingwBundle.bundleId() != parentBundleId) { + m_parentToolchainCombo + ->addItem(mingwBundle.displayName(), mingwBundle.bundleId().toSetting()); + } } } +Id GccToolchainConfigWidget::bundleIdFromId(const QByteArray &id) +{ + const Toolchain * const tc = ToolchainManager::toolchain( + [id](const Toolchain *tc) { return tc->id() == id; }); + return tc ? tc->bundleId() : Id(); +} + +Toolchain *GccToolchainConfigWidget::toolchainFromBundleId(Id bundleId, Id language) +{ + return ToolchainManager::toolchain( + [bundleId, language](const Toolchain *tc) { + return tc->bundleId() == bundleId && tc->language() == language; + }); +} + } // namespace ProjectExplorer // Unit tests: diff --git a/src/plugins/projectexplorer/gcctoolchain.h b/src/plugins/projectexplorer/gcctoolchain.h index 7f870cc603f..7dc1ccfaf5e 100644 --- a/src/plugins/projectexplorer/gcctoolchain.h +++ b/src/plugins/projectexplorer/gcctoolchain.h @@ -10,7 +10,6 @@ #include "headerpath.h" #include <functional> -#include <memory> #include <optional> namespace ProjectExplorer { @@ -34,6 +33,9 @@ public: GccToolchain(Utils::Id typeId, SubType subType = RealGcc); ~GccToolchain() override; + static std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget( + const ToolchainBundle &bundle); + QString originalTargetTriple() const override; Utils::FilePath installDir() const override; QString version() const; @@ -55,8 +57,6 @@ public: void toMap(Utils::Store &data) const override; void fromMap(const Utils::Store &data) override; - std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget() override; - bool operator ==(const Toolchain &) const override; void resetToolchain(const Utils::FilePath &); @@ -86,12 +86,19 @@ public: void setPriority(int priority) { m_priority = priority; } void setOriginalTargetTriple(const QString &targetTriple); + static Utils::FilePath correspondingCompilerCommand( + const Utils::FilePath &srcPath, + Utils::Id targetLang, + const QString &cPattern, + const QString &cxxPattern); + protected: using CacheItem = QPair<QStringList, Macros>; using GccCache = QVector<CacheItem>; void setSupportedAbis(const Abis &abis); void setInstallDir(const Utils::FilePath &installDir); + void setMacroCache(const QStringList &allCxxflags, const Macros ¯oCache) const; Macros macroCache(const QStringList &allCxxflags) const; @@ -113,8 +120,12 @@ protected: int priority() const override { return m_priority; } QString sysRoot() const override; + SubType subType() const { return m_subType; } + QByteArray parentToolchainId() const { return m_parentToolchainId; } private: + bool canShareBundleImpl(const Toolchain &other) const override; + void syncAutodetectedWithParentToolchains(); void updateSupportedAbis() const; diff --git a/src/plugins/projectexplorer/kitaspects.cpp b/src/plugins/projectexplorer/kitaspects.cpp index 450edb5084d..b0a99951b70 100644 --- a/src/plugins/projectexplorer/kitaspects.cpp +++ b/src/plugins/projectexplorer/kitaspects.cpp @@ -205,25 +205,28 @@ public: layout->setContentsMargins(0, 0, 0, 0); layout->setColumnStretch(1, 2); - const QList<Id> languageList = sorted(ToolchainManager::allLanguages(), [](Id l1, Id l2) { - return ToolchainManager::displayNameOfLanguageId(l1) - < ToolchainManager::displayNameOfLanguageId(l2); - }); - QTC_ASSERT(!languageList.isEmpty(), return); + const QList<LanguageCategory> languageCategories = sorted( + ToolchainManager::languageCategories(), + [](const LanguageCategory &l1, const LanguageCategory &l2) { + return ToolchainManager::displayNameOfLanguageCategory(l1) + < ToolchainManager::displayNameOfLanguageCategory(l2); + }); + QTC_ASSERT(!languageCategories.isEmpty(), return); int row = 0; - for (Id l : std::as_const(languageList)) { - layout->addWidget(new QLabel(ToolchainManager::displayNameOfLanguageId(l) + ':'), row, 0); + for (const LanguageCategory &lc : std::as_const(languageCategories)) { + layout->addWidget( + new QLabel(ToolchainManager::displayNameOfLanguageCategory(lc) + ':'), row, 0); auto cb = new QComboBox; cb->setSizePolicy(QSizePolicy::Ignored, cb->sizePolicy().verticalPolicy()); cb->setToolTip(factory->description()); setWheelScrollingWithoutFocusBlocked(cb); - m_languageComboboxMap.insert(l, cb); + m_languageComboboxMap.insert(lc, cb); layout->addWidget(cb, row, 1); ++row; - connect(cb, &QComboBox::currentIndexChanged, this, [this, l](int idx) { - currentToolchainChanged(l, idx); + connect(cb, &QComboBox::currentIndexChanged, this, [this, lc](int idx) { + currentToolchainChanged(lc, idx); }); } @@ -250,8 +253,9 @@ private: const GuardLocker locker(m_ignoreChanges); for (auto it = m_languageComboboxMap.cbegin(); it != m_languageComboboxMap.cend(); ++it) { - const Id l = it.key(); - const Toolchains ltcList = ToolchainManager::toolchains(equal(&Toolchain::language, l)); + const LanguageCategory lc = it.key(); + const Toolchains ltcList = ToolchainManager::toolchains( + [lc](const Toolchain *tc) { return lc.contains(tc->language()); }); QComboBox *cb = *it; cb->clear(); @@ -264,18 +268,36 @@ private: return !tc->compilerCommand().isSameDevice(device->rootPath()); }); - for (Toolchain *item : same) - cb->addItem(item->displayName(), item->id()); + const QList<ToolchainBundle> sameBundles = ToolchainBundle::collectBundles(same); + const QList<ToolchainBundle> otherBundles = ToolchainBundle::collectBundles(other); + for (const ToolchainBundle &b : sameBundles) + cb->addItem(b.displayName(), b.bundleId().toSetting()); - if (!same.isEmpty() && !other.isEmpty()) + if (!sameBundles.isEmpty() && !otherBundles.isEmpty()) cb->insertSeparator(cb->count()); - for (Toolchain *item : other) - cb->addItem(item->displayName(), item->id()); + for (const ToolchainBundle &b : otherBundles) + cb->addItem(b.displayName(), b.bundleId().toSetting()); cb->setEnabled(cb->count() > 1 && !m_isReadOnly); - const int index = indexOf(cb, ToolchainKitAspect::toolchain(m_kit, l)); - cb->setCurrentIndex(index); + Id currentBundleId; + for (const Id lang : lc) { + Toolchain * const currentTc = ToolchainKitAspect::toolchain(m_kit, lang); + if (!currentTc) + continue; + for (const QList<ToolchainBundle> &bundles : {sameBundles, otherBundles}) + for (const ToolchainBundle &b : bundles) { + if (b.bundleId() == currentTc->bundleId()) { + currentBundleId = b.bundleId(); + break; + } + if (currentBundleId.isValid()) + break; + } + if (currentBundleId.isValid()) + break; + } + cb->setCurrentIndex(currentBundleId.isValid() ? indexOf(cb, currentBundleId) : -1); } } @@ -286,32 +308,37 @@ private: cb->setEnabled(false); } - void currentToolchainChanged(Id language, int idx) + void currentToolchainChanged(const LanguageCategory &languageCategory, int idx) { if (m_ignoreChanges.isLocked() || idx < 0) return; - const QByteArray id = m_languageComboboxMap.value(language)->itemData(idx).toByteArray(); - Toolchain *tc = ToolchainManager::findToolchain(id); - QTC_ASSERT(!tc || tc->language() == language, return); - if (tc) - ToolchainKitAspect::setToolchain(m_kit, tc); - else - ToolchainKitAspect::clearToolchain(m_kit, language); + const Id bundleId = Id::fromSetting( + m_languageComboboxMap.value(languageCategory)->itemData(idx)); + const Toolchains bundleTcs = ToolchainManager::toolchains( + [bundleId](const Toolchain *tc) { return tc->bundleId() == bundleId; }); + for (const Id lang : languageCategory) { + Toolchain *const tc = Utils::findOrDefault(bundleTcs, [lang](const Toolchain *tc) { + return tc->language() == lang; + }); + if (tc) + ToolchainKitAspect::setToolchain(m_kit, tc); + else + ToolchainKitAspect::clearToolchain(m_kit, lang); + } } - int indexOf(QComboBox *cb, const Toolchain *tc) + int indexOf(QComboBox *cb, Id bundleId) { - const QByteArray id = tc ? tc->id() : QByteArray(); for (int i = 0; i < cb->count(); ++i) { - if (id == cb->itemData(i).toByteArray()) + if (bundleId.toSetting() == cb->itemData(i)) return i; } return -1; } QWidget *m_mainWidget = nullptr; - QHash<Id, QComboBox *> m_languageComboboxMap; + QHash<LanguageCategory, QComboBox *> m_languageComboboxMap; Guard m_ignoreChanges; bool m_isReadOnly = false; }; diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index 2aa409b1425..dba9089f797 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -788,6 +788,12 @@ void MsvcToolchain::initEnvModWatcher(const QFuture<GenerateEnvResult> &future) m_envModWatcher.setFuture(future); } +bool MsvcToolchain::canShareBundleImpl(const Toolchain &other) const +{ + const auto &otherMsvc = static_cast<const MsvcToolchain &>(other); + return m_vcvarsBat == otherMsvc.m_vcvarsBat && m_varsBatArg == otherMsvc.m_varsBatArg; +} + void MsvcToolchain::updateEnvironmentModifications(Utils::EnvironmentItems modifications) { Utils::EnvironmentItem::sort(&modifications); @@ -1183,6 +1189,9 @@ FilePath MsvcToolchain::makeCommand(const Environment &environment) const void MsvcToolchain::rescanForCompiler() { + if (typeId() == Constants::CLANG_CL_TOOLCHAIN_TYPEID) + return; + Utils::Environment env = Utils::Environment::systemEnvironment(); addToEnvironment(env); @@ -1248,11 +1257,16 @@ static QString msvcVarsToDisplay(const MsvcToolchain &tc) return varsBatDisplay; } +static QString msvcVarsToDisplay(const ToolchainBundle &bundle) +{ + return msvcVarsToDisplay(static_cast<const MsvcToolchain &>(*bundle.toolchains().first())); +} + class MsvcBasedToolchainConfigWidget : public ToolchainConfigWidget { public: - explicit MsvcBasedToolchainConfigWidget(Toolchain *tc) - : ToolchainConfigWidget(tc) + explicit MsvcBasedToolchainConfigWidget(const ToolchainBundle &bundle) + : ToolchainConfigWidget(bundle) , m_nameDisplayLabel(new QLabel(this)) , m_varsBatDisplayLabel(new QLabel(this)) { @@ -1270,10 +1284,7 @@ protected: void setFromMsvcToolChain() { - const auto *tc = static_cast<const MsvcToolchain *>(toolchain()); - QTC_ASSERT(tc, return ); - m_nameDisplayLabel->setText(tc->displayName()); - m_varsBatDisplayLabel->setText(msvcVarsToDisplay(*tc)); + m_varsBatDisplayLabel->setText(msvcVarsToDisplay(bundle())); } protected: @@ -1288,8 +1299,8 @@ protected: class MsvcToolchainConfigWidget final : public MsvcBasedToolchainConfigWidget { public: - explicit MsvcToolchainConfigWidget(Toolchain *tc) - : MsvcBasedToolchainConfigWidget(tc) + explicit MsvcToolchainConfigWidget(const ToolchainBundle &bundle) + : MsvcBasedToolchainConfigWidget(bundle) , m_varsBatPathCombo(new QComboBox(this)) , m_varsBatArchCombo(new QComboBox(this)) , m_varsBatArgumentsEdit(new QLineEdit(this)) @@ -1366,10 +1377,8 @@ private: void MsvcToolchainConfigWidget::applyImpl() { - auto *tc = static_cast<MsvcToolchain *>(toolchain()); - QTC_ASSERT(tc, return ); const QString vcVars = QDir::fromNativeSeparators(m_varsBatPathCombo->currentText()); - tc->setupVarsBat(m_abiWidget->currentAbi(), vcVars, vcVarsArguments()); + bundle().set(&MsvcToolchain::setupVarsBat, m_abiWidget->currentAbi(), vcVars, vcVarsArguments()); setFromMsvcToolchain(); } @@ -1380,11 +1389,10 @@ void MsvcToolchainConfigWidget::discardImpl() bool MsvcToolchainConfigWidget::isDirtyImpl() const { - auto msvcToolchain = static_cast<MsvcToolchain *>(toolchain()); - - return msvcToolchain->varsBat() != QDir::fromNativeSeparators(m_varsBatPathCombo->currentText()) - || msvcToolchain->varsBatArg() != vcVarsArguments() - || msvcToolchain->targetAbi() != m_abiWidget->currentAbi(); + return bundle().get(&MsvcToolchain::varsBat) + != QDir::fromNativeSeparators(m_varsBatPathCombo->currentText()) + || bundle().get(&MsvcToolchain::varsBatArg) != vcVarsArguments() + || bundle().get(&MsvcToolchain::targetAbi) != m_abiWidget->currentAbi(); } void MsvcToolchainConfigWidget::makeReadOnlyImpl() @@ -1397,10 +1405,7 @@ void MsvcToolchainConfigWidget::makeReadOnlyImpl() void MsvcToolchainConfigWidget::setFromMsvcToolchain() { - const auto *tc = static_cast<const MsvcToolchain *>(toolchain()); - QTC_ASSERT(tc, return ); - m_nameDisplayLabel->setText(tc->displayName()); - QString args = tc->varsBatArg(); + QString args = bundle().get(&MsvcToolchain::varsBatArg); QStringList argList = args.split(' '); for (int i = 0; i < argList.count(); ++i) { if (m_varsBatArchCombo->findText(argList.at(i).trimmed()) != -1) { @@ -1410,16 +1415,15 @@ void MsvcToolchainConfigWidget::setFromMsvcToolchain() break; } } - m_varsBatPathCombo->setCurrentText(QDir::toNativeSeparators(tc->varsBat())); + m_varsBatPathCombo->setCurrentText( + QDir::toNativeSeparators(bundle().get(&MsvcToolchain::varsBat))); m_varsBatArgumentsEdit->setText(args); - m_abiWidget->setAbis(tc->supportedAbis(), tc->targetAbi()); + m_abiWidget->setAbis(bundle().supportedAbis(), bundle().targetAbi()); } void MsvcToolchainConfigWidget::updateAbis() { const QString normalizedVcVars = QDir::fromNativeSeparators(m_varsBatPathCombo->currentText()); - const auto *currentTc = static_cast<const MsvcToolchain *>(toolchain()); - QTC_ASSERT(currentTc, return ); const MsvcToolchain::Platform platform = m_varsBatArchCombo->currentData().value<MsvcToolchain::Platform>(); const Abi::Architecture arch = archForPlatform(platform); const unsigned char wordWidth = wordWidthForPlatform(platform); @@ -1431,7 +1435,7 @@ void MsvcToolchainConfigWidget::updateAbis() Abi targetAbi; for (const MsvcToolchain *tc : std::as_const(g_availableMsvcToolchains)) { if (tc->varsBat() == normalizedVcVars && tc->targetAbi().wordWidth() == wordWidth - && tc->targetAbi().architecture() == arch && tc->language() == currentTc->language()) { + && tc->targetAbi().architecture() == arch) { // We need to filter out duplicates as there might be multiple toolchains with // same abi (like x86, amd64_x86 for example). for (const Abi &abi : tc->supportedAbis()) { @@ -1487,11 +1491,6 @@ QString MsvcToolchainConfigWidget::vcVarsArguments() const return varsBatArg; } -std::unique_ptr<ToolchainConfigWidget> MsvcToolchain::createConfigurationWidget() -{ - return std::make_unique<MsvcToolchainConfigWidget>(this); -} - // -------------------------------------------------------------------------- // ClangClToolChainConfigWidget // -------------------------------------------------------------------------- @@ -1499,8 +1498,8 @@ std::unique_ptr<ToolchainConfigWidget> MsvcToolchain::createConfigurationWidget( class ClangClToolchainConfigWidget final : public MsvcBasedToolchainConfigWidget { public: - explicit ClangClToolchainConfigWidget(Toolchain *tc) - : MsvcBasedToolchainConfigWidget(tc) + explicit ClangClToolchainConfigWidget(const ToolchainBundle &bundle) + : MsvcBasedToolchainConfigWidget(bundle) , m_varsBatDisplayCombo(new QComboBox(this)) { m_mainLayout->removeRow(m_mainLayout->rowCount() - 1); @@ -1508,28 +1507,9 @@ public: m_varsBatDisplayCombo->setObjectName("varsBatCombo"); m_varsBatDisplayCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents); m_mainLayout->addRow(Tr::tr("Initialization:"), m_varsBatDisplayCombo); - - if (tc->isAutoDetected()) { - m_llvmDirLabel = new QLabel(this); - m_llvmDirLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - m_mainLayout->addRow(Tr::tr("&Compiler path:"), m_llvmDirLabel); - } else { - const QStringList gnuVersionArgs = QStringList("--version"); - m_compilerCommand = new PathChooser(this); - m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand); - m_compilerCommand->setCommandVersionArguments(gnuVersionArgs); - m_compilerCommand->setHistoryCompleter("PE.Clang.Command.History"); - m_mainLayout->addRow(Tr::tr("&Compiler path:"), m_compilerCommand); - } + setCommandVersionArguments(QStringList("--version")); addErrorLabel(); setFromClangClToolchain(); - - if (m_compilerCommand) { - connect(m_compilerCommand, - &Utils::PathChooser::rawPathChanged, - this, - &ClangClToolchainConfigWidget::dirty); - } } protected: @@ -1541,28 +1521,18 @@ protected: private: void setFromClangClToolchain(); - QLabel *m_llvmDirLabel = nullptr; QComboBox *m_varsBatDisplayCombo = nullptr; - PathChooser *m_compilerCommand = nullptr; }; void ClangClToolchainConfigWidget::setFromClangClToolchain() { - const auto *currentTC = static_cast<const MsvcToolchain *>(toolchain()); - m_nameDisplayLabel->setText(currentTC->displayName()); m_varsBatDisplayCombo->clear(); - m_varsBatDisplayCombo->addItem(msvcVarsToDisplay(*currentTC)); + m_varsBatDisplayCombo->addItem(msvcVarsToDisplay(bundle())); for (const MsvcToolchain *tc : std::as_const(g_availableMsvcToolchains)) { const QString varsToDisplay = msvcVarsToDisplay(*tc); if (m_varsBatDisplayCombo->findText(varsToDisplay) == -1) m_varsBatDisplayCombo->addItem(varsToDisplay); } - - const auto *clangClToolchain = static_cast<const ClangClToolchain *>(toolchain()); - if (clangClToolchain->isAutoDetected()) - m_llvmDirLabel->setText(clangClToolchain->clangPath().toUserOutput()); - else - m_compilerCommand->setFilePath(clangClToolchain->clangPath()); } class ClangClInfo @@ -1661,32 +1631,28 @@ static Toolchains detectClangClToolChainInPath(const FilePath &clangClPath, void ClangClToolchainConfigWidget::applyImpl() { - Utils::FilePath clangClPath = m_compilerCommand->filePath(); - auto clangClToolchain = static_cast<ClangClToolchain *>(toolchain()); - clangClToolchain->setClangPath(clangClPath); - + const FilePath clangClPath = bundle().get(&ClangClToolchain::clangPath); if (clangClPath.fileName() != "clang-cl.exe") { - clangClToolchain->resetVarsBat(); + bundle().set(&ClangClToolchain::resetVarsBat); setFromClangClToolchain(); return; } const QString displayedVarsBat = m_varsBatDisplayCombo->currentText(); Toolchains results = detectClangClToolChainInPath(clangClPath, {}, displayedVarsBat); + const QList<ToolchainBundle> bundles = ToolchainBundle::collectBundles(results); - if (results.isEmpty()) { - clangClToolchain->resetVarsBat(); + if (bundles.isEmpty()) { + bundle().set(&ClangClToolchain::resetVarsBat); } else { - for (const Toolchain *toolchain : results) { - if (toolchain->language() == clangClToolchain->language()) { - auto mstc = static_cast<const MsvcToolchain *>(toolchain); - clangClToolchain->setupVarsBat(mstc->targetAbi(), mstc->varsBat(), mstc->varsBatArg()); - break; - } - } - - qDeleteAll(results); - } + const ToolchainBundle &b = bundles.first(); + bundle().set( + &MsvcToolchain::setupVarsBat, + b.targetAbi(), + b.get(&MsvcToolchain::varsBat), + b.get(&MsvcToolchain::varsBatArg)); + } + qDeleteAll(results); setFromClangClToolchain(); } @@ -1766,11 +1732,6 @@ void ClangClToolchain::fromMap(const Store &data) m_clangPath = FilePath::fromString(clangPath); } -std::unique_ptr<ToolchainConfigWidget> ClangClToolchain::createConfigurationWidget() -{ - return std::make_unique<ClangClToolchainConfigWidget>(this); -} - bool ClangClToolchain::operator==(const Toolchain &other) const { if (!MsvcToolchain::operator==(other)) @@ -1785,6 +1746,12 @@ int ClangClToolchain::priority() const return MsvcToolchain::priority() - 1; } +bool ClangClToolchain::canShareBundleImpl(const Toolchain &other) const +{ + return MsvcToolchain::canShareBundleImpl(other) + && m_clangPath == static_cast<const ClangClToolchain &>(other).m_clangPath; +} + Macros ClangClToolchain::msvcPredefinedMacros(const QStringList &cxxflags, const Utils::Environment &env) const { @@ -1842,6 +1809,11 @@ public: Toolchains autoDetect(const ToolchainDetector &detector) const final; bool canCreate() const final { return !g_availableMsvcToolchains.isEmpty(); } + std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget( + const ToolchainBundle &bundle) const override + { + return std::make_unique<MsvcToolchainConfigWidget>(bundle); + } static QString vcVarsBatFor(const QString &basePath, MsvcToolchain::Platform platform, @@ -2210,6 +2182,11 @@ public: } Toolchains autoDetect(const ToolchainDetector &detector) const final; + std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget( + const ToolchainBundle &bundle) const override + { + return std::make_unique<ClangClToolchainConfigWidget>(bundle); + } bool canCreate() const final { return !g_availableMsvcToolchains.isEmpty(); } }; diff --git a/src/plugins/projectexplorer/msvctoolchain.h b/src/plugins/projectexplorer/msvctoolchain.h index f22a7af38c2..1ac2594fd1a 100644 --- a/src/plugins/projectexplorer/msvctoolchain.h +++ b/src/plugins/projectexplorer/msvctoolchain.h @@ -39,7 +39,6 @@ public: void toMap(Utils::Store &data) const override; void fromMap(const Utils::Store &data) override; - std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget() override; bool hostPrefersToolchain() const override; MacroInspectionRunner createMacroInspectionRunner() const override; @@ -97,6 +96,7 @@ protected: virtual Utils::LanguageVersion msvcLanguageVersion(const QStringList &cxxflags, const Utils::Id &language, const Macros ¯os) const; + bool canShareBundleImpl(const Toolchain &other) const override; struct GenerateEnvResult { @@ -135,10 +135,10 @@ public: QStringList suggestedMkspecList() const override; void addToEnvironment(Utils::Environment &env) const override; Utils::FilePath compilerCommand() const override; // FIXME: Remove + void setCompilerCommand(const Utils::FilePath &cmd) override { setClangPath(cmd); } QList<Utils::OutputLineParser *> createOutputParsers() const override; void toMap(Utils::Store &data) const override; void fromMap(const Utils::Store &data) override; - std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget() override; BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner( const Utils::Environment &env) const override; @@ -157,6 +157,8 @@ public: int priority() const override; private: + bool canShareBundleImpl(const Toolchain &other) const override; + Utils::FilePath m_clangPath; }; diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index c91e221dd17..b802ebe1fb3 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -855,6 +855,8 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er // Register languages ToolchainManager::registerLanguage(Constants::C_LANGUAGE_ID, Tr::tr("C")); ToolchainManager::registerLanguage(Constants::CXX_LANGUAGE_ID, Tr::tr("C++")); + ToolchainManager::registerLanguageCategory( + {Constants::C_LANGUAGE_ID, Constants::CXX_LANGUAGE_ID}, Tr::tr("C/C++")); IWizardFactory::registerFeatureProvider(new KitFeatureProvider); IWizardFactory::registerFactoryCreator([] { return new SimpleProjectWizard; }); diff --git a/src/plugins/projectexplorer/toolchain.cpp b/src/plugins/projectexplorer/toolchain.cpp index 0fa9033fabb..e242f198753 100644 --- a/src/plugins/projectexplorer/toolchain.cpp +++ b/src/plugins/projectexplorer/toolchain.cpp @@ -5,13 +5,17 @@ #include "abi.h" #include "devicesupport/idevice.h" +#include "gcctoolchain.h" #include "projectexplorerconstants.h" +#include "projectexplorertr.h" #include "toolchainmanager.h" #include "task.h" #include <utils/async.h> +#include <utils/pathchooser.h> #include <utils/qtcassert.h> +#include <QHash> #include <QUuid> #include <utility> @@ -19,9 +23,11 @@ using namespace Utils; namespace ProjectExplorer { + namespace Internal { const char ID_KEY[] = "ProjectExplorer.ToolChain.Id"; +const char BUNDLE_ID_KEY[] = "ProjectExplorer.ToolChain.BundleId"; const char DISPLAY_NAME_KEY[] = "ProjectExplorer.ToolChain.DisplayName"; const char AUTODETECT_KEY[] = "ProjectExplorer.ToolChain.Autodetect"; const char DETECTION_SOURCE_KEY[] = "ProjectExplorer.ToolChain.DetectionSource"; @@ -55,6 +61,7 @@ public: } QByteArray m_id; + Id m_bundleId; FilePath m_compilerCommand; Key m_compilerCommandKey; Abi m_targetAbi; @@ -125,9 +132,14 @@ Toolchain::Toolchain(Id typeId) : { } +bool Toolchain::canShareBundleImpl(const Toolchain &other) const +{ + Q_UNUSED(other) + return true; +} + void Toolchain::setLanguage(Id language) { - QTC_ASSERT(!d->m_language.isValid() || isAutoDetected(), return); QTC_ASSERT(language.isValid(), return); QTC_ASSERT(ToolchainManager::isLanguageSupported(language), return); @@ -177,6 +189,38 @@ QByteArray Toolchain::id() const return d->m_id; } +Id Toolchain::bundleId() const +{ + return d->m_bundleId; +} + +void Toolchain::setBundleId(Utils::Id id) +{ + d->m_bundleId = id; +} + +bool Toolchain::canShareBundle(const Toolchain &other) const +{ + QTC_ASSERT(typeId() == other.typeId(), return false); + QTC_ASSERT(language() != other.language(), return false); + + if (int(factory()->supportedLanguages().size()) == 1) + return false; + if (detection() != other.detection()) + return false; + + if (typeId() != Constants::MSVC_TOOLCHAIN_TYPEID + && typeId() != Constants::CLANG_CL_TOOLCHAIN_TYPEID + && (targetAbi() != other.targetAbi() || supportedAbis() != other.supportedAbis() + || extraCodeModelFlags() != other.extraCodeModelFlags() + || suggestedMkspecList() != other.suggestedMkspecList() || sysRoot() != other.sysRoot() + || correspondingCompilerCommand(other.language()) != other.compilerCommand())) { + return false; + } + + return canShareBundleImpl(other); +} + QStringList Toolchain::suggestedMkspecList() const { return {}; @@ -251,6 +295,7 @@ void Toolchain::toMap(Store &result) const QString idToSave = d->m_typeId.toString() + QLatin1Char(':') + QString::fromUtf8(id()); result.insert(ID_KEY, idToSave); + result.insert(BUNDLE_ID_KEY, d->m_bundleId.toSetting()); result.insert(DISPLAY_NAME_KEY, displayName()); result.insert(AUTODETECT_KEY, isAutoDetected()); result.insert(DETECTION_SOURCE_KEY, d->m_detectionSource); @@ -366,6 +411,7 @@ void Toolchain::fromMap(const Store &data) QTC_ASSERT(pos > 0, reportError(); return); d->m_typeId = Id::fromString(id.left(pos)); d->m_id = id.mid(pos + 1).toUtf8(); + d->m_bundleId = Id::fromSetting(data.value(BUNDLE_ID_KEY)); const bool autoDetect = data.value(AUTODETECT_KEY, false).toBool(); d->m_detection = autoDetect ? AutoDetection : ManualDetection; @@ -481,6 +527,12 @@ LanguageVersion Toolchain::languageVersion(const Id &language, const Macros &mac } } +FilePath Toolchain::correspondingCompilerCommand(Utils::Id otherLanguage) const +{ + QTC_ASSERT(language() != otherLanguage, return compilerCommand()); + return factory()->correspondingCompilerCommand(compilerCommand(), otherLanguage); +} + FilePaths Toolchain::includedFiles(const QString &option, const QStringList &flags, const FilePath &directoryPath, @@ -595,6 +647,13 @@ Toolchains ToolchainFactory::detectForImport(const ToolchainDescription &tcd) co return {}; } +FilePath ToolchainFactory::correspondingCompilerCommand( + const Utils::FilePath &srcPath, Utils::Id targetLang) const +{ + Q_UNUSED(targetLang) + return srcPath; +} + bool ToolchainFactory::canCreate() const { return m_userCreatable; @@ -662,6 +721,17 @@ QList<Id> ToolchainFactory::supportedLanguages() const return m_supportedLanguages; } +LanguageCategory ToolchainFactory::languageCategory() const +{ + const QList<Id> langs = supportedLanguages(); + if (langs.size() == 1 + && (langs.first() == Constants::C_LANGUAGE_ID + || langs.first() == Constants::CXX_LANGUAGE_ID)) { + return {Constants::C_LANGUAGE_ID, Constants::CXX_LANGUAGE_ID}; + } + return LanguageCategory(langs.cbegin(), langs.cend()); +} + Id ToolchainFactory::supportedToolchainType() const { return m_supportedToolchainType; @@ -797,4 +867,192 @@ void AsyncToolchainDetector::run() watcher->setFuture(Utils::asyncRun(m_func, m_detector)); } +/* + * PRE: + * - The list of toolchains is not empty. + * - All toolchains in the list have the same bundle id. + * - All toolchains in the list have the same type (and thus were created by the same factory) + * and are also otherwise "compatible" (target ABI etc). + * - No two toolchains in the list are for the same language. + * POST: + * - PRE. + * - There is exactly one toolchain in the list for every language supported by the factory. + * - If there is a C compiler, it comes first in the list. + */ +ToolchainBundle::ToolchainBundle(const Toolchains &toolchains) : m_toolchains(toolchains) +{ + // Check pre-conditions. + QTC_ASSERT(!m_toolchains.isEmpty(), return); + QTC_ASSERT(m_toolchains.size() <= factory()->supportedLanguages().size(), return); + for (const Toolchain * const tc : toolchains) + QTC_ASSERT(factory()->supportedLanguages().contains(tc->language()), return); + for (int i = 1; i < int(toolchains.size()); ++i) { + const Toolchain * const tc = toolchains.at(i); + QTC_ASSERT(tc->typeId() == toolchains.first()->typeId(), return); + QTC_ASSERT(tc->bundleId() == toolchains.first()->bundleId(), return); + } + + addMissingToolchains(); + + // Check post-conditions. + QTC_ASSERT(m_toolchains.size() == m_toolchains.first()->factory()->supportedLanguages().size(), + return); + for (auto i = toolchains.size(); i < m_toolchains.size(); ++i) + QTC_ASSERT(m_toolchains.at(i)->typeId() == m_toolchains.first()->typeId(), return); + + Utils::sort(m_toolchains, [](const Toolchain *tc1, const Toolchain *tc2) { + return tc1 != tc2 && tc1->language() == Constants::C_LANGUAGE_ID; + }); +} + +QList<ToolchainBundle> ToolchainBundle::collectBundles() +{ + return collectBundles(ToolchainManager::toolchains()); +} + +QList<ToolchainBundle> ToolchainBundle::collectBundles(const Toolchains &toolchains) +{ + QHash<Id, Toolchains> toolchainsPerBundleId; + for (Toolchain * const tc : toolchains) + toolchainsPerBundleId[tc->bundleId()] << tc; + + QList<ToolchainBundle> bundles; + if (const auto unbundled = toolchainsPerBundleId.constFind(Id()); + unbundled != toolchainsPerBundleId.constEnd()) { + bundles = bundleUnbundledToolchains(*unbundled); + toolchainsPerBundleId.erase(unbundled); + } + + for (const Toolchains &tcs : toolchainsPerBundleId) + bundles << tcs; + return bundles; +} + +ToolchainFactory *ToolchainBundle::factory() const +{ + QTC_ASSERT(!m_toolchains.isEmpty(), return nullptr); + return m_toolchains.first()->factory(); +} + +QString ToolchainBundle::displayName() const +{ + if (!isAutoDetected() || !dynamic_cast<GccToolchain *>(m_toolchains.first())) + return get(&Toolchain::displayName); + + // Auto-detected GCC toolchains encode language and compiler command in their display names. + // We need to omit the language and we always want to use the C compiler command + // for consistency. + FilePath cmd; + for (const Toolchain * const tc : std::as_const(m_toolchains)) { + if (!tc->isValid()) + continue; + cmd = tc->compilerCommand(); + if (tc->language() == Constants::C_LANGUAGE_ID) + break; + } + + QString name = typeDisplayName(); + const Abi abi = targetAbi(); + if (abi.architecture() != Abi::UnknownArchitecture) + name.append(' ').append(Abi::toString(abi.architecture())); + if (abi.wordWidth() != 0) + name.append(' ').append(Abi::toString(abi.wordWidth())); + if (!cmd.exists()) + return name; + return Tr::tr("%1 at %2").arg(name, cmd.toUserOutput()); +} + +ToolchainBundle::Valid ToolchainBundle::validity() const +{ + if (Utils::allOf(m_toolchains, &Toolchain::isValid)) + return Valid::All; + if (Utils::contains(m_toolchains, &Toolchain::isValid)) + return Valid::Some; + return Valid::None; +} + +QList<ToolchainBundle> ToolchainBundle::bundleUnbundledToolchains(const Toolchains &unbundled) +{ + QList<ToolchainBundle> bundles; + QHash<Id, QHash<Id, Toolchains>> unbundledByTypeAndLanguage; + for (Toolchain * const tc : unbundled) + unbundledByTypeAndLanguage[tc->typeId()][tc->language()] << tc; + for (const auto &tcsByLang : std::as_const(unbundledByTypeAndLanguage)) { + QList<Toolchains> remainingUnbundled; + for (const auto &tcs : tcsByLang) + remainingUnbundled << tcs; + while (true) { + Toolchains nextBundle; + for (Toolchains &list : remainingUnbundled) { + for (auto it = list.begin(); it != list.end(); ++it) { + if (nextBundle.isEmpty() || nextBundle.first()->canShareBundle((**it))) { + nextBundle << *it; + list.erase(it); + break; + } + } + } + if (nextBundle.isEmpty()) + break; + const Id newBundleId = Id::generate(); + for (Toolchain * const tc : nextBundle) + tc->setBundleId(newBundleId); + bundles << nextBundle; + } + } + + return bundles; +} + +void ToolchainBundle::setCompilerCommand(Utils::Id language, const Utils::FilePath &cmd) +{ + for (Toolchain *const tc : std::as_const(m_toolchains)) { + if (tc->language() == language) { + tc->setCompilerCommand(cmd); + break; + } + } +} + +FilePath ToolchainBundle::compilerCommand(Utils::Id language) const +{ + for (Toolchain *const tc : std::as_const(m_toolchains)) { + if (tc->language() == language) + return tc->compilerCommand(); + } + return {}; +} + +void ToolchainBundle::deleteToolchains() +{ + qDeleteAll(m_toolchains); + m_toolchains.clear(); +} + +ToolchainBundle ToolchainBundle::clone() const +{ + const Toolchains clones = Utils::transform(m_toolchains, &Toolchain::clone); + const Id newBundleId = Id::generate(); + for (Toolchain * const tc : clones) + tc->setBundleId(newBundleId); + return clones; +} + +void ToolchainBundle::addMissingToolchains() +{ + const QList<Id> missingLanguages + = Utils::filtered(m_toolchains.first()->factory()->supportedLanguages(), [this](Id lang) { + return !Utils::contains(m_toolchains, [lang](const Toolchain *tc) { + return tc->language() == lang; + }); + }); + for (const Id lang : missingLanguages) { + Toolchain * const tc = m_toolchains.first()->clone(); + tc->setLanguage(lang); + tc->setCompilerCommand(m_toolchains.first()->correspondingCompilerCommand(lang)); + m_toolchains << tc; + m_createdToolchains << tc; + } +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/toolchain.h b/src/plugins/projectexplorer/toolchain.h index 5467d82abb9..dd3459905c2 100644 --- a/src/plugins/projectexplorer/toolchain.h +++ b/src/plugins/projectexplorer/toolchain.h @@ -18,9 +18,11 @@ #include <utils/store.h> #include <QDateTime> +#include <QSet> #include <functional> #include <memory> +#include <optional> namespace Utils { class OutputLineParser; } @@ -54,6 +56,8 @@ public: Utils::Id language; }; +using LanguageCategory = QSet<Utils::Id>; + // -------------------------------------------------------------------------- // Toolchain (documentation inside) // -------------------------------------------------------------------------- @@ -83,6 +87,10 @@ public: QByteArray id() const; + Utils::Id bundleId() const; + void setBundleId(Utils::Id id); + bool canShareBundle(const Toolchain &other) const; + virtual QStringList suggestedMkspecList() const; Utils::Id typeId() const; @@ -132,14 +140,13 @@ public: Utils::Id language() const; virtual Utils::FilePath compilerCommand() const; // FIXME: De-virtualize. - void setCompilerCommand(const Utils::FilePath &command); + virtual void setCompilerCommand(const Utils::FilePath &command); virtual bool matchesCompilerCommand(const Utils::FilePath &command) const; virtual QList<Utils::OutputLineParser *> createOutputParsers() const = 0; virtual bool operator ==(const Toolchain &) const; - virtual std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget() = 0; Toolchain *clone() const; // Used by the toolchainmanager to save user-generated tool chains. @@ -165,6 +172,8 @@ public: virtual int priority() const { return PriorityNormal; } virtual GccToolchain *asGccToolchain() { return nullptr; } + Utils::FilePath correspondingCompilerCommand(Utils::Id otherLanguage) const; + protected: explicit Toolchain(Utils::Id typeId); @@ -196,6 +205,8 @@ private: Toolchain(const Toolchain &) = delete; Toolchain &operator=(const Toolchain &) = delete; + virtual bool canShareBundleImpl(const Toolchain &other) const; + const std::unique_ptr<Internal::ToolchainPrivate> d; friend class Internal::ToolchainSettingsAccessor; @@ -204,6 +215,98 @@ private: using Toolchains = QList<Toolchain *>; +class PROJECTEXPLORER_EXPORT ToolchainBundle +{ +public: + ToolchainBundle(const Toolchains &toolchains); + + static QList<ToolchainBundle> collectBundles(); + static QList<ToolchainBundle> collectBundles(const Toolchains &toolchains); + + template<typename R, class T = Toolchain, typename... A> + R get(R (T:: *getter)(A...) const, A&&... args) const + { + return std::invoke(getter, static_cast<T &>(*m_toolchains.first()), std::forward<A>(args)...); + } + + template<class T = Toolchain, typename R> R& get(R T::*member) const + { + return static_cast<T &>(*m_toolchains.first()).*member; + } + + template<class T = Toolchain, typename ...A> void set(void (T::*setter)(const A&...), const A& ...args) + { + for (Toolchain * const tc : std::as_const(m_toolchains)) + std::invoke(setter, static_cast<T &>(*tc), args...); + } + + template<class T = Toolchain, typename ...A> void set(void (T::*setter)(A...), const A ...args) + { + for (Toolchain * const tc : std::as_const(m_toolchains)) + std::invoke(setter, static_cast<T &>(*tc), args...); + } + + template<typename T> void forEach(const std::function<void(T &toolchain)> &modifier) + { + for (Toolchain * const tc : std::as_const(m_toolchains)) + modifier(static_cast<T &>(*tc)); + } + + template<typename T> void forEach(const std::function<void(const T &toolchain)> &func) const + { + for (const Toolchain * const tc : m_toolchains) + func(static_cast<const T &>(*tc)); + } + + int size() const { return m_toolchains.size(); } + + const QList<Toolchain *> toolchains() const { return m_toolchains; } + const QList<Toolchain *> createdToolchains() const { return m_createdToolchains; } + ToolchainFactory *factory() const; + Utils::Id bundleId() const { return get(&Toolchain::bundleId); } + QString displayName() const; + Utils::Id type() const { return get(&Toolchain::typeId); } + QString typeDisplayName() const { return get(&Toolchain::typeDisplayName); } + QStringList extraCodeModelFlags() const { return get(&Toolchain::extraCodeModelFlags); } + bool isAutoDetected() const { return get(&Toolchain::isAutoDetected); } + bool isSdkProvided() const { return get(&Toolchain::isSdkProvided); } + Utils::FilePath compilerCommand(Utils::Id language) const; + Abi targetAbi() const { return get(&Toolchain::targetAbi); } + QList<Abi> supportedAbis() const { return get(&Toolchain::supportedAbis); } + Utils::FilePath makeCommand(const Utils::Environment &env) const + { + return get(&Toolchain::makeCommand, env); + } + + enum class Valid { All, Some, None }; + Valid validity() const; + + void setDetection(Toolchain::Detection d) { set(&Toolchain::setDetection, d); } + void setCompilerCommand(Utils::Id language, const Utils::FilePath &cmd); + + void setDisplayName(const QString &name) { set(&Toolchain::setDisplayName, name); } + void setTargetAbi(const Abi &abi) { set(&Toolchain::setTargetAbi, abi); } + + ToolchainBundle clone() const; + + // Rampdown operations. No regular access to the bundle is allowed after calling these. + bool removeToolchain(Toolchain *tc) { return m_toolchains.removeOne(tc); } + void clearToolchains() { m_toolchains.clear(); } + void deleteToolchains(); + + friend bool operator==(const ToolchainBundle &b1, const ToolchainBundle &b2) + { + return b1.m_toolchains == b2.m_toolchains; + } + +private: + void addMissingToolchains(); + static QList<ToolchainBundle> bundleUnbundledToolchains(const Toolchains &unbundled); + + Toolchains m_toolchains; + Toolchains m_createdToolchains; +}; + class PROJECTEXPLORER_EXPORT BadToolchain { public: @@ -276,6 +379,10 @@ public: const ToolchainDetector &detector) const; virtual Toolchains autoDetect(const ToolchainDetector &detector) const; virtual Toolchains detectForImport(const ToolchainDescription &tcd) const; + virtual std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget( + const ToolchainBundle &bundle) const = 0; + virtual Utils::FilePath correspondingCompilerCommand( + const Utils::FilePath &srcPath, Utils::Id targetLang) const; virtual bool canCreate() const; Toolchain *create() const; @@ -289,6 +396,7 @@ public: static Toolchain *createToolchain(Utils::Id toolchainType); QList<Utils::Id> supportedLanguages() const; + LanguageCategory languageCategory() const; void setUserCreatable(bool userCreatable); diff --git a/src/plugins/projectexplorer/toolchainconfigwidget.cpp b/src/plugins/projectexplorer/toolchainconfigwidget.cpp index 60b1479e7d8..2192c01c0c5 100644 --- a/src/plugins/projectexplorer/toolchainconfigwidget.cpp +++ b/src/plugins/projectexplorer/toolchainconfigwidget.cpp @@ -4,13 +4,17 @@ #include "toolchainconfigwidget.h" #include "toolchain.h" +#include "projectexplorerconstants.h" #include "projectexplorertr.h" +#include "toolchainmanager.h" #include <utils/detailswidget.h> #include <utils/qtcprocess.h> #include <utils/qtcassert.h> +#include <QCheckBox> #include <QFormLayout> +#include <QHBoxLayout> #include <QLineEdit> #include <QLabel> #include <QScrollArea> @@ -20,11 +24,9 @@ using namespace Utils; namespace ProjectExplorer { -ToolchainConfigWidget::ToolchainConfigWidget(Toolchain *tc) : - m_toolChain(tc) +ToolchainConfigWidget::ToolchainConfigWidget(const ToolchainBundle &bundle) + : m_bundle(bundle) { - Q_ASSERT(tc); - auto centralWidget = new Utils::DetailsWidget; centralWidget->setState(Utils::DetailsWidget::NoSummary); @@ -42,38 +44,48 @@ ToolchainConfigWidget::ToolchainConfigWidget(Toolchain *tc) : m_mainLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); // for the Macs... m_nameLineEdit = new QLineEdit; - m_nameLineEdit->setText(tc->displayName()); + m_nameLineEdit->setText(bundle.displayName()); m_mainLayout->addRow(Tr::tr("Name:"), m_nameLineEdit); + if (bundle.type() != Constants::MSVC_TOOLCHAIN_TYPEID) + setupCompilerPathChoosers(); + connect(m_nameLineEdit, &QLineEdit::textChanged, this, &ToolchainConfigWidget::dirty); } void ToolchainConfigWidget::apply() { - m_toolChain->setDisplayName(m_nameLineEdit->text()); + m_bundle.setDisplayName(m_nameLineEdit->text()); + if (!bundle().isAutoDetected()) { + for (const auto &[tc, pathChooser] : std::as_const(m_commands)) + bundle().setCompilerCommand(tc->language(), pathChooser->filePath()); + } applyImpl(); } void ToolchainConfigWidget::discard() { - m_nameLineEdit->setText(m_toolChain->displayName()); + m_nameLineEdit->setText(m_bundle.displayName()); + for (const auto &[tc, pathChooser] : std::as_const(m_commands)) + pathChooser->setFilePath(bundle().compilerCommand(tc->language())); discardImpl(); } bool ToolchainConfigWidget::isDirty() const { - return m_nameLineEdit->text() != m_toolChain->displayName() || isDirtyImpl(); -} - -Toolchain *ToolchainConfigWidget::toolchain() const -{ - return m_toolChain; + for (const auto &[tc, pathChooser] : std::as_const(m_commands)) { + if (pathChooser->filePath() != bundle().compilerCommand(tc->language())) + return true; + } + return m_nameLineEdit->text() != m_bundle.displayName() || isDirtyImpl(); } void ToolchainConfigWidget::makeReadOnly() { m_nameLineEdit->setEnabled(false); + for (const auto &commands : std::as_const(m_commands)) + commands.second->setReadOnly(true); makeReadOnlyImpl(); } @@ -122,4 +134,90 @@ QStringList ToolchainConfigWidget::splitString(const QString &s) return res; } +ToolchainConfigWidget::ToolchainChooser ToolchainConfigWidget::compilerPathChooser(Utils::Id language) +{ + for (const ToolchainChooser &chooser : std::as_const(m_commands)) { + if (chooser.first->language() == language) + return chooser; + } + return {}; +} + +void ToolchainConfigWidget::setupCompilerPathChoosers() +{ + const QString nameLabelString = int(bundle().toolchains().size()) == 1 + ? Tr::tr("&Compiler path") + : QString(); + bundle().forEach<Toolchain>([&](const Toolchain &tc) { + const QString name = !nameLabelString.isEmpty() + ? nameLabelString + : Tr::tr("%1 compiler path").arg( + ToolchainManager::displayNameOfLanguageId(tc.language())); + const auto commandChooser = new PathChooser(this); + commandChooser->setExpectedKind(PathChooser::ExistingCommand); + commandChooser->setHistoryCompleter("PE.ToolChainCommand.History"); + commandChooser->setAllowPathFromDevice(true); + commandChooser->setFilePath(tc.compilerCommand()); + m_commands << std::make_pair(&tc, commandChooser); + if (tc.language() == Constants::CXX_LANGUAGE_ID + && bundle().factory()->supportedLanguages().contains(Constants::C_LANGUAGE_ID)) { + m_deriveCxxCompilerCheckBox = new QCheckBox(Tr::tr("Derive from C compiler")); + m_deriveCxxCompilerCheckBox->setChecked(true); + const auto commandLayout = new QHBoxLayout; + commandLayout->addWidget(commandChooser); + commandLayout->addWidget(m_deriveCxxCompilerCheckBox); + m_mainLayout->addRow(name, commandLayout); + if (!tc.compilerCommand().isExecutableFile()) + deriveCxxCompilerCommand(); + } else { + m_mainLayout->addRow(name, commandChooser); + } + connect(commandChooser, &PathChooser::rawPathChanged, this, [this, &tc] { + emit compilerCommandChanged(tc.language()); + if (tc.language() == Constants::C_LANGUAGE_ID) + deriveCxxCompilerCommand(); + }); + connect(commandChooser, &PathChooser::rawPathChanged, this, &ToolchainConfigWidget::dirty); + }); +} + +FilePath ToolchainConfigWidget::compilerCommand(Utils::Id language) +{ + if (const PathChooser * const chooser = compilerPathChooser(language).second) + return chooser->filePath(); + return {}; +} + +bool ToolchainConfigWidget::hasAnyCompiler() const +{ + for (const auto &cmd : std::as_const(m_commands)) { + if (cmd.second->filePath().isExecutableFile()) + return true; + } + return false; +} + +void ToolchainConfigWidget::setCommandVersionArguments(const QStringList &args) +{ + for (const auto &[_,pathChooser] : std::as_const(m_commands)) + pathChooser->setCommandVersionArguments(args); +} + +void ToolchainConfigWidget::deriveCxxCompilerCommand() +{ + if (!m_deriveCxxCompilerCheckBox || !m_deriveCxxCompilerCheckBox->isChecked()) + return; + + using namespace Constants; + const ToolchainChooser cChooser = compilerPathChooser(C_LANGUAGE_ID); + const ToolchainChooser cxxChooser = compilerPathChooser(CXX_LANGUAGE_ID); + QTC_ASSERT(cChooser.first && cChooser.second && cxxChooser.second, return); + if (cChooser.second->filePath().isExecutableFile()) { + if (const FilePath cxxCmd = bundle().factory()->correspondingCompilerCommand( + cChooser.second->filePath(), CXX_LANGUAGE_ID); + cxxCmd.isExecutableFile()) + cxxChooser.second->setFilePath(cxxCmd); + } +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/toolchainconfigwidget.h b/src/plugins/projectexplorer/toolchainconfigwidget.h index 02257ef571e..1f8cee1273a 100644 --- a/src/plugins/projectexplorer/toolchainconfigwidget.h +++ b/src/plugins/projectexplorer/toolchainconfigwidget.h @@ -5,9 +5,16 @@ #include "projectexplorer_export.h" +#include "toolchain.h" + #include <QScrollArea> +#include <utility> + +namespace Utils { class PathChooser; } + QT_BEGIN_NAMESPACE +class QCheckBox; class QFormLayout; class QLineEdit; class QLabel; @@ -15,8 +22,6 @@ QT_END_NAMESPACE namespace ProjectExplorer { -class Toolchain; - // -------------------------------------------------------------------------- // ToolChainConfigWidget // -------------------------------------------------------------------------- @@ -26,9 +31,9 @@ class PROJECTEXPLORER_EXPORT ToolchainConfigWidget : public QScrollArea Q_OBJECT public: - explicit ToolchainConfigWidget(Toolchain *tc); + explicit ToolchainConfigWidget(const ToolchainBundle &bundle); - Toolchain *toolchain() const; + ToolchainBundle bundle() const { return m_bundle; } void apply(); void discard(); @@ -36,6 +41,7 @@ public: void makeReadOnly(); signals: + void compilerCommandChanged(Utils::Id language); void dirty(); protected: @@ -49,12 +55,23 @@ protected: void addErrorLabel(); static QStringList splitString(const QString &s); + Utils::FilePath compilerCommand(Utils::Id language); + bool hasAnyCompiler() const; + void setCommandVersionArguments(const QStringList &args); + void deriveCxxCompilerCommand(); + QFormLayout *m_mainLayout; - QLineEdit *m_nameLineEdit; private: - Toolchain *m_toolChain; + using ToolchainChooser = std::pair<const Toolchain *, Utils::PathChooser *>; + ToolchainChooser compilerPathChooser(Utils::Id language); + void setupCompilerPathChoosers(); + + ToolchainBundle m_bundle; + QLineEdit *m_nameLineEdit = nullptr; QLabel *m_errorLabel = nullptr; + QCheckBox *m_deriveCxxCompilerCheckBox = nullptr; + QList<ToolchainChooser> m_commands; }; } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/toolchainmanager.cpp b/src/plugins/projectexplorer/toolchainmanager.cpp index e463a317a3b..f3fa73bb9c3 100644 --- a/src/plugins/projectexplorer/toolchainmanager.cpp +++ b/src/plugins/projectexplorer/toolchainmanager.cpp @@ -43,6 +43,7 @@ public: Toolchains m_toolChains; // prioritized List BadToolchains m_badToolchains; // to be skipped when auto-detecting QVector<LanguageDisplayPair> m_languages; + QList<std::pair<LanguageCategory, QString>> m_languageCategories; ToolchainDetectionSettings m_detectionSettings; bool m_loaded = false; }; @@ -255,6 +256,11 @@ bool ToolchainManager::registerLanguage(const Utils::Id &language, const QString return true; } +void ToolchainManager::registerLanguageCategory(const LanguageCategory &languages, const QString &displayName) +{ + d->m_languageCategories.push_back(std::make_pair(languages, displayName)); +} + QString ToolchainManager::displayNameOfLanguageId(const Utils::Id &id) { QTC_ASSERT(id.isValid(), return Tr::tr("None")); @@ -263,6 +269,36 @@ QString ToolchainManager::displayNameOfLanguageId(const Utils::Id &id) return entry.displayName; } +QString ToolchainManager::displayNameOfLanguageCategory(const LanguageCategory &category) +{ + if (int(category.size()) == 1) + return displayNameOfLanguageId(*category.begin()); + QString name = Utils::findOrDefault(d->m_languageCategories, [&category](const auto &e) { + return e.first == category; + }).second; + QTC_ASSERT(!name.isEmpty(), return Tr::tr("None")); + return name; +} + +const QList<LanguageCategory> ToolchainManager::languageCategories() +{ + QList<LanguageCategory> categories + = Utils::transform<QList<LanguageCategory>>(d->m_languageCategories, [](const auto &e) { + return e.first; + }); + const QList<Utils::Id> languages = allLanguages(); + for (const Utils::Id &l : languages) { + if (Utils::contains(categories, [l](const LanguageCategory &lc) { + return lc.contains(l); + })) { + continue; + } + categories.push_back({l}); + } + + return categories; +} + bool ToolchainManager::isLanguageSupported(const Utils::Id &id) { return Utils::contains(d->m_languages, Utils::equal(&LanguageDisplayPair::id, id)); diff --git a/src/plugins/projectexplorer/toolchainmanager.h b/src/plugins/projectexplorer/toolchainmanager.h index 3a8dde495ea..5eff268c288 100644 --- a/src/plugins/projectexplorer/toolchainmanager.h +++ b/src/plugins/projectexplorer/toolchainmanager.h @@ -12,8 +12,6 @@ #include <QSet> #include <QString> -#include <functional> - namespace Utils { class FilePath; } namespace ProjectExplorer { @@ -53,7 +51,11 @@ public: static QList<Utils::Id> allLanguages(); static bool registerLanguage(const Utils::Id &language, const QString &displayName); + static void registerLanguageCategory( + const LanguageCategory &languages, const QString &displayName); static QString displayNameOfLanguageId(const Utils::Id &id); + static QString displayNameOfLanguageCategory(const LanguageCategory &category); + static const QList<LanguageCategory> languageCategories(); static bool isLanguageSupported(const Utils::Id &id); static void aboutToShutdown(); diff --git a/src/plugins/projectexplorer/toolchainoptionspage.cpp b/src/plugins/projectexplorer/toolchainoptionspage.cpp index c691a847356..c773a6d6957 100644 --- a/src/plugins/projectexplorer/toolchainoptionspage.cpp +++ b/src/plugins/projectexplorer/toolchainoptionspage.cpp @@ -17,6 +17,7 @@ #include <utils/algorithm.h> #include <utils/detailswidget.h> +#include <utils/guard.h> #include <utils/qtcassert.h> #include <utils/treemodel.h> #include <utils/utilsicons.h> @@ -48,8 +49,8 @@ namespace Internal { class ToolChainTreeItem : public TreeItem { public: - ToolChainTreeItem(QStackedWidget *parentWidget, Toolchain *tc, bool c) : - toolChain(tc), changed(c), m_parentWidget(parentWidget) + ToolChainTreeItem(QStackedWidget *parentWidget, const ToolchainBundle &bundle, bool c) : + bundle(bundle), changed(c), m_parentWidget(parentWidget) {} QVariant data(int column, int role) const override @@ -57,8 +58,8 @@ public: switch (role) { case Qt::DisplayRole: if (column == 0) - return toolChain->displayName(); - return toolChain->typeDisplayName(); + return bundle.displayName(); + return bundle.typeDisplayName(); case Qt::FontRole: { QFont font; font.setBold(changed); @@ -66,18 +67,31 @@ public: } case Qt::ToolTipRole: { QString toolTip; - if (toolChain->isValid()) { + const ToolchainBundle::Valid validity = bundle.validity(); + if (validity != ToolchainBundle::Valid::None) { toolTip = Tr::tr("<nobr><b>ABI:</b> %1").arg( changed ? Tr::tr("not up-to-date") - : toolChain->targetAbi().toString()); + : bundle.targetAbi().toString()); + if (validity == ToolchainBundle::Valid::Some) + toolTip.append("<br/>").append( + Tr::tr("Not all compilers are set up correctly.")); } else { toolTip = Tr::tr("This toolchain is invalid."); } return QVariant("<div style=\"white-space:pre\">" + toolTip + "</div>"); } case Qt::DecorationRole: - return column == 0 && !toolChain->isValid() - ? Utils::Icons::CRITICAL.icon() : QVariant(); + if (column == 0) { + switch (bundle.validity()) { + case ToolchainBundle::Valid::All: + break; + case ToolchainBundle::Valid::Some: + return Utils::Icons::WARNING.icon(); + case ToolchainBundle::Valid::None: + return Utils::Icons::CRITICAL.icon(); + } + } + return QVariant(); } return {}; } @@ -85,10 +99,10 @@ public: ToolchainConfigWidget *widget() { if (!m_widget) { - m_widget = toolChain->createConfigurationWidget().release(); + m_widget = bundle.factory()->createConfigurationWidget(bundle).release(); if (m_widget) { m_parentWidget->addWidget(m_widget); - if (toolChain->isAutoDetected()) + if (bundle.isAutoDetected()) m_widget->makeReadOnly(); QObject::connect(m_widget, &ToolchainConfigWidget::dirty, [this] { @@ -100,7 +114,7 @@ public: return m_widget; } - Toolchain *toolChain; + ToolchainBundle bundle; bool changed; private: @@ -163,16 +177,15 @@ public: {ProjectExplorer::Constants::msgAutoDetectedToolTip()}); auto manualRoot = new StaticTreeItem(ProjectExplorer::Constants::msgManual()); - const QList<Utils::Id> languages = ToolchainManager::allLanguages(); - for (const Utils::Id &l : languages) { - const QString dn = ToolchainManager::displayNameOfLanguageId(l); + for (const LanguageCategory &category : ToolchainManager::languageCategories()) { + const QString dn = ToolchainManager::displayNameOfLanguageCategory(category); auto autoNode = new StaticTreeItem(dn); auto manualNode = new StaticTreeItem(dn); autoRoot->appendChild(autoNode); manualRoot->appendChild(manualNode); - m_languageMap.insert(l, {autoNode, manualNode}); + m_languageMap.insert(category, {autoNode, manualNode}); } m_model.rootItem()->appendChild(autoRoot); @@ -199,23 +212,14 @@ public: if (languages.isEmpty()) continue; - if (languages.count() == 1) { - addMenu->addAction(createAction(factory->displayName(), factory, languages.at(0))); - } else { - Utils::sort(languages, [](const Utils::Id &l1, const Utils::Id &l2) { - return ToolchainManager::displayNameOfLanguageId(l1) < ToolchainManager::displayNameOfLanguageId(l2); - }); - auto subMenu = addMenu->addMenu(factory->displayName()); - for (const Utils::Id &l : std::as_const(languages)) - subMenu->addAction(createAction(ToolchainManager::displayNameOfLanguageId(l), factory, l)); - } + addMenu->addAction(createAction(factory->displayName(), factory, languages)); } m_addButton->setMenu(addMenu); if (HostOsInfo::isMacHost()) m_addButton->setStyleSheet("text-align:center;"); m_cloneButton = new QPushButton(Tr::tr("Clone"), this); - connect(m_cloneButton, &QAbstractButton::clicked, this, [this] { cloneToolChain(); }); + connect(m_cloneButton, &QAbstractButton::clicked, this, [this] { cloneToolchains(); }); m_delButton = new QPushButton(Tr::tr("Remove"), this); @@ -227,7 +231,7 @@ public: if (item->level() != 3) return; const auto tcItem = static_cast<ToolChainTreeItem *>(item); - if (!tcItem->toolChain->isSdkProvided()) + if (!tcItem->bundle.isSdkProvided()) itemsToRemove << tcItem; }); for (ToolChainTreeItem * const tcItem : std::as_const(itemsToRemove)) @@ -253,8 +257,11 @@ public: m_widgetStack = new QStackedWidget; m_container->setWidget(m_widgetStack); - for (Toolchain *tc : ToolchainManager::toolchains()) - insertToolChain(tc); + const QList<ToolchainBundle> bundles = ToolchainBundle::collectBundles(); + for (const ToolchainBundle &b : bundles) { + ToolchainManager::registerToolchains(b.createdToolchains()); + insertBundle(b); + } auto buttonLayout = new QVBoxLayout; buttonLayout->setSpacing(6); @@ -295,21 +302,23 @@ public: void toolChainSelectionChanged(); void updateState(); - void createToolChain(ToolchainFactory *factory, const Utils::Id &language); - void cloneToolChain(); + void createToolchains(ToolchainFactory *factory, const QList<Id> &languages); + void cloneToolchains(); ToolChainTreeItem *currentTreeItem(); void markForRemoval(ToolChainTreeItem *item); - ToolChainTreeItem *insertToolChain(ProjectExplorer::Toolchain *tc, bool changed = false); // Insert directly into model + ToolChainTreeItem *insertBundle(const ToolchainBundle &bundle, bool changed = false); // Insert directly into model void handleToolchainsRegistered(const Toolchains &toolchains); void handleToolchainsDeregistered(const Toolchains &toolchains); - StaticTreeItem *parentForToolChain(Toolchain *tc); - QAction *createAction(const QString &name, ToolchainFactory *factory, Utils::Id language) + StaticTreeItem *rootItem(const LanguageCategory &languageCategory, bool autoDetected); + StaticTreeItem *parentForBundle(const ToolchainBundle &bundle); + StaticTreeItem *parentForToolchain(const Toolchain &tc); + QAction *createAction(const QString &name, ToolchainFactory *factory, const QList<Id> &languages) { auto action = new QAction(name, this); connect(action, &QAction::triggered, this, - [this, factory, language] { createToolChain(factory, language); }); + [this, factory, languages] { createToolchains(factory, languages); }); return action; } @@ -331,10 +340,13 @@ public: QPushButton *m_redetectButton; QPushButton *m_detectionSettingsButton; - QHash<Utils::Id, QPair<StaticTreeItem *, StaticTreeItem *>> m_languageMap; + QHash<LanguageCategory, QPair<StaticTreeItem *, StaticTreeItem *>> m_languageMap; - QList<ToolChainTreeItem *> m_toAddList; - QList<ToolChainTreeItem *> m_toRemoveList; + using AddRemoveList = QList<ToolChainTreeItem *>; + AddRemoveList m_toAddList; + AddRemoveList m_toRemoveList; + Guard m_registerGuard; + Guard m_deregisterGuard; ToolchainDetectionSettings m_detectionSettings; }; @@ -342,20 +354,21 @@ public: void ToolChainOptionsWidget::markForRemoval(ToolChainTreeItem *item) { m_model.takeItem(item); - if (m_toAddList.contains(item)) { - delete item->toolChain; - item->toolChain = nullptr; - m_toAddList.removeOne(item); + if (const auto it = std::find(m_toAddList.begin(), m_toAddList.end(), item); + it != m_toAddList.end()) { + item->bundle.deleteToolchains(); + m_toAddList.erase(it); delete item; } else { m_toRemoveList.append(item); } } -ToolChainTreeItem *ToolChainOptionsWidget::insertToolChain(Toolchain *tc, bool changed) +ToolChainTreeItem *ToolChainOptionsWidget::insertBundle( + const ToolchainBundle &bundle, bool changed) { - StaticTreeItem *parent = parentForToolChain(tc); - auto item = new ToolChainTreeItem(m_widgetStack, tc, changed); + StaticTreeItem *parent = parentForBundle(bundle); + auto item = new ToolChainTreeItem(m_widgetStack, bundle, changed); parent->appendChild(item); return item; @@ -363,86 +376,148 @@ ToolChainTreeItem *ToolChainOptionsWidget::insertToolChain(Toolchain *tc, bool c void ToolChainOptionsWidget::handleToolchainsRegistered(const Toolchains &toolchains) { - for (Toolchain * const tc : toolchains) { - if (Utils::eraseOne(m_toAddList, [tc](const ToolChainTreeItem *item) { - return item->toolChain == tc; })) { - // do not delete here! - continue; - } + if (m_registerGuard.isLocked()) + return; + GuardLocker locker(m_registerGuard); - insertToolChain(tc); + if (const auto it = std::find_if( + m_toAddList.begin(), + m_toAddList.end(), + [&toolchains](ToolChainTreeItem * const item) { + return item->bundle.bundleId() == toolchains.first()->bundleId(); + }); + it != m_toAddList.end()) { + if ((*it)->bundle.toolchains().size() == toolchains.size()) + m_toAddList.erase(it); + return; + } + + const QList<ToolchainBundle> bundles = ToolchainBundle::collectBundles(toolchains); + for (const ToolchainBundle &bundle : bundles) { + ToolchainManager::registerToolchains(bundle.createdToolchains()); + insertBundle(bundle); } updateState(); } void ToolChainOptionsWidget::handleToolchainsDeregistered(const Toolchains &toolchains) { + if (m_deregisterGuard.isLocked()) + return; + GuardLocker locker(m_deregisterGuard); + + if (const auto it = std::find_if( + m_toRemoveList.begin(), + m_toRemoveList.end(), + [&toolchains](const ToolChainTreeItem *item) { + return item->bundle.toolchains() == toolchains; + }); + it != m_toRemoveList.end()) { + ToolChainTreeItem * const item = *it; + m_toRemoveList.erase(it); + delete item; + return; + } + + QList<ToolChainTreeItem *> affectedItems; for (Toolchain * const tc : toolchains) { - if (auto it = std::find_if( - m_toRemoveList.begin(), - m_toRemoveList.end(), - [tc](const ToolChainTreeItem *item) { return item->toolChain == tc; }); - it != m_toRemoveList.end()) { - m_toRemoveList.erase(it); - delete *it; - continue; - } + StaticTreeItem *parent = parentForToolchain(*tc); + auto item = static_cast<ToolChainTreeItem *>( + parent->findChildAtLevel(1, [tc](TreeItem *item) { + return static_cast<ToolChainTreeItem *>(item)->bundle.bundleId() == tc->bundleId(); + })); + const bool removed = item->bundle.removeToolchain(tc); + QTC_CHECK(removed); + affectedItems << item; + } - StaticTreeItem *parent = parentForToolChain(tc); - auto item = parent->findChildAtLevel(1, [tc](TreeItem *item) { - return static_cast<ToolChainTreeItem *>(item)->toolChain == tc; - }); + for (ToolChainTreeItem *item : std::as_const(affectedItems)) { + ToolchainManager::deregisterToolchains(item->bundle.toolchains()); + item->bundle.clearToolchains(); m_model.destroyItem(item); } updateState(); } -StaticTreeItem *ToolChainOptionsWidget::parentForToolChain(Toolchain *tc) +StaticTreeItem *ToolChainOptionsWidget::rootItem( + const LanguageCategory &languageCategory, bool autoDetected) +{ + QPair<StaticTreeItem *, StaticTreeItem *> nodes = m_languageMap.value(languageCategory); + return autoDetected ? nodes.first : nodes.second; +} + +StaticTreeItem *ToolChainOptionsWidget::parentForBundle(const ToolchainBundle &bundle) +{ + return rootItem(bundle.factory()->languageCategory(), bundle.isAutoDetected()); +} + +StaticTreeItem *ToolChainOptionsWidget::parentForToolchain(const Toolchain &tc) { - QPair<StaticTreeItem *, StaticTreeItem *> nodes = m_languageMap.value(tc->language()); - return tc->isAutoDetected() ? nodes.first : nodes.second; + return rootItem(tc.factory()->languageCategory(), tc.isAutoDetected()); } void ToolChainOptionsWidget::redetectToolchains() { - QList<ToolChainTreeItem *> itemsToRemove; + // The second element is the set of toolchains for the respective bundle that were re-discovered. + using ItemToCheck = std::pair<ToolChainTreeItem *, Toolchains>; + QList<ItemToCheck> itemsToRemove; + Toolchains knownTcs; + + // Step 1: All previously auto-detected items are candidates for removal. m_model.forAllItems([&itemsToRemove, &knownTcs](TreeItem *item) { if (item->level() != 3) return; const auto tcItem = static_cast<ToolChainTreeItem *>(item); - if (tcItem->toolChain->isAutoDetected() && !tcItem->toolChain->isSdkProvided()) - itemsToRemove << tcItem; + if (tcItem->bundle.isAutoDetected() && !tcItem->bundle.isSdkProvided()) + itemsToRemove << std::make_pair(tcItem, Toolchains()); else - knownTcs << tcItem->toolChain; + knownTcs << tcItem->bundle.toolchains(); }); + Toolchains toAdd; - QSet<Toolchain *> toDelete; ToolchainManager::resetBadToolchains(); + + // Step 2: Re-detect toolchains. for (ToolchainFactory *f : ToolchainFactory::allToolchainFactories()) { const ToolchainDetector detector(knownTcs, DeviceManager::defaultDesktopDevice(), {}); // FIXME: Pass search paths for (Toolchain * const tc : f->autoDetect(detector)) { - if (knownTcs.contains(tc) || toDelete.contains(tc)) + if (knownTcs.contains(tc)) continue; - const auto matchItem = [tc](const ToolChainTreeItem *item) { - return *item->toolChain == *tc; + knownTcs << tc; + const auto matchItem = [&](const ItemToCheck &item) { + return Utils::contains(item.first->bundle.toolchains(), [&](Toolchain *btc) { + return *btc == *tc; + }); }; - ToolChainTreeItem * const item = findOrDefault(itemsToRemove, matchItem); - if (item) { - itemsToRemove.removeOne(item); - toDelete << tc; + if (const auto item + = std::find_if(itemsToRemove.begin(), itemsToRemove.end(), matchItem); + item != itemsToRemove.end()) { + item->second << tc; continue; } - knownTcs << tc; toAdd << tc; } } - for (ToolChainTreeItem * const tcItem : std::as_const(itemsToRemove)) - markForRemoval(tcItem); - for (Toolchain * const newTc : std::as_const(toAdd)) - m_toAddList.append(insertToolChain(newTc, true)); - qDeleteAll(toDelete); + + // Step 3: Items whose toolchains were all re-discovered are no longer candidates for removal. + // Instead, delete the re-discovered toolchains. + // Conversely, if not all toolchains of the bundle were re-discovered, we remove the existing + // item and the newly discovered toolchains are marked for re-bundling. + for (const auto &[item, newToolchains] : itemsToRemove) { + if (item->bundle.toolchains().size() == newToolchains.size()) { + qDeleteAll(newToolchains); + } else { + toAdd << newToolchains; + markForRemoval(item); + } + } + + // Step 4: Create new bundles and add items for them. + const QList<ToolchainBundle> newBundles = ToolchainBundle::collectBundles(toAdd); + for (const ToolchainBundle &bundle : newBundles) + m_toAddList << insertBundle(bundle, true); } void ToolChainOptionsWidget::toolChainSelectionChanged() @@ -459,8 +534,9 @@ void ToolChainOptionsWidget::toolChainSelectionChanged() void ToolChainOptionsWidget::apply() { // Remove unused tool chains: - ToolchainManager::deregisterToolchains( - Utils::transform(m_toRemoveList, &ToolChainTreeItem::toolChain)); + const AddRemoveList toRemove = m_toRemoveList; + for (const ToolChainTreeItem * const item : toRemove) + ToolchainManager::deregisterToolchains(item->bundle.toolchains()); Q_ASSERT(m_toRemoveList.isEmpty()); @@ -469,8 +545,7 @@ void ToolChainOptionsWidget::apply() for (StaticTreeItem *parent : {autoAndManual.first, autoAndManual.second}) { for (TreeItem *item : *parent) { auto tcItem = static_cast<ToolChainTreeItem *>(item); - Q_ASSERT(tcItem->toolChain); - if (!tcItem->toolChain->isAutoDetected() && tcItem->widget() && tcItem->changed) + if (!tcItem->bundle.isAutoDetected() && tcItem->widget() && tcItem->changed) tcItem->widget()->apply(); tcItem->changed = false; tcItem->update(); @@ -478,16 +553,18 @@ void ToolChainOptionsWidget::apply() } } - // Add new (and already updated) tool chains - const Toolchains notRegistered = ToolchainManager::registerToolchains( - Utils::transform(m_toAddList, &ToolChainTreeItem::toolChain)); - const QStringList removedTcs = Utils::transform(notRegistered, &Toolchain::displayName); - - const QList<ToolChainTreeItem *> toAddList = m_toAddList; - for (ToolChainTreeItem *n : toAddList) - markForRemoval(n); - - qDeleteAll(m_toAddList); + // Add new (and already updated) toolchains + QStringList removedTcs; + const AddRemoveList toAdd = m_toAddList; + for (ToolChainTreeItem * const item : toAdd) { + const Toolchains notRegistered = ToolchainManager::registerToolchains(item->bundle.toolchains()); + removedTcs << Utils::transform(notRegistered, &Toolchain::displayName); + } + for (ToolChainTreeItem * const item : std::as_const(m_toAddList)) { + item->bundle.deleteToolchains(); + delete item; + } + m_toAddList.clear(); if (removedTcs.count() == 1) { QMessageBox::warning(Core::ICore::dialogParent(), @@ -508,41 +585,41 @@ void ToolChainOptionsWidget::apply() ToolchainManager::setDetectionSettings(m_detectionSettings); } -void ToolChainOptionsWidget::createToolChain(ToolchainFactory *factory, const Utils::Id &language) +void ToolChainOptionsWidget::createToolchains(ToolchainFactory *factory, const QList<Id> &languages) { QTC_ASSERT(factory, return); QTC_ASSERT(factory->canCreate(), return); - QTC_ASSERT(language.isValid(), return); - Toolchain *tc = factory->create(); - if (!tc) - return; - - tc->setDetection(Toolchain::ManualDetection); - tc->setLanguage(language); + const Id bundleId = Id::generate(); + Toolchains toolchains; + for (const Id lang : languages) { + Toolchain *tc = factory->create(); + QTC_ASSERT(tc, return); - auto item = insertToolChain(tc, true); - m_toAddList.append(item); + tc->setDetection(Toolchain::ManualDetection); + tc->setLanguage(lang); + tc->setBundleId(bundleId); + toolchains << tc; + } + const ToolchainBundle bundle(toolchains); + ToolChainTreeItem * const item = insertBundle(bundle, true); + m_toAddList << item; m_toolChainView->setCurrentIndex(m_sortModel.mapFromSource(m_model.indexForItem(item))); } -void ToolChainOptionsWidget::cloneToolChain() +void ToolChainOptionsWidget::cloneToolchains() { ToolChainTreeItem *current = currentTreeItem(); if (!current) return; - Toolchain *tc = current->toolChain->clone(); - if (!tc) - return; - - tc->setDetection(Toolchain::ManualDetection); - tc->setDisplayName(Tr::tr("Clone of %1").arg(current->toolChain->displayName())); - - auto item = insertToolChain(tc, true); - m_toAddList.append(item); + ToolchainBundle bundle = current->bundle.clone(); + bundle.setDetection(Toolchain::ManualDetection); + bundle.setDisplayName(Tr::tr("Clone of %1").arg(current->bundle.displayName())); + ToolChainTreeItem * const item = insertBundle(bundle, true); + m_toAddList << item; m_toolChainView->setCurrentIndex(m_sortModel.mapFromSource(m_model.indexForItem(item))); } @@ -551,9 +628,8 @@ void ToolChainOptionsWidget::updateState() bool canCopy = false; bool canDelete = false; if (ToolChainTreeItem *item = currentTreeItem()) { - Toolchain *tc = item->toolChain; - canCopy = tc->isValid(); - canDelete = !tc->isSdkProvided(); + canCopy = item->bundle.validity() != ToolchainBundle::Valid::None; + canDelete = !item->bundle.isSdkProvided(); } m_cloneButton->setEnabled(canCopy); diff --git a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp index d40a3b019fb..a12d747627c 100644 --- a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp +++ b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp @@ -326,12 +326,12 @@ public: void addToEnvironment(Environment &env) const override { Q_UNUSED(env) } FilePath makeCommand(const Environment &) const override { return "make"; } QList<OutputLineParser *> createOutputParsers() const override { return {}; } - std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget() override { return nullptr; } bool operator ==(const Toolchain &other) const override { if (!Toolchain::operator==(other)) return false; return static_cast<const TTC *>(&other)->token == token; } + bool canShareBundleImpl(const Toolchain &) const override { return false; } void fromMap(const Store &data) final { @@ -370,6 +370,11 @@ void ProjectExplorerTest::testToolChainMerging_data() setSupportedToolchainType(TestToolChainType); setToolchainConstructor([] { return new TTC; }); } + std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget( + const ToolchainBundle &) const override + { + return nullptr; + } }; TestToolchainFactory factory; diff --git a/src/plugins/qnx/qnxtoolchain.cpp b/src/plugins/qnx/qnxtoolchain.cpp index 6978a16611c..30feae7a2c7 100644 --- a/src/plugins/qnx/qnxtoolchain.cpp +++ b/src/plugins/qnx/qnxtoolchain.cpp @@ -27,7 +27,7 @@ namespace Qnx::Internal { class QnxToolchainConfigWidget : public ToolchainConfigWidget { public: - QnxToolchainConfigWidget(QnxToolchain *tc); + QnxToolchainConfigWidget(const ToolchainBundle &bundle); private: void applyImpl() override; @@ -37,7 +37,6 @@ private: void handleSdpPathChange(); - PathChooser *m_compilerCommand; PathChooser *m_sdpPath; ProjectExplorer::AbiWidget *m_abiWidget; }; @@ -116,11 +115,6 @@ QnxToolchain::QnxToolchain() }); } -std::unique_ptr<ToolchainConfigWidget> QnxToolchain::createConfigurationWidget() -{ - return std::make_unique<QnxToolchainConfigWidget>(this); -} - void QnxToolchain::addToEnvironment(Environment &env) const { if (env.expandedValueForKey("QNX_HOST").isEmpty() || @@ -166,32 +160,24 @@ bool QnxToolchain::operator ==(const Toolchain &other) const // QnxToolChainConfigWidget //--------------------------------------------------------------------------------- -QnxToolchainConfigWidget::QnxToolchainConfigWidget(QnxToolchain *tc) - : ToolchainConfigWidget(tc) - , m_compilerCommand(new PathChooser) +QnxToolchainConfigWidget::QnxToolchainConfigWidget(const ToolchainBundle &bundle) + : ToolchainConfigWidget(bundle) , m_sdpPath(new PathChooser) , m_abiWidget(new AbiWidget) { - m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand); - m_compilerCommand->setHistoryCompleter("Qnx.ToolChain.History"); - m_compilerCommand->setFilePath(tc->compilerCommand()); - m_compilerCommand->setEnabled(!tc->isAutoDetected()); - m_sdpPath->setExpectedKind(PathChooser::ExistingDirectory); m_sdpPath->setHistoryCompleter("Qnx.Sdp.History"); - m_sdpPath->setFilePath(tc->sdpPath()); - m_sdpPath->setEnabled(!tc->isAutoDetected()); + m_sdpPath->setFilePath(bundle.get<QnxToolchain>(&QnxToolchain::sdpPath)()); + m_sdpPath->setEnabled(!bundle.isAutoDetected()); const Abis abiList = detectTargetAbis(m_sdpPath->filePath()); - m_abiWidget->setAbis(abiList, tc->targetAbi()); - m_abiWidget->setEnabled(!tc->isAutoDetected() && !abiList.isEmpty()); + m_abiWidget->setAbis(abiList, bundle.targetAbi()); + m_abiWidget->setEnabled(!bundle.isAutoDetected() && !abiList.isEmpty()); - m_mainLayout->addRow(Tr::tr("&Compiler path:"), m_compilerCommand); //: SDP refers to 'Software Development Platform'. m_mainLayout->addRow(Tr::tr("SDP path:"), m_sdpPath); m_mainLayout->addRow(Tr::tr("&ABI:"), m_abiWidget); - connect(m_compilerCommand, &PathChooser::rawPathChanged, this, &ToolchainConfigWidget::dirty); connect(m_sdpPath, &PathChooser::rawPathChanged, this, &QnxToolchainConfigWidget::handleSdpPathChange); connect(m_abiWidget, &AbiWidget::abiChanged, this, &ToolchainConfigWidget::dirty); @@ -199,37 +185,30 @@ QnxToolchainConfigWidget::QnxToolchainConfigWidget(QnxToolchain *tc) void QnxToolchainConfigWidget::applyImpl() { - if (toolchain()->isAutoDetected()) + if (bundle().isAutoDetected()) return; - auto tc = static_cast<QnxToolchain *>(toolchain()); - Q_ASSERT(tc); - QString displayName = tc->displayName(); - tc->setDisplayName(displayName); // reset display name - tc->sdpPath.setValue(m_sdpPath->filePath()); - tc->setTargetAbi(m_abiWidget->currentAbi()); - tc->resetToolchain(m_compilerCommand->filePath()); + bundle().setTargetAbi(m_abiWidget->currentAbi()); + bundle().forEach<QnxToolchain>([this](QnxToolchain &tc) { + tc.sdpPath.setValue(m_sdpPath->filePath()); + tc.resetToolchain(compilerCommand(tc.language())); + }); } void QnxToolchainConfigWidget::discardImpl() { // subwidgets are not yet connected! QSignalBlocker blocker(this); - auto tc = static_cast<const QnxToolchain *>(toolchain()); - m_compilerCommand->setFilePath(tc->compilerCommand()); - m_sdpPath->setFilePath(tc->sdpPath()); - m_abiWidget->setAbis(tc->supportedAbis(), tc->targetAbi()); - if (!m_compilerCommand->filePath().toString().isEmpty()) + m_sdpPath->setFilePath(bundle().get(&QnxToolchain::sdpPath)()); + m_abiWidget->setAbis(bundle().supportedAbis(), bundle().targetAbi()); + if (hasAnyCompiler()) m_abiWidget->setEnabled(true); } bool QnxToolchainConfigWidget::isDirtyImpl() const { - auto tc = static_cast<const QnxToolchain *>(toolchain()); - Q_ASSERT(tc); - return m_compilerCommand->filePath() != tc->compilerCommand() - || m_sdpPath->filePath() != tc->sdpPath() - || m_abiWidget->currentAbi() != tc->targetAbi(); + return m_sdpPath->filePath() != bundle().get(&QnxToolchain::sdpPath)() + || m_abiWidget->currentAbi() != bundle().targetAbi(); } void QnxToolchainConfigWidget::handleSdpPathChange() @@ -275,6 +254,12 @@ public: Toolchains tcs = autoDetectHelper(detector.alreadyKnown); return tcs; } + + std::unique_ptr<ProjectExplorer::ToolchainConfigWidget> createConfigurationWidget( + const ToolchainBundle &bundle) const override + { + return std::make_unique<QnxToolchainConfigWidget>(bundle); + } }; void setupQnxToolchain() diff --git a/src/plugins/qnx/qnxtoolchain.h b/src/plugins/qnx/qnxtoolchain.h index 47a9a706439..da50e108da0 100644 --- a/src/plugins/qnx/qnxtoolchain.h +++ b/src/plugins/qnx/qnxtoolchain.h @@ -12,8 +12,6 @@ class QnxToolchain : public ProjectExplorer::GccToolchain public: QnxToolchain(); - std::unique_ptr<ProjectExplorer::ToolchainConfigWidget> createConfigurationWidget() override; - void addToEnvironment(Utils::Environment &env) const override; QStringList suggestedMkspecList() const override; diff --git a/src/plugins/webassembly/webassemblytoolchain.cpp b/src/plugins/webassembly/webassemblytoolchain.cpp index 99e8309d4a4..90c43c60d0a 100644 --- a/src/plugins/webassembly/webassemblytoolchain.cpp +++ b/src/plugins/webassembly/webassemblytoolchain.cpp @@ -13,6 +13,7 @@ #include <projectexplorer/kitmanager.h> #include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectmacro.h> +#include <projectexplorer/toolchainconfigwidget.h> #include <projectexplorer/toolchainmanager.h> #include <qtsupport/qtkitaspect.h> @@ -183,10 +184,16 @@ public: setUserCreatable(true); } - Toolchains autoDetect(const ToolchainDetector &detector) const + Toolchains autoDetect(const ToolchainDetector &detector) const override { return doAutoDetect(detector); } + + std::unique_ptr<ToolchainConfigWidget> createConfigurationWidget( + const ToolchainBundle &bundle) const override + { + return GccToolchain::createConfigurationWidget(bundle); + } }; void setupWebAssemblyToolchain() |