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