~bzoltan/kubuntu-packaging/decouple_cmake_plugin

« back to all changes in this revision

Viewing changes to src/plugins/debugger/debuggeritemmanager.cpp

  • Committer: Timo Jyrinki
  • Date: 2013-12-02 09:16:15 UTC
  • mfrom: (1.1.29)
  • Revision ID: timo.jyrinki@canonical.com-20131202091615-xbj1os1f604ber1m
New upstream release candidate.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
 
4
** Contact: http://www.qt-project.org/legal
 
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 Digia.  For licensing terms and
 
13
** conditions see http://qt.digia.com/licensing.  For further information
 
14
** use the contact form at http://qt.digia.com/contact-us.
 
15
**
 
16
** GNU Lesser General Public License Usage
 
17
** Alternatively, this file may be used under the terms of the GNU Lesser
 
18
** General Public License version 2.1 as published by the Free Software
 
19
** Foundation and appearing in the file LICENSE.LGPL included in the
 
20
** packaging of this file.  Please review the following information to
 
21
** ensure the GNU Lesser General Public License version 2.1 requirements
 
22
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 
23
**
 
24
** In addition, as a special exception, Digia gives you certain additional
 
25
** rights.  These rights are described in the Digia Qt LGPL Exception
 
26
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 
27
**
 
28
****************************************************************************/
 
29
 
 
30
#include "debuggeritemmanager.h"
 
31
 
 
32
#include "debuggeritemmodel.h"
 
33
#include "debuggerkitinformation.h"
 
34
 
 
35
#include <coreplugin/icore.h>
 
36
 
 
37
#include <utils/environment.h>
 
38
#include <utils/fileutils.h>
 
39
#include <utils/persistentsettings.h>
 
40
#include <utils/qtcassert.h>
 
41
#include <utils/hostosinfo.h>
 
42
 
 
43
#include <QDebug>
 
44
#include <QDir>
 
45
#include <QFileInfo>
 
46
#include <QProcess>
 
47
 
 
48
using namespace ProjectExplorer;
 
49
using namespace Utils;
 
50
 
 
51
namespace Debugger {
 
52
 
 
53
static const char DEBUGGER_COUNT_KEY[] = "DebuggerItem.Count";
 
54
static const char DEBUGGER_DATA_KEY[] = "DebuggerItem.";
 
55
static const char DEBUGGER_LEGACY_FILENAME[] = "/qtcreator/profiles.xml";
 
56
static const char DEBUGGER_FILE_VERSION_KEY[] = "Version";
 
57
static const char DEBUGGER_FILENAME[] = "/qtcreator/debuggers.xml";
 
58
 
 
59
// --------------------------------------------------------------------------
 
60
// DebuggerItemManager
 
61
// --------------------------------------------------------------------------
 
62
 
 
63
static DebuggerItemManager *m_instance = 0;
 
64
 
 
65
static FileName userSettingsFileName()
 
66
{
 
67
    QFileInfo settingsLocation(Core::ICore::settings()->fileName());
 
68
    return FileName::fromString(settingsLocation.absolutePath() + QLatin1String(DEBUGGER_FILENAME));
 
69
}
 
70
 
 
71
static void readDebuggers(const FileName &fileName, bool isSystem)
 
72
{
 
73
    PersistentSettingsReader reader;
 
74
    if (!reader.load(fileName))
 
75
        return;
 
76
    QVariantMap data = reader.restoreValues();
 
77
 
 
78
    // Check version
 
79
    int version = data.value(QLatin1String(DEBUGGER_FILE_VERSION_KEY), 0).toInt();
 
80
    if (version < 1)
 
81
        return;
 
82
 
 
83
    int count = data.value(QLatin1String(DEBUGGER_COUNT_KEY), 0).toInt();
 
84
    for (int i = 0; i < count; ++i) {
 
85
        const QString key = QString::fromLatin1(DEBUGGER_DATA_KEY) + QString::number(i);
 
86
        if (!data.contains(key))
 
87
            continue;
 
88
        const QVariantMap dbMap = data.value(key).toMap();
 
89
        DebuggerItem item(dbMap);
 
90
        if (isSystem) {
 
91
            item.setAutoDetected(true);
 
92
            // SDK debuggers are always considered to be up-to-date, so no need to recheck them.
 
93
        } else {
 
94
            // User settings.
 
95
            if (item.isAutoDetected() && (!item.isValid() || item.engineType() == NoEngineType)) {
 
96
                qWarning() << QString::fromLatin1("DebuggerItem \"%1\" (%2) dropped since it is not valid")
 
97
                              .arg(item.command().toString()).arg(item.id().toString());
 
98
                continue;
 
99
            }
 
100
        }
 
101
        DebuggerItemManager::registerDebugger(item);
 
102
    }
 
103
}
 
104
 
 
105
QList<DebuggerItem> DebuggerItemManager::m_debuggers;
 
106
PersistentSettingsWriter * DebuggerItemManager::m_writer = 0;
 
107
 
 
108
DebuggerItemManager::DebuggerItemManager(QObject *parent)
 
109
    : QObject(parent)
 
110
{
 
111
    m_instance = this;
 
112
    m_writer = new PersistentSettingsWriter(userSettingsFileName(), QLatin1String("QtCreatorDebugger"));
 
113
    connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()),
 
114
            this, SLOT(saveDebuggers()));
 
