aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Kandeler <[email protected]>2024-07-11 13:03:12 +0200
committerChristian Kandeler <[email protected]>2024-08-05 15:35:48 +0000
commit020883c47f62151684f5d72cb7204b6fc7061934 (patch)
tree590a4bf2b2674b2283cc52854e2342400e73f08d
parent08d6b861623067eab11eeb7869228540e463fac7 (diff)
ProjectExplorer: Stop pretending that C and C++ compilers are unrelated
Motivation: a) It was ridiculous that when users wanted to manually add a new toolchain, they had to do the entire setup twice. b) It was equally weird that users had to take care to choose matching toolchains when setting up a kit, or indeed that it was even possible to mix random toolchains in the first place. User-visible changes: - The "C" and "C++" categories in the toolchain settings page have been merged into a single "C/C++" category. - When adding a new toolchain, the "C" and "C++" sub-menus are gone. Instead, the toolchain config widget offers two path choosers if the respective toolchain type supports C and C++ compilers. - By default, the C++ compiler file path is derived from the C compiler file path automatically, so the user usually has to enter only the former. - In the kit settings page, the "C" and "C++" toolchain combo boxes have been replaced by a single "C/C++" combo box, relieving the user of the responsibility to choose two matching toolchains. Implementation: The notion that a Toolchain object corresponds to a single compiler is so deeply engrained in the code that it cannot realistically be changed in the short term. We therefore introduce the concept of a "toolchain bundle" as an additional layer that groups matching C and C++ toolchains together. This way, most code dealing with toolchains stays unchanged, and only the presentation layer (i.e. the toolchain and kit settings pages) needed to be rewritten. Once set up in a bundle, toolchains stay implicitly linked together so the matching only needs to be done once. In follow-up patches, we will make use of toolchain bundles in all the places where kits are auto-created, eliminating the risk of mixing incompatible toolchains in a kit. Change-Id: Ie6c5add9963e7c1096268dd77acd624671b2674f Reviewed-by: Christian Stenger <[email protected]> Reviewed-by: hjk <[email protected]>
-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()