baseqtversion.cpp 59.6 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
dt's avatar
dt committed
2
**
Eike Ziller's avatar
Eike Ziller committed
3
4
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
dt's avatar
dt committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
dt's avatar
dt committed
7
**
hjk's avatar
hjk committed
8
9
10
11
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
Eike Ziller's avatar
Eike Ziller committed
12
13
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
** use the contact form at http://www.qt.io/contact-us.
dt's avatar
dt committed
15
16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18
19
20
21
22
23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
hjk's avatar
hjk committed
24
**
Eike Ziller's avatar
Eike Ziller committed
25
26
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
dt's avatar
dt committed
27
28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
dt's avatar
dt committed
30
31

#include "baseqtversion.h"
32
#include "qtconfigwidget.h"
dt's avatar
dt committed
33
#include "qmldumptool.h"
Tobias Hunger's avatar
Tobias Hunger committed
34
#include "qtkitinformation.h"
dt's avatar
dt committed
35
36

#include "qtversionmanager.h"
37
#include "profilereader.h"
38
39
#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
40
#include <proparser/qmakevfs.h>
dt's avatar
dt committed
41
#include <projectexplorer/toolchainmanager.h>
42
#include <projectexplorer/toolchain.h>
dt's avatar
dt committed
43
#include <projectexplorer/projectexplorer.h>
44
#include <projectexplorer/headerpath.h>
45
#include <qtsupport/debugginghelperbuildtask.h>
46
#include <qtsupport/qtkitinformation.h>
47
#include <qtsupport/qtsupportconstants.h>
dt's avatar
dt committed
48

49
#include <utils/algorithm.h>
50
#include <utils/hostosinfo.h>
51
#include <utils/macroexpander.h>
Tobias Hunger's avatar
Tobias Hunger committed
52
#include <utils/qtcassert.h>
53
#include <utils/runextensions.h>
dt's avatar
dt committed
54
#include <utils/synchronousprocess.h>
55
#include <utils/winutils.h>
56
#include <utils/algorithm.h>
dt's avatar
dt committed
57

58
#include <QDir>
59
#include <QUrl>
60
#include <QFileInfo>
61
#include <QFuture>
62
63
#include <QCoreApplication>
#include <QProcess>
64
#include <QRegExp>
dt's avatar
dt committed
65

66
using namespace Core;
67
68
using namespace QtSupport;
using namespace QtSupport::Internal;
hjk's avatar
hjk committed
69
using namespace ProjectExplorer;
70
using namespace Utils;
dt's avatar
dt committed
71
72
73
74
75

static const char QTVERSIONAUTODETECTED[] = "isAutodetected";
static const char QTVERSIONAUTODETECTIONSOURCE []= "autodetectionSource";
static const char QTVERSIONQMAKEPATH[] = "QMakePath";

76
77
78
static const char MKSPEC_VALUE_LIBINFIX[] = "QT_LIBINFIX";
static const char MKSPEC_VALUE_NAMESPACE[] = "QT_NAMESPACE";

79
static QSet<Id> versionedIds(const QByteArray &prefix, int major, int minor)
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
{
    QSet<Id> result;
    result.insert(Id::fromName(prefix));

    if (major < 0)
        return result;

    const QByteArray majorStr = QString::number(major).toLatin1();
    const QByteArray featureMajor = prefix + majorStr;
    const QByteArray featureDotMajor = prefix + '.' + majorStr;

    result.insert(Id::fromName(featureMajor));
    result.insert(Id::fromName(featureDotMajor));

    for (int i = 0; i <= minor; ++i) {
        const QByteArray minorStr = QString::number(i).toLatin1();
        result.insert(Id::fromName(featureMajor + '.' + minorStr));
        result.insert(Id::fromName(featureDotMajor + '.' + minorStr));
    }

    return result;
}

dt's avatar
dt committed
103
104
105
106
107
108
109
110
111
112
///////////////
// QtVersionNumber
///////////////
QtVersionNumber::QtVersionNumber(int ma, int mi, int p)
    : majorVersion(ma), minorVersion(mi), patchVersion(p)
{
}

QtVersionNumber::QtVersionNumber(const QString &versionString)
{
113
114
    if (::sscanf(versionString.toLatin1().constData(), "%d.%d.%d",
           &majorVersion, &minorVersion, &patchVersion) != 3)
dt's avatar
dt committed
115
116
117
118
119
120
121
122
        majorVersion = minorVersion = patchVersion = -1;
}

QtVersionNumber::QtVersionNumber()
{
    majorVersion = minorVersion = patchVersion = -1;
}

123
QSet<Id> QtVersionNumber::features() const
124
{
125
    return versionedIds(Constants::FEATURE_QT_PREFIX, majorVersion, minorVersion);
Tobias Hunger's avatar
Tobias Hunger committed
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
}

bool QtVersionNumber::matches(int major, int minor, int patch) const
{
    if (major < 0)
        return true;
    if (major != majorVersion)
        return false;

    if (minor < 0)
        return true;
    if (minor != minorVersion)
        return false;

    if (patch < 0)
        return true;
    return (patch == patchVersion);
143
144
}

dt's avatar
dt committed
145
146
bool QtVersionNumber::operator <(const QtVersionNumber &b) const
{
147
148
149
150
151
    if (majorVersion != b.majorVersion)
        return majorVersion < b.majorVersion;
    if (minorVersion != b.minorVersion)
        return minorVersion < b.minorVersion;
    return patchVersion < b.patchVersion;
dt's avatar
dt committed
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
}

bool QtVersionNumber::operator >(const QtVersionNumber &b) const
{
    return b < *this;
}