115
}
 
116
 
 
117
QObject *DebuggerItemManager::instance()
 
118
{
 
119
    return m_instance;
 
120
}
 
121
 
 
122
DebuggerItemManager::~DebuggerItemManager()
 
123
{
 
124
    disconnect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()),
 
125
            this, SLOT(saveDebuggers()));
 
126
    delete m_writer;
 
127
}
 
128
 
 
129
QList<DebuggerItem> DebuggerItemManager::debuggers()
 
130
{
 
131
    return m_debuggers;
 
132
}
 
133
 
 
134
void DebuggerItemManager::autoDetectCdbDebuggers()
 
135
{
 
136
    QList<FileName> cdbs;
 
137
 
 
138
    QStringList programDirs;
 
139
    programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramFiles")));
 
140
    programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramFiles(x86)")));
 
141
    programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramW6432")));
 
142
 
 
143
    foreach (const QString &dirName, programDirs) {
 
144
        if (dirName.isEmpty())
 
145
            continue;
 
146
        QDir dir(dirName);
 
147
        // Windows SDK's starting from version 8 live in
 
148
        // "ProgramDir\Windows Kits\<version>"
 
149
        const QString windowsKitsFolderName = QLatin1String("Windows Kits");
 
150
        if (dir.exists(windowsKitsFolderName)) {
 
151
            QDir windowKitsFolder = dir;
 
152
            if (windowKitsFolder.cd(windowsKitsFolderName)) {
 
153
                // Check in reverse order (latest first)
 
154
                const QFileInfoList kitFolders =
 
155
                    windowKitsFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot,
 
156
                                                   QDir::Time | QDir::Reversed);
 
157
                foreach (const QFileInfo &kitFolderFi, kitFolders) {
 
158
                    const QString path = kitFolderFi.absoluteFilePath();
 
159
                    const QFileInfo cdb32(path + QLatin1String("/Debuggers/x86/cdb.exe"));
 
160
                    if (cdb32.isExecutable())
 
161
                        cdbs.append(FileName::fromString(cdb32.absoluteFilePath()));
 
162
                    const QFileInfo cdb64(path + QLatin1String("/Debuggers/x64/cdb.exe"));
 
163
                    if (cdb64.isExecutable())
 
164
                        cdbs.append(FileName::fromString(cdb64.absoluteFilePath()));
 
165
                }
 
166
            }
 
167
        }
 
168
 
 
169
        // Pre Windows SDK 8: Check 'Debugging Tools for Windows'
 
170
        foreach (const QFileInfo &fi, dir.entryInfoList(QStringList(QLatin1String("Debugging Tools for Windows*")),
 
171
                                                        QDir::Dirs | QDir::NoDotAndDotDot)) {
 
172
            FileName filePath(fi);
 
173
            filePath.appendPath(QLatin1String("cdb.exe"));
 
174
            if (!cdbs.contains(filePath))
 
175
                cdbs.append(filePath);
 
176
        }
 
177
    }
 
