Qnx: auto-detected BlackBerry kits have mutable Device field
[qt-creator:qt-creator.git] / src / plugins / qnx / blackberryconfiguration.cpp
1 /**************************************************************************
2 **
3 ** Copyright (C) 2011 - 2013 Research In Motion
4 **
5 ** Contact: Research In Motion (blackberry-qt@qnx.com)
6 ** Contact: KDAB (info@kdab.com)
7 **
8 ** This file is part of Qt Creator.
9 **
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Digia.  For licensing terms and
15 ** conditions see http://qt.digia.com/licensing.  For further information
16 ** use the contact form at http://qt.digia.com/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 2.1 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL included in the
22 ** packaging of this file.  Please review the following information to
23 ** ensure the GNU Lesser General Public License version 2.1 requirements
24 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** In addition, as a special exception, Digia gives you certain additional
27 ** rights.  These rights are described in the Digia Qt LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ****************************************************************************/
31
32 #include "blackberryconfiguration.h"
33 #include "blackberryqtversion.h"
34
35 #include "qnxutils.h"
36
37 #include <projectexplorer/projectexplorerconstants.h>
38 #include <projectexplorer/kitmanager.h>
39 #include <projectexplorer/kitinformation.h>
40 #include <projectexplorer/toolchainmanager.h>
41
42 #include <qtsupport/baseqtversion.h>
43 #include <qtsupport/qtversionmanager.h>
44 #include <qtsupport/qtkitinformation.h>
45
46 #include <qt4projectmanager/qmakekitinformation.h>
47
48 #include <debugger/debuggerkitinformation.h>
49
50 #include <QFileInfo>
51 #include <QDir>
52 #include <QMessageBox>
53
54 using namespace ProjectExplorer;
55 using namespace QtSupport;
56 using namespace Utils;
57
58 namespace Qnx {
59 namespace Internal {
60
61 BlackBerryConfiguration::BlackBerryConfiguration(const FileName &ndkEnvFile, bool isAutoDetected,
62                                                  const QString &displayName)
63 {
64     Q_ASSERT(!QFileInfo(ndkEnvFile.toString()).isDir());
65     m_ndkEnvFile = ndkEnvFile;
66     m_isAutoDetected = isAutoDetected;
67     QString ndkPath = ndkEnvFile.parentDir().toString();
68     m_displayName = displayName.isEmpty() ? ndkPath.split(QDir::separator()).last() : displayName;
69     m_qnxEnv = QnxUtils::parseEnvironmentFile(m_ndkEnvFile.toString());
70
71     QString ndkTarget = m_qnxEnv.value(QLatin1String("QNX_TARGET"));
72     QString sep = QString::fromLatin1("%1qnx6").arg(QDir::separator());
73     m_targetName = ndkTarget.split(sep).first().split(QDir::separator()).last();
74
75     if (QDir(ndkTarget).exists())
76         m_sysRoot = FileName::fromString(ndkTarget);
77
78     QString qnxHost = m_qnxEnv.value(QLatin1String("QNX_HOST"));
79     FileName qmake4Path = QnxUtils::executableWithExtension(FileName::fromString(qnxHost + QLatin1String("/usr/bin/qmake")));
80     FileName qmake5Path = QnxUtils::executableWithExtension(FileName::fromString(qnxHost + QLatin1String("/usr/bin/qt5/qmake")));
81     FileName gccPath = QnxUtils::executableWithExtension(FileName::fromString(qnxHost + QLatin1String("/usr/bin/qcc")));
82     FileName deviceGdbPath = QnxUtils::executableWithExtension(FileName::fromString(qnxHost + QLatin1String("/usr/bin/ntoarm-gdb")));
83     FileName simulatorGdbPath = QnxUtils::executableWithExtension(FileName::fromString(qnxHost + QLatin1String("/usr/bin/ntox86-gdb")));
84
85     if (qmake4Path.toFileInfo().exists())
86         m_qmake4BinaryFile = qmake4Path;
87
88     if (qmake5Path.toFileInfo().exists())
89         m_qmake5BinaryFile = qmake5Path;
90
91     if (gccPath.toFileInfo().exists())
92         m_gccCompiler = gccPath;
93
94     if (deviceGdbPath.toFileInfo().exists())
95         m_deviceDebuger = deviceGdbPath;
96
97     if (simulatorGdbPath.toFileInfo().exists())
98         m_simulatorDebuger = simulatorGdbPath;
99
100 }
101
102 QString BlackBerryConfiguration::ndkPath() const
103 {
104     return m_ndkEnvFile.parentDir().toString();
105 }
106
107 QString BlackBerryConfiguration::displayName() const
108 {
109     return m_displayName;
110 }
111
112 QString BlackBerryConfiguration::targetName() const
113 {
114     return m_targetName;
115 }
116
117 bool BlackBerryConfiguration::isAutoDetected() const
118 {
119     return m_isAutoDetected;
120 }
121
122 bool BlackBerryConfiguration::isActive() const
123 {
124     BaseQtVersion *qt4Version = QtVersionManager::qtVersionForQMakeBinary(m_qmake4BinaryFile);
125     BaseQtVersion *qt5Version = QtVersionManager::qtVersionForQMakeBinary(m_qmake5BinaryFile);
126     return (qt4Version || qt5Version);
127 }
128
129 bool BlackBerryConfiguration::isValid() const
130 {
131     return !((m_qmake4BinaryFile.isEmpty() && m_qmake5BinaryFile.isEmpty()) || m_gccCompiler.isEmpty()
132             || m_deviceDebuger.isEmpty() || m_simulatorDebuger.isEmpty());
133 }
134
135 FileName BlackBerryConfiguration::ndkEnvFile() const
136 {
137     return m_ndkEnvFile;
138 }
139
140 FileName BlackBerryConfiguration::qmake4BinaryFile() const
141 {
142     return m_qmake4BinaryFile;
143 }
144
145 FileName BlackBerryConfiguration::qmake5BinaryFile() const
146 {
147     return m_qmake5BinaryFile;
148 }
149
150 FileName BlackBerryConfiguration::gccCompiler() const
151 {
152     return m_gccCompiler;
153 }
154
155 FileName BlackBerryConfiguration::deviceDebuger() const
156 {
157     return m_deviceDebuger;
158 }
159
160 FileName BlackBerryConfiguration::simulatorDebuger() const
161 {
162     return m_simulatorDebuger;
163 }
164
165 FileName BlackBerryConfiguration::sysRoot() const
166 {
167     return m_sysRoot;
168 }
169
170 QMultiMap<QString, QString> BlackBerryConfiguration::qnxEnv() const
171 {
172     return m_qnxEnv;
173 }
174
175 void BlackBerryConfiguration::setupConfigurationPerQtVersion(const FileName &qmakePath, GccToolChain *tc)
176 {
177     if (qmakePath.isEmpty() || !tc)
178         return;
179
180     BaseQtVersion *qtVersion = createQtVersion(qmakePath);
181     Kit *deviceKit = createKit(ArmLeV7, qtVersion, tc);
182     Kit *simulatorKit = createKit(X86, qtVersion, tc);
183     if (qtVersion && tc && deviceKit && simulatorKit) {
184         if (!qtVersion->qtAbis().isEmpty())
185             tc->setTargetAbi(qtVersion->qtAbis().first());
186         // register
187         QtVersionManager::addVersion(qtVersion);
188         ToolChainManager::registerToolChain(tc);
189         KitManager::registerKit(deviceKit);
190         KitManager::registerKit(simulatorKit);
191     }
192 }
193
194 BaseQtVersion *BlackBerryConfiguration::createQtVersion(const FileName &qmakePath)
195 {
196     if (qmakePath.isEmpty())
197         return 0;
198
199     QString cpuDir = m_qnxEnv.value(QLatin1String("CPUVARDIR"));
200     BaseQtVersion *version = QtVersionManager::qtVersionForQMakeBinary(qmakePath);
201     if (version) {
202         if (!m_isAutoDetected)
203             QMessageBox::warning(0, tr("Qt Version Already Known"),
204                              tr("This Qt version was already registered."), QMessageBox::Ok);
205         return version;
206     }
207
208     version = new BlackBerryQtVersion(QnxUtils::cpudirToArch(cpuDir), qmakePath, m_isAutoDetected, QString(), m_ndkEnvFile.toString());
209     if (!version) {
210         if (!m_isAutoDetected)
211             QMessageBox::warning(0, tr("Invalid Qt Version"),
212                              tr("Unable to add BlackBerry Qt version."), QMessageBox::Ok);
213         return 0;
214     }
215
216     version->setDisplayName(QString::fromLatin1("Qt %1 BlackBerry 10 (%2)").arg(version->qtVersionString(), m_targetName));
217     return version;
218 }
219
220 GccToolChain *BlackBerryConfiguration::createGccToolChain()
221 {
222     if ((m_qmake4BinaryFile.isEmpty() && m_qmake5BinaryFile.isEmpty()) || m_gccCompiler.isEmpty())
223         return 0;
224
225     foreach (ToolChain *tc, ToolChainManager::toolChains()) {
226         if (tc->compilerCommand() == m_gccCompiler) {
227             if (!m_isAutoDetected)
228                 QMessageBox::warning(0, tr("Compiler Already Known"),
229                                  tr("This compiler was already registered."), QMessageBox::Ok);
230             return dynamic_cast<GccToolChain *>(tc);
231         }
232     }
233
234     GccToolChain* tc = new GccToolChain(QLatin1String(ProjectExplorer::Constants::GCC_TOOLCHAIN_ID), m_isAutoDetected ? ToolChain::AutoDetection : ToolChain::ManualDetection);
235     tc->setDisplayName(QString::fromLatin1("GCC BlackBerry 10 (%1)").arg(m_targetName));
236     tc->setCompilerCommand(m_gccCompiler);
237
238     return tc;
239 }
240
241 Kit *BlackBerryConfiguration::createKit(QnxArchitecture arch, BaseQtVersion *qtVersion, GccToolChain *tc)
242 {
243     if (!qtVersion || !tc || m_targetName.isEmpty())
244         return 0;
245
246     // Check if an identical kit already exists
247     foreach (Kit *kit, KitManager::kits()) {
248         if (QtKitInformation::qtVersion(kit) == qtVersion && ToolChainKitInformation::toolChain(kit) == tc
249                 && DeviceTypeKitInformation::deviceTypeId(kit) == Constants::QNX_BB_OS_TYPE
250                 && SysRootKitInformation::sysRoot(kit) == m_sysRoot) {
251             if ((arch == X86 && Qt4ProjectManager::QmakeKitInformation::mkspec(kit).toString() == QString::fromLatin1("blackberry-x86-qcc")
252                  && Debugger::DebuggerKitInformation::debuggerCommand(kit) == m_simulatorDebuger)
253                     || (arch == ArmLeV7 && Debugger::DebuggerKitInformation::debuggerCommand(kit) == m_deviceDebuger)) {
254                 if (!m_isAutoDetected)
255                     QMessageBox::warning(0, tr("Kit Already Known"),
256                                      tr("This kit was already registered."), QMessageBox::Ok);
257                 setSticky(kit);
258                 return kit;
259             }
260         }
261     }
262
263     Kit *kit = new Kit;
264     QtKitInformation::setQtVersion(kit, qtVersion);
265     ToolChainKitInformation::setToolChain(kit, tc);
266     if (arch == X86) {
267         Debugger::DebuggerKitInformation::setDebugger(kit, Debugger::GdbEngineType, m_simulatorDebuger);
268         Qt4ProjectManager::QmakeKitInformation::setMkspec(kit, FileName::fromString(QString::fromLatin1("blackberry-x86-qcc")));
269         // TODO: Check if the name already exists(?)
270         kit->setDisplayName(tr("BlackBerry 10 (%1 - %2) - Simulator").arg(qtVersion->qtVersionString(), m_targetName));
271     } else {
272         Debugger::DebuggerKitInformation::setDebugger(kit, Debugger::GdbEngineType, m_deviceDebuger);
273         kit->setDisplayName(tr("BlackBerry 10 (%1 - %2)").arg(qtVersion->qtVersionString(), m_targetName));
274     }
275
276
277     kit->setAutoDetected(m_isAutoDetected);
278     kit->setIconPath(FileName::fromString(QLatin1String(Constants::QNX_BB_CATEGORY_ICON)));
279     kit->setMutable(DeviceKitInformation::id(), true);
280     setSticky(kit);
281     DeviceTypeKitInformation::setDeviceTypeId(kit, Constants::QNX_BB_OS_TYPE);
282     SysRootKitInformation::setSysRoot(kit, m_sysRoot);
283
284     return kit;
285 }
286
287 void BlackBerryConfiguration::setSticky(Kit *kit)
288 {
289     kit->setSticky(QtKitInformation::id(), true);
290     kit->setSticky(ToolChainKitInformation::id(), true);
291     kit->setSticky(DeviceTypeKitInformation::id(), true);
292     kit->setSticky(SysRootKitInformation::id(), true);
293     kit->setSticky(Debugger::DebuggerKitInformation::id(), true);
294     kit->setSticky(Qt4ProjectManager::QmakeKitInformation::id(), true);
295 }
296
297 bool BlackBerryConfiguration::activate()
298 {
299     if (!isValid()) {
300         if (m_isAutoDetected)
301             return false;
302
303         QString errorMessage = tr("The following errors occurred while activating Target: %1").arg(m_targetName);
304         if (m_qmake4BinaryFile.isEmpty() && m_qmake5BinaryFile.isEmpty())
305             errorMessage += QLatin1Char('\n') + tr("- No Qt version found.");
306
307         if (m_gccCompiler.isEmpty())
308             errorMessage += QLatin1Char('\n') + tr("- No GCC compiler found.");
309
310         if (m_deviceDebuger.isEmpty())
311             errorMessage += QLatin1Char('\n') + tr("- No GDB debugger found for BB10 Device.");
312
313         if (!m_simulatorDebuger.isEmpty())
314             errorMessage += QLatin1Char('\n') + tr("- No GDB debugger found for BB10 Simulator.");
315
316         QMessageBox::warning(0, tr("Cannot Set up BB10 Configuration"),
317                              errorMessage, QMessageBox::Ok);
318         return false;
319     }
320
321     if (isActive() && !m_isAutoDetected)
322         return true;
323
324     GccToolChain *tc = createGccToolChain();
325     if (!m_qmake4BinaryFile.isEmpty())
326         setupConfigurationPerQtVersion(m_qmake4BinaryFile, tc);
327
328     if (!m_qmake5BinaryFile.isEmpty())
329         setupConfigurationPerQtVersion(m_qmake5BinaryFile, tc);
330
331     return true;
332 }
333
334 void BlackBerryConfiguration::deactivate()
335 {
336     BaseQtVersion *qt4Version = QtVersionManager::qtVersionForQMakeBinary(m_qmake4BinaryFile);
337     BaseQtVersion *qt5Version = QtVersionManager::qtVersionForQMakeBinary(m_qmake5BinaryFile);
338     if (qt4Version || qt5Version) {
339         foreach (Kit *kit, KitManager::kits()) {
340             if (qt4Version && qt4Version == QtKitInformation::qtVersion(kit))
341                 KitManager::deregisterKit(kit);
342
343             else if (qt5Version && qt5Version == QtKitInformation::qtVersion(kit))
344                 KitManager::deregisterKit(kit);
345         }
346
347         if (qt4Version)
348             QtVersionManager::removeVersion(qt4Version);
349
350         if (qt5Version)
351             QtVersionManager::removeVersion(qt5Version);
352
353     }
354
355     foreach (ToolChain *tc, ToolChainManager::toolChains())
356         if (tc->compilerCommand() == m_gccCompiler)
357             ToolChainManager::deregisterToolChain(tc);
358 }
359
360 } // namespace Internal
361 } // namespace Qnx