bool QtVersionNumber::operator ==(const QtVersionNumber &b) const
{
    return majorVersion == b.majorVersion
            && minorVersion == b.minorVersion
            && patchVersion == b.patchVersion;
}

bool QtVersionNumber::operator !=(const QtVersionNumber &b) const
{
    return !(*this == b);
}

bool QtVersionNumber::operator <=(const QtVersionNumber &b) const
{
    return !(*this > b);
}

bool QtVersionNumber::operator >=(const QtVersionNumber &b) const
{
    return b <= *this;
}

///////////////
// BaseQtVersion
///////////////
int BaseQtVersion::getUniqueId()
{
hjk's avatar
hjk committed
186
    return QtVersionManager::getUniqueId();
dt's avatar
dt committed
187
188
}

189
BaseQtVersion::BaseQtVersion(const FileName &qmakeCommand, bool isAutodetected, const QString &autodetectionSource)
dt's avatar
dt committed
190
191
192
193
194
195
196
    : m_id(getUniqueId()),
      m_isAutodetected(isAutodetected),
      m_hasQmlDump(false),
      m_mkspecUpToDate(false),
      m_mkspecReadUpToDate(false),
      m_defaultConfigIsDebug(true),
      m_defaultConfigIsDebugAndRelease(true),
197
      m_frameworkBuild(false),
dt's avatar
dt committed
198
      m_versionInfoUpToDate(false),
hjk's avatar
hjk committed
199
      m_installed(true),
dt's avatar
dt committed
200
201
202
      m_hasExamples(false),
      m_hasDemos(false),
      m_hasDocumentation(false),
203
      m_qmakeIsExecutable(true),
204
      m_hasQtAbis(false),
205
      m_autodetectionSource(autodetectionSource)
dt's avatar
dt committed
206
207
208
209
{
    ctor(qmakeCommand);
}

210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
BaseQtVersion::BaseQtVersion(const BaseQtVersion &other) :
    m_id(other.m_id),
    m_isAutodetected(other.m_isAutodetected),
    m_hasQmlDump(other.m_hasQmlDump),
    m_mkspecUpToDate(other.m_mkspecUpToDate),
    m_mkspecReadUpToDate(other.m_mkspecReadUpToDate),
    m_defaultConfigIsDebug(other.m_defaultConfigIsDebug),
    m_defaultConfigIsDebugAndRelease(other.m_defaultConfigIsDebugAndRelease),
    m_frameworkBuild(other.m_frameworkBuild),
    m_versionInfoUpToDate(other.m_versionInfoUpToDate),
    m_installed(other.m_installed),
    m_hasExamples(other.m_hasExamples),
    m_hasDemos(other.m_hasDemos),
    m_hasDocumentation(other.m_hasDocumentation),
    m_qmakeIsExecutable(other.m_qmakeIsExecutable),
    m_hasQtAbis(other.m_hasQtAbis),
    m_configValues(other.m_configValues),
    m_qtConfigValues(other.m_qtConfigValues),
    m_unexpandedDisplayName(other.m_unexpandedDisplayName),
    m_autodetectionSource(other.m_autodetectionSource),
    m_sourcePath(other.m_sourcePath),
    m_mkspec(other.m_mkspec),
    m_mkspecFullPath(other.m_mkspecFullPath),
    m_mkspecValues(other.m_mkspecValues),
    m_versionInfo(other.m_versionInfo),
    m_qmakeCommand(other.m_qmakeCommand),
    m_qtVersionString(other.m_qtVersionString),
    m_uicCommand(other.m_uicCommand),
    m_designerCommand(other.m_designerCommand),
    m_linguistCommand(other.m_linguistCommand),
    m_qmlsceneCommand(other.m_qmlsceneCommand),
    m_qmlviewerCommand(other.m_qmlviewerCommand),
242
243
244
245
    m_qtAbis(other.m_qtAbis)
{
    setupExpander();
}
246

dt's avatar
dt committed
247
248
249
250
251
252
253
BaseQtVersion::BaseQtVersion()
    :  m_id(-1), m_isAutodetected(false),
    m_hasQmlDump(false),
    m_mkspecUpToDate(false),
    m_mkspecReadUpToDate(false),
    m_defaultConfigIsDebug(true),
    m_defaultConfigIsDebugAndRelease(true),
254
    m_frameworkBuild(false),
dt's avatar
dt committed
255
    m_versionInfoUpToDate(false),
hjk's avatar
hjk committed
256
    m_installed(true),
dt's avatar
dt committed
257
258
    m_hasExamples(false),
    m_hasDemos(false),
259
    m_hasDocumentation(false),
260
261
    m_qmakeIsExecutable(true),
    m_hasQtAbis(false)
dt's avatar
dt committed
262
{
263
    ctor(FileName());
dt's avatar
dt committed
264
265
}

266
void BaseQtVersion::ctor(const FileName &qmakePath)
dt's avatar
dt committed
267
{
268
    m_qmakeCommand = qmakePath;
dt's avatar
dt committed
269
270
271
272
273
274
275
    m_designerCommand.clear();
    m_linguistCommand.clear();
    m_qmlviewerCommand.clear();
    m_uicCommand.clear();
    m_mkspecUpToDate = false;
    m_mkspecReadUpToDate = false;
    m_versionInfoUpToDate = false;
276
    m_hasQtAbis = false;
dt's avatar
dt committed
277
278
    m_qtVersionString.clear();
    m_sourcePath.clear();
279
280
281
282
283
    setupExpander();
}