178
 
 
179
    foreach (const FileName &cdb, cdbs) {
 
180
        if (findByCommand(cdb))
 
181
            continue;
 
182
        DebuggerItem item;
 
183
        item.createId();
 
184
        item.setAutoDetected(true);
 
185
        item.setAbis(Abi::abisOfBinary(cdb));
 
186
        item.setCommand(cdb);
 
187
        item.setEngineType(CdbEngineType);
 
188
        item.setDisplayName(uniqueDisplayName(tr("Auto-detected CDB at %1").arg(cdb.toUserOutput())));
 
189
        addDebugger(item);
 
190
    }
 
191
}
 
192
 
 
193
void DebuggerItemManager::autoDetectGdbOrLldbDebuggers()
 
194
{
 
195
    QStringList filters;
 
196
    filters.append(QLatin1String("gdb-i686-pc-mingw32"));
 
197
    filters.append(QLatin1String("gdb"));
 
198
    filters.append(QLatin1String("lldb"));
 
199
    filters.append(QLatin1String("lldb-*"));
 
200
 
 
201
//    DebuggerItem result;
 
202
//    result.setAutoDetected(true);
 
203
//    result.setDisplayName(tr("Auto-detected for Tool Chain %1").arg(tc->displayName()));
 
204
    /*
 
205
    // Check suggestions from the SDK.
 
206
    Environment env = Environment::systemEnvironment();
 
207
    if (tc) {
 
208
        tc->addToEnvironment(env); // Find MinGW gdb in toolchain environment.
 
209
        QString path = tc->suggestedDebugger().toString();
 
210
        if (!path.isEmpty()) {
 
211
            const QFileInfo fi(path);
 
212
            if (!fi.isAbsolute())
 
213
                path = env.searchInPath(path);
 
214
            result.command = FileName::fromString(path);
 
215
            result.engineType = engineTypeFromBinary(path);
 
216
            return maybeAddDebugger(result, false);
 
217
        }
 
218
    }
 
219
    */
 
220
 
 
221
    QFileInfoList suspects;
 
222
 
 
223
    if (HostOsInfo::isMacHost()) {
 
224
        QProcess lldbInfo;
 
225
        lldbInfo.start(QLatin1String("xcrun"), QStringList() << QLatin1String("--find")
 
226
                       << QLatin1String("lldb"));
 
227
        if (!lldbInfo.waitForFinished(2000)) {
 
228
            lldbInfo.kill();
 
229
            lldbInfo.waitForFinished();
 
230
        } else {
 
231
            QByteArray lPath = lldbInfo.readAll();
 
232
            suspects.append(QFileInfo(QString::fromLocal8Bit(lPath.data(), lPath.size() -1)));
 
233
        }
 
234
    }
 
235
 
 
236
    QStringList path = Environment::systemEnvironment().path();
 
237
    foreach (const QString &base, path) {
 
238
        QDir dir(base);
 
239
        dir.setNameFilters(filters);
 
240
        suspects += dir.entryInfoList();
 
241
    }
 
242
 
 
243
    foreach (const QFileInfo &fi, suspects) {
 
244
        if (fi.exists()) {
 
245
            FileName command = FileName::fromString(fi.absoluteFilePath());
 
246
            if (findByCommand(command))
 
247
                continue;
 
248
            DebuggerItem item;
 
249
            item.createId();
 
250
            item.setCommand(command);
 
251
            item.reinitializeFromFile();
 
252
            //: %1: Debugger engine type (GDB, LLDB, CDB...), %2: Path
 
253
            item.setDisplayName(tr("System %1 at %2")
 
254
                .arg(item.engineTypeName()).arg(QDir::toNativeSeparators(fi.absoluteFilePath())));
 
255
            item.setAutoDetected(true);
 
256
            addDebugger(item);
 
257
        }
 
258
    }
 
259
}
 
