aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/android/androidtoolchain.cpp13
-rw-r--r--src/plugins/baremetal/iarewtoolchain.cpp102
-rw-r--r--src/plugins/baremetal/keiltoolchain.cpp81
-rw-r--r--src/plugins/baremetal/sdcctoolchain.cpp58
-rw-r--r--src/plugins/cppeditor/projectinfo_test.cpp5
-rw-r--r--src/plugins/ios/iosconfigurations.cpp7
-rw-r--r--src/plugins/mcusupport/test/unittest.cpp2
-rw-r--r--src/plugins/nim/project/nimtoolchain.cpp57
-rw-r--r--src/plugins/nim/project/nimtoolchain.h3
-rw-r--r--src/plugins/projectexplorer/customtoolchain.cpp120
-rw-r--r--src/plugins/projectexplorer/gcctoolchain.cpp268
-rw-r--r--src/plugins/projectexplorer/gcctoolchain.h17
-rw-r--r--src/plugins/projectexplorer/kitaspects.cpp89
-rw-r--r--src/plugins/projectexplorer/msvctoolchain.cpp147
-rw-r--r--src/plugins/projectexplorer/msvctoolchain.h6
-rw-r--r--src/plugins/projectexplorer/projectexplorer.cpp2
-rw-r--r--src/plugins/projectexplorer/toolchain.cpp260
-rw-r--r--src/plugins/projectexplorer/toolchain.h112
-rw-r--r--src/plugins/projectexplorer/toolchainconfigwidget.cpp124
-rw-r--r--src/plugins/projectexplorer/toolchainconfigwidget.h29
-rw-r--r--src/plugins/projectexplorer/toolchainmanager.cpp36
-rw-r--r--src/plugins/projectexplorer/toolchainmanager.h6
-rw-r--r--src/plugins/projectexplorer/toolchainoptionspage.cpp322
-rw-r--r--src/plugins/projectexplorer/toolchainsettingsaccessor.cpp7
-rw-r--r--src/plugins/qnx/qnxtoolchain.cpp63
-rw-r--r--src/plugins/qnx/qnxtoolchain.h2
-rw-r--r--src/plugins/webassembly/webassemblytoolchain.cpp9
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 &macros = 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 &macros = 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 &macroCache) 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 &macros) 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()