void BaseQtVersion::setupExpander()
{
hjk's avatar
hjk committed
284
    m_expander.setDisplayName(
285
        QtKitInformation::tr("Qt version"));
hjk's avatar
hjk committed
286

hjk's avatar
hjk committed
287
    m_expander.registerVariable("Qt:Version",
288
289
        QtKitInformation::tr("The version string of the current Qt version."),
        [this] { return qtVersionString(); });
290

hjk's avatar
hjk committed
291
    m_expander.registerVariable("Qt:Type",
292
293
        QtKitInformation::tr("The type of the current Qt version."),
        [this] { return type(); });
294

hjk's avatar
hjk committed
295
    m_expander.registerVariable("Qt:Mkspec",
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
        QtKitInformation::tr("The mkspec of the current Qt version."),
        [this] { return mkspec().toUserOutput(); });

    m_expander.registerVariable("Qt:QT_INSTALL_PREFIX",
        QtKitInformation::tr("The installation prefix of the current Qt version."),
        [this] { return qmakeProperty(m_versionInfo, "QT_INSTALL_PREFIX"); });

    m_expander.registerVariable("Qt:QT_INSTALL_DATA",
        QtKitInformation::tr("The installation location of the current Qt version's data."),
        [this] { return qmakeProperty(m_versionInfo, "QT_INSTALL_DATA"); });

    m_expander.registerVariable("Qt:QT_INSTALL_HEADERS",
        QtKitInformation::tr("The installation location of the current Qt version's header files."),
        [this] { return qmakeProperty(m_versionInfo, "QT_INSTALL_HEADERS"); });

    m_expander.registerVariable("Qt:QT_INSTALL_LIBS",
        QtKitInformation::tr("The installation location of the current Qt version's library files."),
        [this] { return qmakeProperty(m_versionInfo, "QT_INSTALL_LIBS"); });

    m_expander.registerVariable("Qt:QT_INSTALL_DOCS",
        QtKitInformation::tr("The installation location of the current Qt version's documentation files."),
        [this] { return qmakeProperty(m_versionInfo, "QT_INSTALL_DOCS"); });

    m_expander.registerVariable("Qt:QT_INSTALL_BINS",
        QtKitInformation::tr("The installation location of the current Qt version's executable files."),
        [this] { return qmakeProperty(m_versionInfo, "QT_INSTALL_BINS"); });

    m_expander.registerVariable("Qt:QT_INSTALL_PLUGINS",
        QtKitInformation::tr("The installation location of the current Qt version's plugins."),
        [this] { return qmakeProperty(m_versionInfo, "QT_INSTALL_PLUGINS"); });

    m_expander.registerVariable("Qt:QT_INSTALL_IMPORTS",
        QtKitInformation::tr("The installation location of the current Qt version's imports."),
        [this] { return qmakeProperty(m_versionInfo, "QT_INSTALL_IMPORTS"); });

    m_expander.registerVariable("Qt:QT_INSTALL_TRANSLATIONS",
        QtKitInformation::tr("The installation location of the current Qt version's translation files."),
        [this] { return qmakeProperty(m_versionInfo, "QT_INSTALL_TRANSLATIONS"); });

    m_expander.registerVariable("Qt:QT_INSTALL_CONFIGURATION",
        QtKitInformation::tr("The installation location of the current Qt version's translation files."),
        [this] { return qmakeProperty(m_versionInfo, "QT_INSTALL_CONFIGURATION"); });

    m_expander.registerVariable("Qt:QT_INSTALL_EXAMPLES",
        QtKitInformation::tr("The installation location of the current Qt version's examples."),
        [this] { return qmakeProperty(m_versionInfo, "QT_INSTALL_EXAMPLES"); });

    m_expander.registerVariable("Qt:QT_INSTALL_DEMOS",
        QtKitInformation::tr("The installation location of the current Qt version's demos."),
        [this] { return qmakeProperty(m_versionInfo, "QT_INSTALL_DEMOS"); });

    m_expander.registerVariable("Qt:QMAKE_MKSPECS",
        QtKitInformation::tr("The current Qt version's default mkspecs."),
        [this] { return qmakeProperty(m_versionInfo, "QMAKE_MKSPECS"); });

    m_expander.registerVariable("Qt:QMAKE_VERSION",
        QtKitInformation::tr("The current Qt's qmake version."),
        [this] { return qmakeProperty(m_versionInfo, "QMAKE_VERSION"); });
354
355

//    FIXME: Re-enable once we can detect expansion loops.
hjk's avatar
hjk committed
356
//    m_expander.registerVariable("Qt:Name",
357
358
//        QtKitInformation::tr("The display name of the current Qt version."),
//        [this] { return displayName(); });
dt's avatar
dt committed
359
360
361
362
}

BaseQtVersion::~BaseQtVersion()
{
363
364
}

365
QString BaseQtVersion::defaultUnexpandedDisplayName(const FileName &qmakePath, bool fromPath)
366
367
368
369
370
371
372
{
    QString location;
    if (qmakePath.isEmpty()) {
        location = QCoreApplication::translate("QtVersion", "<unknown>");
    } else {
        // Deduce a description from '/foo/qt-folder/[qtbase]/bin/qmake' -> '/foo/qt-folder'.
        // '/usr' indicates System Qt 4.X on Linux.
373
        QDir dir = qmakePath.toFileInfo().absoluteDir();
374
375
376
377
378
379
        do {
            const QString dirName = dir.dirName();
            if (dirName == QLatin1String("usr")) { // System-installed Qt.
                location = QCoreApplication::translate("QtVersion", "System");
                break;
            }
380
381
            location = dirName;
            // Also skip default checkouts named 'qt'. Parent dir might have descriptive name.
382
            if (dirName.compare(QLatin1String("bin"), Qt::CaseInsensitive)
383
384
                && dirName.compare(QLatin1String("qtbase"), Qt::CaseInsensitive)
                && dirName.compare(QLatin1String("qt"), Qt::CaseInsensitive)) {
385
386
                break;
            }
Orgad Shaneh's avatar
Orgad Shaneh committed
387
        } while (!dir.isRoot() && dir.cdUp());
388
    }
dt's avatar
dt committed
389

390
    return fromPath ?
391
392
        QCoreApplication::translate("QtVersion", "Qt %{Qt:Version} in PATH (%2)").arg(location) :
        QCoreApplication::translate("QtVersion", "Qt %{Qt:Version} (%2)").arg(location);
dt's avatar
dt committed
393
394
}