260
 
 
261
void DebuggerItemManager::readLegacyDebuggers()
 
262
{
 
263
    QFileInfo systemLocation(Core::ICore::settings(QSettings::SystemScope)->fileName());
 
264
    readLegacyDebuggers(FileName::fromString(systemLocation.absolutePath() + QLatin1String(DEBUGGER_LEGACY_FILENAME)));
 
265
    QFileInfo userLocation(Core::ICore::settings()->fileName());
 
266
    readLegacyDebuggers(FileName::fromString(userLocation.absolutePath() + QLatin1String(DEBUGGER_LEGACY_FILENAME)));
 
267
}
 
268
 
 
269
void DebuggerItemManager::readLegacyDebuggers(const FileName &file)
 
270
{
 
271
    PersistentSettingsReader reader;
 
272
    if (!reader.load(file))
 
273
        return;
 
274
 
 
275
    foreach (const QVariant &v, reader.restoreValues()) {
 
276
        QVariantMap data1 = v.toMap();
 
277
        QString kitName = data1.value(QLatin1String("PE.Profile.Name")).toString();
 
278
        QVariantMap data2 = data1.value(QLatin1String("PE.Profile.Data")).toMap();
 
279
        QVariant v3 = data2.value(DebuggerKitInformation::id().toString());
 
280
        QString fn;
 
281
        if (v3.type() == QVariant::String)
 
282
            fn = v3.toString();
 
283
        else
 
284
            fn = v3.toMap().value(QLatin1String("Binary")).toString();
 
285
        if (fn.isEmpty())
 
286
            continue;
 
287
        if (fn.startsWith(QLatin1Char('{')))
 
288
            continue;
 
289
        if (fn == QLatin1String("auto"))
 
290
            continue;
 
291
        FileName command = FileName::fromUserInput(fn);
 
292
        if (findByCommand(command))
 
293
            continue;
 
294
        DebuggerItem item;
 
295
        item.createId();
 
296
        item.setCommand(command);
 
297
        item.setAutoDetected(true);
 
298
        item.reinitializeFromFile();
 
299
        item.setDisplayName(tr("Extracted from Kit %1").arg(kitName));
 
300
        addDebugger(item);
 
301
    }
 
302
}
 
303
 
 
304
const DebuggerItem *DebuggerItemManager::findByCommand(const FileName &command)
 
305
{
 
306
    foreach (const DebuggerItem &item, m_debuggers)
 
307
        if (item.command() == command)
 
308
            return &item;
 
309
 
 
310
    return 0;
 
311
}
 
312
 
 
313
const DebuggerItem *DebuggerItemManager::findById(const QVariant &id)
 
314
{
 
315
    foreach (const DebuggerItem &item, m_debuggers)
 
316
        if (item.id() == id)
 
317
            return &item;
 
318
 
 
319
    return 0;
 
320
}
 
321
 
 
322
const DebuggerItem *DebuggerItemManager::findByEngineType(DebuggerEngineType engineType)
 
323
{
 
324
    foreach (const DebuggerItem &item, m_debuggers)
 
325
        if (item.engineType() == engineType && item.isValid())
 
326
            return &item;
 
327
    return 0;
 
328
}
 
329
 
 
330
void DebuggerItemManager::restoreDebuggers()
 
331
{
 
332
    // Read debuggers from SDK
 
333
    QFileInfo systemSettingsFile(Core::ICore::settings(QSettings::SystemScope)->fileName());
 
334
    readDebuggers(FileName::fromString(systemSettingsFile.absolutePath() + QLatin1String(DEBUGGER_FILENAME)), true);
 
335
 
 
336
    // Read all debuggers from user file.
 
337
    readDebuggers(userSettingsFileName(), false);
 
338
 
 
339
    // Auto detect current.
 
340
    autoDetectCdbDebuggers();
 
341
    autoDetectGdbOrLldbDebuggers();
 
342
 
 
343
    // Add debuggers from pre-3.x profiles.xml
 
344
    readLegacyDebuggers();
 
345
}
 
346
 
 
347
void DebuggerItemManager::saveDebuggers()
 
