1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #include "toolchainmanager.h"
27
28 #include "abi.h"
29 #include "kitinformation.h"
30 #include "msvctoolchain.h"
31 #include "toolchain.h"
32 #include "toolchainsettingsaccessor.h"
33
34 #include <coreplugin/icore.h>
35
36 #include <utils/fileutils.h>
37 #include <utils/persistentsettings.h>
38 #include <utils/qtcassert.h>
39 #include <utils/algorithm.h>
40
41 #include <QDir>
42 #include <QSettings>
43
44 #include <tuple>
45
46 using namespace Utils;
47
48 namespace ProjectExplorer {
49 namespace Internal {
50
51 // --------------------------------------------------------------------------
52 // ToolChainManagerPrivate
53 // --------------------------------------------------------------------------
54
55 struct LanguageDisplayPair
56 {
57 Utils::Id id;
58 QString displayName;
59 };
60
61 class ToolChainManagerPrivate
62 {
63 public:
64 ~ToolChainManagerPrivate();
65
66 std::unique_ptr<ToolChainSettingsAccessor> m_accessor;
67
68 QList<ToolChain *> m_toolChains; // prioritized List
69 QVector<LanguageDisplayPair> m_languages;
70 ToolchainDetectionSettings m_detectionSettings;
71 bool m_loaded = false;
72 };
73
~ToolChainManagerPrivate()74 ToolChainManagerPrivate::~ToolChainManagerPrivate()
75 {
76 qDeleteAll(m_toolChains);
77 m_toolChains.clear();
78 }
79
80 static ToolChainManager *m_instance = nullptr;
81 static ToolChainManagerPrivate *d = nullptr;
82
83 } // namespace Internal
84
85 using namespace Internal;
86
87 const char DETECT_X64_AS_X32_KEY[] = "ProjectExplorer/Toolchains/DetectX64AsX32";
88
89 // --------------------------------------------------------------------------
90 // ToolChainManager
91 // --------------------------------------------------------------------------
92
ToolChainManager(QObject * parent)93 ToolChainManager::ToolChainManager(QObject *parent) :
94 QObject(parent)
95 {
96 Q_ASSERT(!m_instance);
97 m_instance = this;
98
99 d = new ToolChainManagerPrivate;
100
101 connect(Core::ICore::instance(), &Core::ICore::saveSettingsRequested,
102 this, &ToolChainManager::saveToolChains);
103 connect(this, &ToolChainManager::toolChainAdded, this, &ToolChainManager::toolChainsChanged);
104 connect(this, &ToolChainManager::toolChainRemoved, this, &ToolChainManager::toolChainsChanged);
105 connect(this, &ToolChainManager::toolChainUpdated, this, &ToolChainManager::toolChainsChanged);
106
107 QSettings * const s = Core::ICore::settings();
108 d->m_detectionSettings.detectX64AsX32
109 = s->value(DETECT_X64_AS_X32_KEY, ToolchainDetectionSettings().detectX64AsX32).toBool();
110 }
111
~ToolChainManager()112 ToolChainManager::~ToolChainManager()
113 {
114 m_instance = nullptr;
115 delete d;
116 d = nullptr;
117 }
118
instance()119 ToolChainManager *ToolChainManager::instance()
120 {
121 return m_instance;
122 }
123
restoreToolChains()124 void ToolChainManager::restoreToolChains()
125 {
126 QTC_ASSERT(!d->m_accessor, return);
127 d->m_accessor = std::make_unique<Internal::ToolChainSettingsAccessor>();
128
129 for (ToolChain *tc : d->m_accessor->restoreToolChains(Core::ICore::dialogParent()))
130 registerToolChain(tc);
131
132 d->m_loaded = true;
133 emit m_instance->toolChainsLoaded();
134 }
135
saveToolChains()136 void ToolChainManager::saveToolChains()
137 {
138 QTC_ASSERT(d->m_accessor, return);
139
140 d->m_accessor->saveToolChains(d->m_toolChains, Core::ICore::dialogParent());
141 QtcSettings *const s = Core::ICore::settings();
142 s->setValueWithDefault(DETECT_X64_AS_X32_KEY,
143 d->m_detectionSettings.detectX64AsX32,
144 ToolchainDetectionSettings().detectX64AsX32);
145 }
146
toolChains(const ToolChain::Predicate & predicate)147 QList<ToolChain *> ToolChainManager::toolChains(const ToolChain::Predicate &predicate)
148 {
149 if (predicate)
150 return Utils::filtered(d->m_toolChains, predicate);
151 return d->m_toolChains;
152 }
153
toolChain(const ToolChain::Predicate & predicate)154 ToolChain *ToolChainManager::toolChain(const ToolChain::Predicate &predicate)
155 {
156 return Utils::findOrDefault(d->m_toolChains, predicate);
157 }
158
findToolChains(const Abi & abi)159 QList<ToolChain *> ToolChainManager::findToolChains(const Abi &abi)
160 {
161 QList<ToolChain *> result;
162 foreach (ToolChain *tc, d->m_toolChains) {
163 bool isCompatible = Utils::anyOf(tc->supportedAbis(), [abi](const Abi &supportedAbi) {
164 return supportedAbi.isCompatibleWith(abi);
165 });
166
167 if (isCompatible)
168 result.append(tc);
169 }
170 return result;
171 }
172
findToolChain(const QByteArray & id)173 ToolChain *ToolChainManager::findToolChain(const QByteArray &id)
174 {
175 if (id.isEmpty())
176 return nullptr;
177
178 ToolChain *tc = Utils::findOrDefault(d->m_toolChains, Utils::equal(&ToolChain::id, id));
179
180 // Compatibility with versions 3.5 and earlier:
181 if (!tc) {
182 const int pos = id.indexOf(':');
183 if (pos < 0)
184 return tc;
185
186 const QByteArray shortId = id.mid(pos + 1);
187
188 tc = Utils::findOrDefault(d->m_toolChains, Utils::equal(&ToolChain::id, shortId));
189 }
190 return tc;
191 }
192
isLoaded()193 bool ToolChainManager::isLoaded()
194 {
195 return d->m_loaded;
196 }
197
notifyAboutUpdate(ToolChain * tc)198 void ToolChainManager::notifyAboutUpdate(ToolChain *tc)
199 {
200 if (!tc || !d->m_toolChains.contains(tc))
201 return;
202 emit m_instance->toolChainUpdated(tc);
203 }
204
registerToolChain(ToolChain * tc)205 bool ToolChainManager::registerToolChain(ToolChain *tc)
206 {
207 QTC_ASSERT(tc, return false);
208 QTC_ASSERT(isLanguageSupported(tc->language()),
209 qDebug() << qPrintable("language \"" + tc->language().toString()
210 + "\" unknown while registering \""
211 + tc->compilerCommand().toString() + "\"");
212 return false);
213 QTC_ASSERT(d->m_accessor, return false);
214
215 if (d->m_toolChains.contains(tc))
216 return true;
217 foreach (ToolChain *current, d->m_toolChains) {
218 if (*tc == *current && !tc->isAutoDetected())
219 return false;
220 QTC_ASSERT(current->id() != tc->id(), return false);
221 }
222
223 d->m_toolChains.append(tc);
224 emit m_instance->toolChainAdded(tc);
225 return true;
226 }
227
deregisterToolChain(ToolChain * tc)228 void ToolChainManager::deregisterToolChain(ToolChain *tc)
229 {
230 if (!tc || !d->m_toolChains.contains(tc))
231 return;
232 d->m_toolChains.removeOne(tc);
233 emit m_instance->toolChainRemoved(tc);
234 delete tc;
235 }
236
allLanguages()237 QList<Id> ToolChainManager::allLanguages()
238 {
239 return Utils::transform<QList>(d->m_languages, &LanguageDisplayPair::id);
240 }
241
registerLanguage(const Utils::Id & language,const QString & displayName)242 bool ToolChainManager::registerLanguage(const Utils::Id &language, const QString &displayName)
243 {
244 QTC_ASSERT(language.isValid(), return false);
245 QTC_ASSERT(!isLanguageSupported(language), return false);
246 QTC_ASSERT(!displayName.isEmpty(), return false);
247 d->m_languages.push_back({language, displayName});
248 return true;
249 }
250
displayNameOfLanguageId(const Utils::Id & id)251 QString ToolChainManager::displayNameOfLanguageId(const Utils::Id &id)
252 {
253 QTC_ASSERT(id.isValid(), return tr("None"));
254 auto entry = Utils::findOrDefault(d->m_languages, Utils::equal(&LanguageDisplayPair::id, id));
255 QTC_ASSERT(entry.id.isValid(), return tr("None"));
256 return entry.displayName;
257 }
258
isLanguageSupported(const Utils::Id & id)259 bool ToolChainManager::isLanguageSupported(const Utils::Id &id)
260 {
261 return Utils::contains(d->m_languages, Utils::equal(&LanguageDisplayPair::id, id));
262 }
263
aboutToShutdown()264 void ToolChainManager::aboutToShutdown()
265 {
266 if (HostOsInfo::isWindowsHost())
267 MsvcToolChain::cancelMsvcToolChainDetection();
268 }
269
detectionSettings()270 ToolchainDetectionSettings ToolChainManager::detectionSettings()
271 {
272 return d->m_detectionSettings;
273 }
274
setDetectionSettings(const ToolchainDetectionSettings & settings)275 void ToolChainManager::setDetectionSettings(const ToolchainDetectionSettings &settings)
276 {
277 d->m_detectionSettings = settings;
278 }
279
280 } // namespace ProjectExplorer
281