395
QSet<Id> BaseQtVersion::availableFeatures() const
396
{
397
    QSet<Id> features = qtVersion().features(); // Qt Version features
398

399
400
401
    features.insert(Constants::FEATURE_QWIDGETS);
    features.insert(Constants::FEATURE_QT_WEBKIT);
    features.insert(Constants::FEATURE_QT_CONSOLE);
jkobus's avatar
jkobus committed
402

403
404
    if (qtVersion() < QtVersionNumber(4, 7, 0))
        return features;
jkobus's avatar
jkobus committed
405

406
    features.unite(versionedIds(Constants::FEATURE_QT_QUICK_PREFIX, 1, 0));
jkobus's avatar
jkobus committed
407

Tobias Hunger's avatar
Tobias Hunger committed
408
    if (qtVersion().matches(4, 7, 0))
409
        return features;
jkobus's avatar
jkobus committed
410

411
    features.unite(versionedIds(Constants::FEATURE_QT_QUICK_PREFIX, 1, 1));
jkobus's avatar
jkobus committed
412

Tobias Hunger's avatar
Tobias Hunger committed
413
    if (qtVersion().matches(4))
414
        return features;
jkobus's avatar
jkobus committed
415

416
    features.unite(versionedIds(Constants::FEATURE_QT_QUICK_PREFIX, 2, 0));
jkobus's avatar
jkobus committed
417

Tobias Hunger's avatar
Tobias Hunger committed
418
    if (qtVersion().matches(5, 0))
419
        return features;
jkobus's avatar
jkobus committed
420

421
422
    features.unite(versionedIds(Constants::FEATURE_QT_QUICK_PREFIX, 2, 1));
    features.unite(versionedIds(Constants::FEATURE_QT_QUICK_CONTROLS_PREFIX, 1, 0));
jkobus's avatar
jkobus committed
423

Tobias Hunger's avatar
Tobias Hunger committed
424
    if (qtVersion().matches(5, 1))
425
        return features;
426

427
428
    features.unite(versionedIds(Constants::FEATURE_QT_QUICK_PREFIX, 2, 2));
    features.unite(versionedIds(Constants::FEATURE_QT_QUICK_CONTROLS_PREFIX, 1, 1));
429

Tobias Hunger's avatar
Tobias Hunger committed
430
    if (qtVersion().matches(5, 2))
431
        return features;
432

433
434
    features.unite(versionedIds(Constants::FEATURE_QT_QUICK_PREFIX, 2, 3));
    features.unite(versionedIds(Constants::FEATURE_QT_QUICK_CONTROLS_PREFIX, 1, 2));
435

Tobias Hunger's avatar
Tobias Hunger committed
436
    if (qtVersion().matches(5, 3))
437
438
        return features;

439
    features.insert(Constants::FEATURE_QT_QUICK_UI_FILES);
Tobias Hunger's avatar
Tobias Hunger committed
440

441
442
    features.unite(versionedIds(Constants::FEATURE_QT_QUICK_PREFIX, 2, 4));
    features.unite(versionedIds(Constants::FEATURE_QT_QUICK_CONTROLS_PREFIX, 1, 3));
443

Tobias Hunger's avatar
Tobias Hunger committed
444
    if (qtVersion().matches(5, 4))
445
446
        return features;

447
448
    features.insert(Constants::FEATURE_QT_3D);
    features.insert(Constants::FEATURE_QT_CANVAS3D);
Tobias Hunger's avatar
Tobias Hunger committed
449

450
451
    features.unite(versionedIds(Constants::FEATURE_QT_QUICK_PREFIX, 2, 5));
    features.unite(versionedIds(Constants::FEATURE_QT_QUICK_CONTROLS_PREFIX, 1, 4));
Tobias Hunger's avatar
Tobias Hunger committed
452
453
454

    if (qtVersion().matches(5, 5))
        return features;
455

456
457
458
459
460
461
    features |= FeatureSet::versionedFeatures(Constants::FEATURE_QT_QUICK_PREFIX, 2, 6);
    features |= FeatureSet::versionedFeatures(Constants::FEATURE_QT_QUICK_CONTROLS_PREFIX, 1, 5);

    if (qtVersion().matches(5, 6))
        return features;

462
    return features;
463
464
}