348
{
 
349
    QTC_ASSERT(m_writer, return);
 
350
    QVariantMap data;
 
351
    data.insert(QLatin1String(DEBUGGER_FILE_VERSION_KEY), 1);
 
352
 
 
353
    int count = 0;
 
354
    foreach (const DebuggerItem &item, m_debuggers) {
 
355
        if (item.isValid() && item.engineType() != NoEngineType) {
 
356
            QVariantMap tmp = item.toMap();
 
357
            if (tmp.isEmpty())
 
358
                continue;
 
359
            data.insert(QString::fromLatin1(DEBUGGER_DATA_KEY) + QString::number(count), tmp);
 
360
            ++count;
 
361
        }
 
362
    }
 
363
    data.insert(QLatin1String(DEBUGGER_COUNT_KEY), count);
 
364
    m_writer->save(data, Core::ICore::mainWindow());
 
365
 
 
366
    // Do not save default debuggers as they are set by the SDK.
 
367
}
 
368
 
 
369
QVariant DebuggerItemManager::registerDebugger(const DebuggerItem &item)
 
370
{
 
371
    // Force addition when Id is set.
 
372
    if (item.id().isValid())
 
373
        return addDebugger(item);
 
374
 
 
375
    // Otherwise, try re-using existing item first.
 
376
    foreach (const DebuggerItem &d, m_debuggers) {
 
377
        if (d.command() == item.command()
 
378
                && d.isAutoDetected() == item.isAutoDetected()
 
379
                && d.engineType() == item.engineType()
 
380
                && d.displayName() == item.displayName()
 
381
                && d.abis() == item.abis())
 
382
            return d.id();
 
383
    }
 
384
 
 
385
    // Nothing suitable. Create a new id and add the item.
 
386
    DebuggerItem di = item;
 
387
    di.createId();
 
388
    return addDebugger(di);
 
389
}
 
390
 
 
391
void DebuggerItemManager::deregisterDebugger(const QVariant &id)
 
392
{
 
393
    if (findById(id))
 
394
        removeDebugger(id);
 
395
}
 
396
 
 
397
QVariant DebuggerItemManager::addDebugger(const DebuggerItem &item)
 
398
{
 
399
    QTC_ASSERT(item.id().isValid(), return QVariant());
 
400
    m_debuggers.append(item);
 
401
    QVariant id = item.id();
 
402
    emit m_instance->debuggerAdded(id);
 
403
    return id;
 
404
}
 
405
 
 
406
void DebuggerItemManager::removeDebugger(const QVariant &id)
 
407
{
 
408
    bool ok = false;
 
409
    for (int i = 0, n = m_debuggers.size(); i != n; ++i) {
 
410
        if (m_debuggers.at(i).id() == id) {
 
411
            emit m_instance->aboutToRemoveDebugger(id);
 
412
            m_debuggers.removeAt(i);
 
413
            emit m_instance->debuggerRemoved(id);
 
414
            ok = true;
 
415
            break;
 
416
        }
 
417
    }
 
418
 
 
419
    QTC_ASSERT(ok, return);
 
420
}
 
421
 
 
422
QString DebuggerItemManager::uniqueDisplayName(const QString &base)
 
423
{
 
424
    foreach (const DebuggerItem &item, m_debuggers)
 
425
        if (item.displayName() == base)
 
426
            return uniqueDisplayName(base + QLatin1String(" (1)"));
 
427
 
 
428
    return base;
 
429
}
 
430
 
 
431
void DebuggerItemManager::setItemData(const QVariant &id, const QString &displayName, const FileName &fileName)
 
432
{
 
433
    for (int i = 0, n = m_debuggers.size(); i != n; ++i) {
 
434
        DebuggerItem &item = m_debuggers[i];
 
435
        if (item.id() == id) {
 
436
            item.setDisplayName(displayName);
 
437
            item.setCommand(fileName);
 
438
            item.reinitializeFromFile();
 
439
            emit m_instance->debuggerUpdated(id);
 
440
            break;
 
441
        }
 
442
    }
 
443
}
 
444
 
 
445
} // namespace Debugger;