hjk's avatar
hjk committed
465
QList<Task> BaseQtVersion::validateKit(const Kit *k)
Tobias Hunger's avatar
Tobias Hunger committed
466
{
hjk's avatar
hjk committed
467
    QList<Task> result;
Tobias Hunger's avatar
Tobias Hunger committed
468

Tobias Hunger's avatar
Tobias Hunger committed
469
    BaseQtVersion *version = QtKitInformation::qtVersion(k);
Tobias Hunger's avatar
Tobias Hunger committed
470
471
    Q_ASSERT(version == this);

hjk's avatar
hjk committed
472
    const QList<Abi> qtAbis = version->qtAbis();
473
    if (qtAbis.isEmpty()) // No need to test if Qt does not know anyway...
474
475
        return result;

476
477
478
479
480
481
482
483
484
    const Id dt = DeviceTypeKitInformation::deviceTypeId(k);
    const QSet<Id> tdt = targetDeviceTypes();
    if (!tdt.isEmpty() && !tdt.contains(dt)) {
        result << Task(Task::Warning,
                       QCoreApplication::translate("BaseQtVersion",
                                                   "Device type is not supported by Qt version."),
                       FileName(), -1, ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
    }

hjk's avatar
hjk committed
485
    ToolChain *tc = ToolChainKitInformation::toolChain(k);
486
    if (tc) {
hjk's avatar
hjk committed
487
        Abi targetAbi = tc->targetAbi();
488
489
        bool fuzzyMatch = false;
        bool fullMatch = false;
490
491

        QString qtAbiString;
hjk's avatar
hjk committed
492
        foreach (const Abi &qtAbi, qtAbis) {
493
494
495
            if (!qtAbiString.isEmpty())
                qtAbiString.append(QLatin1Char(' '));
            qtAbiString.append(qtAbi.toString());
496
497
498
499
500
501
502
503
504
505
506

            if (!fullMatch)
                fullMatch = (targetAbi == qtAbi);
            if (!fuzzyMatch)
                fuzzyMatch = targetAbi.isCompatibleWith(qtAbi);
        }

        QString message;
        if (!fullMatch) {
            if (!fuzzyMatch)
                message = QCoreApplication::translate("BaseQtVersion",
507
                                                      "The compiler \"%1\" (%2) cannot produce code for the Qt version \"%3\" (%4).");
508
509
            else
                message = QCoreApplication::translate("BaseQtVersion",
510
                                                      "The compiler \"%1\" (%2) may not produce code compatible with the Qt version \"%3\" (%4).");
511
512
            message = message.arg(tc->displayName(), targetAbi.toString(),
                                  version->displayName(), qtAbiString);
hjk's avatar
hjk committed
513
514
            result << Task(fuzzyMatch ? Task::Warning : Task::Error, message, FileName(), -1,
                           ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
515
        }
516
    }
Tobias Hunger's avatar
Tobias Hunger committed
517
518
519
    return result;
}

520
521
FileName BaseQtVersion::headerPath() const
{
hjk's avatar
hjk committed
522
    return FileName::fromUserInput(qmakeProperty("QT_INSTALL_HEADERS"));
523
524
}

525
526
FileName BaseQtVersion::docsPath() const
{
hjk's avatar
hjk committed
527
    return FileName::fromUserInput(qmakeProperty("QT_INSTALL_DOCS"));
528
529
}

530
531
FileName BaseQtVersion::libraryPath() const
{
hjk's avatar
hjk committed
532
    return FileName::fromUserInput(qmakeProperty("QT_INSTALL_LIBS"));
533
534
}

535
536
FileName BaseQtVersion::pluginPath() const
{
hjk's avatar
hjk committed
537
    return FileName::fromUserInput(qmakeProperty("QT_INSTALL_PLUGINS"));
538
539
}

540
541
FileName BaseQtVersion::binPath() const
{
hjk's avatar
hjk committed
542
    return FileName::fromUserInput(qmakeProperty("QT_HOST_BINS"));
543
544
}

hjk's avatar
hjk committed
545
FileName BaseQtVersion::mkspecsPath() const
546
{
hjk's avatar
hjk committed
547
    FileName result = FileName::fromUserInput(qmakeProperty("QT_HOST_DATA"));
548
    if (result.isEmpty())
hjk's avatar
hjk committed
549
        result = FileName::fromUserInput(qmakeProperty("QMAKE_MKSPECS"));
550
551
552
553
554
    else
        result.appendPath(QLatin1String("mkspecs"));
    return result;
}

555
QString BaseQtVersion::qtNamespace() const
556
{
557
558
    ensureMkSpecParsed();
    return m_mkspecValues.value(QLatin1String(MKSPEC_VALUE_NAMESPACE));
559
560
}

561
QString BaseQtVersion::qtLibInfix() const
562
{
563
564
    ensureMkSpecParsed();
    return m_mkspecValues.value(QLatin1String(MKSPEC_VALUE_LIBINFIX));
565
566
}

567
568
bool BaseQtVersion::isFrameworkBuild() const
{
569
    ensureMkSpecParsed();
570
571
572
    return m_frameworkBuild;
}

573
574
575
576
577
578
579
580
581
582
bool BaseQtVersion::hasDebugBuild() const
{
    return m_defaultConfigIsDebug || m_defaultConfigIsDebugAndRelease;
}

bool BaseQtVersion::hasReleaseBuild() const
{
    return !m_defaultConfigIsDebug || m_defaultConfigIsDebugAndRelease;
}

dt's avatar
dt committed
583
584
585
586
587
588
589
void BaseQtVersion::setId(int id)
{
    m_id = id;
}

void BaseQtVersion::fromMap(const QVariantMap &map)
{
590
    m_id = map.value(QLatin1String(Constants::QTVERSIONID)).toInt();
dt's avatar
dt committed
591
    if (m_id == -1) // this happens on adding from installer, see updateFromInstaller => get a new unique id
hjk's avatar
hjk committed
592
        m_id = QtVersionManager::getUniqueId();
593
    m_unexpandedDisplayName = map.value(QLatin1String(Constants::QTVERSIONNAME)).toString();
dt's avatar
dt committed
594
595
596
    m_isAutodetected = map.value(QLatin1String(QTVERSIONAUTODETECTED)).toBool();
    if (m_isAutodetected)
        m_autodetectionSource = map.value(QLatin1String(QTVERSIONAUTODETECTIONSOURCE)).toString();
597
    QString string = map.value(QLatin1String(QTVERSIONQMAKEPATH)).toString();
598
    if (string.startsWith(QLatin1Char('~')))
599
        string.remove(0, 1).prepend(QDir::homePath());
600
601
602
603
604
605

    QFileInfo fi(string);
    if (BuildableHelperLibrary::isQtChooser(fi)) {
        // we don't want to treat qtchooser as a normal qmake
        // see e.g. QTCREATORBUG-9841, also this lead to users changing what
        // qtchooser forwards too behind our backs, which will inadvertly lead to bugs
606
        string = BuildableHelperLibrary::qtChooserToQmakePath(fi.symLinkTarget());
607
608
    }

Eike Ziller's avatar
Eike Ziller committed
609
    ctor(FileName::fromString(string));
dt's avatar
dt committed
610
611
612
613
614
}

QVariantMap BaseQtVersion::toMap() const
{
    QVariantMap result;
615
    result.insert(QLatin1String(Constants::QTVERSIONID), uniqueId());
616
    result.insert(QLatin1String(Constants::QTVERSIONNAME), unexpandedDisplayName());
dt's avatar
dt committed
617
618
619
    result.insert(QLatin1String(QTVERSIONAUTODETECTED), isAutodetected());
    if (isAutodetected())
        result.insert(QLatin1String(QTVERSIONAUTODETECTIONSOURCE), autodetectionSource());
620
    result.insert(QLatin1String(QTVERSIONQMAKEPATH), qmakeCommand().toString());
dt's avatar
dt committed
621
622
623
624
625
    return result;
}

bool BaseQtVersion::isValid() const
{
dt's avatar
dt committed
626
    if (uniqueId() == -1 || displayName().isEmpty())
dt's avatar
dt committed
627
628
629
630
631
        return false;
    updateVersionInfo();
    updateMkspec();

    return  !qmakeCommand().isEmpty()
hjk's avatar
hjk committed
632
            && m_installed
633
            && !qmakeProperty("QT_HOST_BINS").isNull()
634
            && !m_mkspecFullPath.isEmpty()
dt's avatar
dt committed
635
636
637
638
639
640
641
642
643
644
645
            && m_qmakeIsExecutable;
}

QString BaseQtVersion::invalidReason() const
{
    if (displayName().isEmpty())
        return QCoreApplication::translate("QtVersion", "Qt version has no name");
    if (qmakeCommand().isEmpty())
        return QCoreApplication::translate("QtVersion", "No qmake path set");
    if (!m_qmakeIsExecutable)
        return QCoreApplication::translate("QtVersion", "qmake does not exist or is not executable");
hjk's avatar
hjk committed
646
    if (!m_installed)
dt's avatar
dt committed
647
        return QCoreApplication::translate("QtVersion", "Qt version is not properly installed, please run make install");
648
    if (qmakeProperty("QT_HOST_BINS").isNull())
dt's avatar
dt committed
649
650
651
652
653
654
655
        return QCoreApplication::translate("QtVersion",
                                           "Could not determine the path to the binaries of the Qt installation, maybe the qmake path is wrong?");
    if (m_mkspecUpToDate && m_mkspecFullPath.isEmpty())
        return QCoreApplication::translate("QtVersion", "The default mkspec symlink is broken.");
    return QString();
}

656
QStringList BaseQtVersion::warningReason() const
657
{
658
    QStringList ret;
659
    if (qtAbis().isEmpty())
660
        ret << QCoreApplication::translate("QtVersion", "ABI detection failed: Make sure to use a matching compiler when building.");
661
662
663
664
    if (m_versionInfo.value(QLatin1String("QT_INSTALL_PREFIX/get"))
        != m_versionInfo.value(QLatin1String("QT_INSTALL_PREFIX"))) {
        ret << QCoreApplication::translate("QtVersion", "Non-installed -prefix build - for internal development only.");
    }
665
    return ret;
666
667
}

668
FileName BaseQtVersion::qmakeCommand() const
dt's avatar
dt committed
669
{
Tobias Hunger's avatar
Tobias Hunger committed
670
    return m_qmakeCommand;
dt's avatar
dt committed
671
672
}

hjk's avatar
hjk committed
673
QList<Abi> BaseQtVersion::qtAbis() const
674
{
675
    if (!m_hasQtAbis) {
676
        m_qtAbis = detectQtAbis();
677
678
        m_hasQtAbis = true;
    }
679
680
681
    return m_qtAbis;
}

dt's avatar
dt committed
682
683
bool BaseQtVersion::equals(BaseQtVersion *other)
{
684
685
    if (m_qmakeCommand != other->m_qmakeCommand)
        return false;
dt's avatar
dt committed
686
687
688
689
690
691
    if (type() != other->type())
        return false;
    if (uniqueId() != other->uniqueId())
        return false;
    if (displayName() != other->displayName())
        return false;
692
693
    if (isValid() != other->isValid())
        return false;
dt's avatar
dt committed
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712

    return true;
}

int BaseQtVersion::uniqueId() const
{
    return m_id;
}

bool BaseQtVersion::isAutodetected() const
{
    return m_isAutodetected;
}

QString BaseQtVersion::autodetectionSource() const
{
    return m_autodetectionSource;
}

dt's avatar
dt committed
713
714
715
716
717
void BaseQtVersion::setAutoDetectionSource(const QString &autodetectionSource)
{
    m_autodetectionSource = autodetectionSource;
}

dt's avatar
dt committed
718
719
QString BaseQtVersion::displayName() const
{
720
    return m_expander.expand(m_unexpandedDisplayName);
dt's avatar
dt committed
721
722
}

723
QString BaseQtVersion::unexpandedDisplayName() const
dt's avatar
dt committed
724
{
725
726
727
728
729
730
    return m_unexpandedDisplayName;
}

void BaseQtVersion::setUnexpandedDisplayName(const QString &name)
{
    m_unexpandedDisplayName = name;
dt's avatar
dt committed
731
732
733
734
735
736
737
738
739
740
}

QString BaseQtVersion::toHtml(bool verbose) const
{
    QString rc;
    QTextStream str(&rc);
    str << "<html><body><table>";
    str << "<tr><td><b>" << QCoreApplication::translate("BaseQtVersion", "Name:")
        << "</b></td><td>" << displayName() << "</td></tr>";
    if (!isValid()) {
741
742
743
        str << "<tr><td colspan=2><b>"
            << QCoreApplication::translate("BaseQtVersion", "Invalid Qt version")
            << "</b></td></tr>";
dt's avatar
dt committed
744
    } else {
745
746
        str << "<tr><td><b>" << QCoreApplication::translate("BaseQtVersion", "ABI:")
            << "</b></td>";
hjk's avatar
hjk committed
747
        const QList<Abi> abis = qtAbis();
748
        if (abis.isEmpty()) {
hjk's avatar
hjk committed
749
            str << "<td>" << Abi().toString() << "</td></tr>";
750
751
752
753
754
755
        } else {
            for (int i = 0; i < abis.size(); ++i) {
                if (i)
                    str << "<tr><td></td>";
                str << "<td>" << abis.at(i).toString() << "</td></tr>";
            }
dt's avatar
dt committed
756
757
        }
        str << "<tr><td><b>" << QCoreApplication::translate("BaseQtVersion", "Source:")
758
            << "</b></td><td>" << sourcePath().toUserOutput() << "</td></tr>";
dt's avatar
dt committed
759
        str << "<tr><td><b>" << QCoreApplication::translate("BaseQtVersion", "mkspec:")
760
            << "</b></td><td>" << mkspec().toUserOutput() << "</td></tr>";
dt's avatar
dt committed
761
        str << "<tr><td><b>" << QCoreApplication::translate("BaseQtVersion", "qmake:")
762
            << "</b></td><td>" << m_qmakeCommand.toUserOutput() << "</td></tr>";
dt's avatar
dt committed
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
        ensureMkSpecParsed();
        if (!mkspecPath().isEmpty()) {
            if (m_defaultConfigIsDebug || m_defaultConfigIsDebugAndRelease) {
                str << "<tr><td><b>" << QCoreApplication::translate("BaseQtVersion", "Default:") << "</b></td><td>"
                    << (m_defaultConfigIsDebug ? "debug" : "release");
                if (m_defaultConfigIsDebugAndRelease)
                    str << " debug_and_release";
                str << "</td></tr>";
            } // default config.
        }
        str << "<tr><td><b>" << QCoreApplication::translate("BaseQtVersion", "Version:")
            << "</b></td><td>" << qtVersionString() << "</td></tr>";
        if (verbose) {
            const QHash<QString,QString> vInfo = versionInfo();
            if (!vInfo.isEmpty()) {
778
779
780
781
                QStringList keys = vInfo.keys();
                keys.sort();
                foreach (QString variableName, keys) {
                    const QString &value = vInfo.value(variableName);
782
                    if (variableName != QLatin1String("QMAKE_MKSPECS")
783
784
785
786
787
788
789
790
                        && !variableName.endsWith(QLatin1String("/raw"))) {
                        bool isPath = false;
                        if (variableName.contains(QLatin1String("_HOST_"))
                            || variableName.contains(QLatin1String("_INSTALL_"))) {
                            if (!variableName.endsWith(QLatin1String("/get")))
                                continue;
                            variableName.chop(4);
                            isPath = true;
791
792
                        } else if (variableName == QLatin1String("QT_SYSROOT")) {
                            isPath = true;
793
                        }
794
                        str << "<tr><td><pre>" << variableName <<  "</pre></td><td>";
795
796
                        if (value.isEmpty())
                            isPath = false;
797
798
799
800
                        if (isPath) {
                            str << "<a href=\"" << QUrl::fromLocalFile(value).toString()
                                << "\">" << QDir::toNativeSeparators(value) << "</a>";
                        } else {
801
                            str << value;
802
803
804
805
                        }
                        str << "</td></tr>";
                    }
                }
dt's avatar
dt committed
806
807
808
809
810
811
812
813
814
815
816
817
            }
        }
    }
    str << "</table></body></html>";
    return rc;
}

void BaseQtVersion::updateSourcePath() const
{
    if (!m_sourcePath.isEmpty())
        return;
    updateVersionInfo();
818
    m_sourcePath = sourcePath(m_versionInfo);
dt's avatar
dt committed
819
820
}

821
FileName BaseQtVersion::sourcePath() const
dt's avatar
dt committed
822
823
824
825
826
827
828
829
830
831
{
    updateSourcePath();
    return m_sourcePath;
}

QString BaseQtVersion::designerCommand() const
{
    if (!isValid())
        return QString();
    if (m_designerCommand.isNull())
832
        m_designerCommand = findQtBinary(Designer);
dt's avatar
dt committed
833
834
835
836
837
838
839
840
    return m_designerCommand;
}

QString BaseQtVersion::linguistCommand() const
{
    if (!isValid())
        return QString();
    if (m_linguistCommand.isNull())
841
        m_linguistCommand = findQtBinary(Linguist);
dt's avatar
dt committed
842
843
844
    return m_linguistCommand;
}

845
846
847
848
849
850
851
852
853
854
QString BaseQtVersion::qmlsceneCommand() const
{
    if (!isValid())
        return QString();

    if (m_qmlsceneCommand.isNull())
        m_qmlsceneCommand = findQtBinary(QmlScene);
    return m_qmlsceneCommand;
}

dt's avatar
dt committed
855
856
857
858
859
QString BaseQtVersion::qmlviewerCommand() const
{
    if (!isValid())
        return QString();

860
861
    if (m_qmlviewerCommand.isNull())
        m_qmlviewerCommand = findQtBinary(QmlViewer);
dt's avatar
dt committed
862
863
864
    return m_qmlviewerCommand;
}

Daniel Teske's avatar
Compile  
Daniel Teske committed
865
QString BaseQtVersion::findQtBinary(Binaries binary) const
dt's avatar
dt committed
866
{
867
868
    QString baseDir;
    if (qtVersion() < QtVersionNumber(5, 0, 0)) {
869
        baseDir = qmakeProperty("QT_HOST_BINS");
870
871
872
    } else {
        ensureMkSpecParsed();
        switch (binary) {
873
        case QmlScene:
Aurindam Jana's avatar
Aurindam Jana committed
874
            baseDir = m_mkspecValues.value(QLatin1String("QT.qml.bins"));
875
            break;
876
877
878
        case QmlViewer:
            baseDir = m_mkspecValues.value(QLatin1String("QT.declarative.bins"));
            break;
879
880
        case Designer:
        case Linguist:
881
            baseDir = m_mkspecValues.value(QLatin1String("QT.designer.bins"));
882
883
            break;
        case Uic:
884
            baseDir = qmakeProperty("QT_HOST_BINS");
885
886
887
888
889
890
891
892
            break;
        default:
            // Can't happen
            Q_ASSERT(false);
        }
    }

    if (baseDir.isEmpty())
dt's avatar
dt committed
893
        return QString();
894
    if (!baseDir.endsWith(QLatin1Char('/')))
895
        baseDir += QLatin1Char('/');
dt's avatar
dt committed
896

897
898
    QStringList possibleCommands;
    switch (binary) {
899
900
    case QmlScene:
        possibleCommands << HostOsInfo::withExecutableSuffix(QLatin1String("qmlscene"));
901
        break;
902
    case QmlViewer: {
903
        if (HostOsInfo::isMacHost())
904
905
            possibleCommands << QLatin1String("QMLViewer.app/Contents/MacOS/QMLViewer");
        else
906
            possibleCommands << HostOsInfo::withExecutableSuffix(QLatin1String("qmlviewer"));
907
    }
908
909
        break;
    case Designer:
910
        if (HostOsInfo::isMacHost())
911
912
            possibleCommands << QLatin1String("Designer.app/Contents/MacOS/Designer");
        else
913
            possibleCommands << HostOsInfo::withExecutableSuffix(QLatin1String("designer"));
914
915
        break;
    case Linguist:
916
        if (HostOsInfo::isMacHost())
917
            possibleCommands << QLatin1String("Linguist.app/Contents/MacOS/Linguist");
918
            possibleCommands << HostOsInfo::withExecutableSuffix(QLatin1String("linguist"));
919
920
        break;
    case Uic:
921
922
923
924
925
926
        if (HostOsInfo::isWindowsHost()) {
            possibleCommands << QLatin1String("uic.exe");
        } else {
            possibleCommands << QLatin1String("uic-qt4") << QLatin1String("uic4")
                             << QLatin1String("uic");
        }
927
928
929
930
        break;
    default:
        Q_ASSERT(false);
    }
dt's avatar
dt committed
931
    foreach (const QString &possibleCommand, possibleCommands) {
932
        const QString fullPath = baseDir + possibleCommand;
dt's avatar
dt committed
933
934
935
936
937
938
939
940
941
942
943
944
        if (QFileInfo(fullPath).isFile())
            return QDir::cleanPath(fullPath);
    }
    return QString();
}

QString BaseQtVersion::uicCommand() const
{
    if (!isValid())
        return QString();
    if (!m_uicCommand.isNull())
        return m_uicCommand;
945
    m_uicCommand = findQtBinary(Uic);
dt's avatar
dt committed
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
    return m_uicCommand;
}

void BaseQtVersion::updateMkspec() const
{
    if (uniqueId() == -1 || m_mkspecUpToDate)
        return;

    m_mkspecUpToDate = true;
    m_mkspecFullPath = mkspecFromVersionInfo(versionInfo());

    m_mkspec = m_mkspecFullPath;
    if (m_mkspecFullPath.isEmpty())
        return;

961
    FileName baseMkspecDir = mkspecDirectoryFromVersionInfo(versionInfo());
dt's avatar
dt committed
962

963
964
    if (m_mkspec.isChildOf(baseMkspecDir)) {
        m_mkspec = m_mkspec.relativeChildPath(baseMkspecDir);
dt's avatar
dt committed
965
966
//        qDebug() << "Setting mkspec to"<<mkspec;
    } else {
967
        FileName sourceMkSpecPath = sourcePath().appendPath(QLatin1String("mkspecs"));
968
969
        if (m_mkspec.isChildOf(sourceMkSpecPath)) {
            m_mkspec = m_mkspec.relativeChildPath(sourceMkSpecPath);
dt's avatar
dt committed
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
        } else {
            // Do nothing
        }
    }
}

void BaseQtVersion::ensureMkSpecParsed() const
{
    if (m_mkspecReadUpToDate)
        return;
    m_mkspecReadUpToDate = true;

    if (mkspecPath().isEmpty())
        return;

985
    QMakeVfs vfs;
986
    ProFileGlobals option;
987
    option.setProperties(versionInfo());
988
    option.environment = qmakeRunEnvironment().toProcessEnvironment();
dt's avatar
dt committed <