qmakestep.cpp 28.5 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
Eike Ziller's avatar
Eike Ziller committed
3 4
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con 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.
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
con's avatar
con committed
27 28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
hjk's avatar
hjk committed
30

con's avatar
con committed
31
#include "qmakestep.h"
32
#include "ui_qmakestep.h"
hjk's avatar
hjk committed
33

Tobias Hunger's avatar
Tobias Hunger committed
34
#include "qmakeparser.h"
35 36 37
#include "qmakebuildconfiguration.h"
#include "qmakeproject.h"
#include "qmakeprojectmanagerconstants.h"
Tobias Hunger's avatar
Tobias Hunger committed
38
#include "qmakekitinformation.h"
39
#include "qmakenodes.h"
con's avatar
con committed
40

41
#include <projectexplorer/buildmanager.h>
Tobias Hunger's avatar
Tobias Hunger committed
42
#include <projectexplorer/buildsteplist.h>
43
#include <projectexplorer/projectexplorer.h>
Tobias Hunger's avatar
Tobias Hunger committed
44
#include <projectexplorer/target.h>
45
#include <projectexplorer/toolchain.h>
Tobias Hunger's avatar
Tobias Hunger committed
46

con's avatar
con committed
47
#include <coreplugin/icore.h>
48
#include <coreplugin/icontext.h>
49
#include <qtsupport/debugginghelperbuildtask.h>
Tobias Hunger's avatar
Tobias Hunger committed
50
#include <qtsupport/qtkitinformation.h>
51
#include <qtsupport/qtversionmanager.h>
52
#include <qtsupport/qtsupportconstants.h>
53
#include <utils/algorithm.h>
54
#include <utils/hostosinfo.h>
55
#include <utils/qtcprocess.h>
con's avatar
con committed
56

57 58
#include <QDir>
#include <QMessageBox>
con's avatar
con committed
59

60 61
using namespace QmakeProjectManager;
using namespace QmakeProjectManager::Internal;
62
using namespace QtSupport;
con's avatar
con committed
63
using namespace ProjectExplorer;
64
using namespace Utils;
con's avatar
con committed
65

66
namespace {
Orgad Shaneh's avatar
Orgad Shaneh committed
67
const char QMAKE_BS_ID[] = "QtProjectManager.QMakeBuildStep";
68

Orgad Shaneh's avatar
Orgad Shaneh committed
69 70
const char QMAKE_ARGUMENTS_KEY[] = "QtProjectManager.QMakeBuildStep.QMakeArguments";
const char QMAKE_FORCED_KEY[] = "QtProjectManager.QMakeBuildStep.QMakeForced";
71
const char QMAKE_USE_QTQUICKCOMPILER[] = "QtProjectManager.QMakeBuildStep.UseQtQuickCompiler";
72
const char QMAKE_SEPARATEDEBUGINFO_KEY[] = "QtProjectManager.QMakeBuildStep.SeparateDebugInfo";
Orgad Shaneh's avatar
Orgad Shaneh committed
73 74
const char QMAKE_QMLDEBUGLIBAUTO_KEY[] = "QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto";
const char QMAKE_QMLDEBUGLIB_KEY[] = "QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary";
75 76
}

Tobias Hunger's avatar
Tobias Hunger committed
77
QMakeStep::QMakeStep(BuildStepList *bsl) :
78
    AbstractProcessStep(bsl, Core::Id(QMAKE_BS_ID)),
79
    m_forced(false),
80
    m_needToRunQMake(false),
81
    m_linkQmlDebuggingLibrary(DebugLink),
82 83
    m_useQtQuickCompiler(false),
    m_separateDebugInfo(false)
con's avatar
con committed
84
{
85
    ctor();
con's avatar
con committed
86 87
}

88
QMakeStep::QMakeStep(BuildStepList *bsl, Core::Id id) :
Tobias Hunger's avatar
Tobias Hunger committed
89
    AbstractProcessStep(bsl, id),
90
    m_forced(false),
91
    m_linkQmlDebuggingLibrary(DebugLink),
92 93
    m_useQtQuickCompiler(false),
    m_separateDebugInfo(false)
94 95 96 97
{
    ctor();
}

Tobias Hunger's avatar
Tobias Hunger committed
98 99
QMakeStep::QMakeStep(BuildStepList *bsl, QMakeStep *bs) :
    AbstractProcessStep(bsl, bs),
100
    m_forced(bs->m_forced),
101
    m_userArgs(bs->m_userArgs),
102
    m_linkQmlDebuggingLibrary(bs->m_linkQmlDebuggingLibrary),
103 104
    m_useQtQuickCompiler(bs->m_useQtQuickCompiler),
    m_separateDebugInfo(bs->m_separateDebugInfo)
105
{
106 107 108 109 110
    ctor();
}

void QMakeStep::ctor()
{
111 112
    //: QMakeStep default display name
    setDefaultDisplayName(tr("qmake"));
113 114
}

con's avatar
con committed
115 116 117 118
QMakeStep::~QMakeStep()
{
}

119
QmakeBuildConfiguration *QMakeStep::qmakeBuildConfiguration() const
dt's avatar
dt committed
120
{
121
    return static_cast<QmakeBuildConfiguration *>(buildConfiguration());
dt's avatar
dt committed
122 123
}

dt's avatar
dt committed
124 125 126 127 128 129 130
///
/// Returns all arguments
/// That is: possbile subpath
/// spec
/// config arguemnts
/// moreArguments
/// user arguments
131
QString QMakeStep::allArguments(bool shorted)
con's avatar
con committed
132
{
133
    QmakeBuildConfiguration *bc = qmakeBuildConfiguration();
con's avatar
con committed
134
    QStringList arguments;
135
    if (bc->subNodeBuild())
136
        arguments << bc->subNodeBuild()->path().toUserOutput();
137
    else if (shorted)
138
        arguments << project()->projectFilePath().fileName();
139
    else
140
        arguments << project()->projectFilePath().toUserOutput();
con's avatar
con committed
141

142
    arguments << QLatin1String("-r");
143
    bool userProvidedMkspec = false;
144
    for (QtcProcess::ConstArgIterator ait(m_userArgs); ait.next(); ) {
145 146 147 148 149
        if (ait.value() == QLatin1String("-spec")) {
            if (ait.next()) {
                userProvidedMkspec = true;
                break;
            }
dt's avatar
dt committed
150
        }
151
    }
152
    FileName specArg = mkspec();
153
    if (!userProvidedMkspec && !specArg.isEmpty())
154
        arguments << QLatin1String("-spec") << specArg.toUserOutput();
155

dt's avatar
dt committed
156
    // Find out what flags we pass on to qmake
157
    arguments << bc->configCommandLineArguments();
dt's avatar
dt committed
158

159
    arguments << deducedArguments().toArguments();
160

161
    QString args = QtcProcess::joinArgs(arguments);
162
    // User arguments
163
    QtcProcess::addArgs(&args, m_userArgs);
164
    return args;
dt's avatar
dt committed
165 166
}

167
QMakeStepConfig QMakeStep::deducedArguments()
dt's avatar
dt committed
168
{
169 170
    ProjectExplorer::Kit *kit = target()->kit();
    QMakeStepConfig config;
Tobias Hunger's avatar
Tobias Hunger committed
171
    ProjectExplorer::ToolChain *tc
172
            = ProjectExplorer::ToolChainKitInformation::toolChain(kit);
173 174 175
    ProjectExplorer::Abi targetAbi;
    if (tc)
        targetAbi = tc->targetAbi();
176

Tobias Hunger's avatar
Tobias Hunger committed
177
    QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target()->kit());
178 179 180

    config.archConfig = QMakeStepConfig::targetArchFor(targetAbi, version);
    config.osType = QMakeStepConfig::osTypeFor(targetAbi, version);
181
    if (linkQmlDebuggingLibrary() && version) {
182
        config.linkQmlDebuggingQQ1 = true;
183
        if (version->qtVersion().majorVersion >= 5)
184
            config.linkQmlDebuggingQQ2 = true;
185 186
    }

187
    if (useQtQuickCompiler() && version)
188
        config.useQtQuickCompiler = true;
189

190 191
    if (separateDebugInfo())
        config.separateDebugInfo = true;
192

193
    return config;
194 195
}

196

197
bool QMakeStep::init()
con's avatar
con committed
198
{
199
    QmakeBuildConfiguration *qt4bc = qmakeBuildConfiguration();
Tobias Hunger's avatar
Tobias Hunger committed
200
    const QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(target()->kit());
dt's avatar
dt committed
201 202 203

    if (!qtVersion)
        return false;
con's avatar
con committed
204

205
    QString args = allArguments();
206
    QString workingDirectory;
207

208 209 210
    if (qt4bc->subNodeBuild())
        workingDirectory = qt4bc->subNodeBuild()->buildDir();
    else
211
        workingDirectory = qt4bc->buildDirectory().toString();
con's avatar
con committed
212

213
    FileName program = qtVersion->qmakeCommand();
con's avatar
con committed
214

215 216 217
    QString makefile = workingDirectory;

    if (qt4bc->subNodeBuild()) {
Tobias Hunger's avatar
Tobias Hunger committed
218
        if (!qt4bc->subNodeBuild()->makefile().isEmpty())
219
            makefile.append(qt4bc->subNodeBuild()->makefile());
Tobias Hunger's avatar
Tobias Hunger committed
220
        else
221
            makefile.append(QLatin1String("/Makefile"));
222
    } else if (!qt4bc->makefile().isEmpty()) {
223
        makefile.append(QLatin1Char('/'));
224 225
        makefile.append(qt4bc->makefile());
    } else {
226
        makefile.append(QLatin1String("/Makefile"));
227 228
    }

229
    // Check whether we need to run qmake
230
    bool makefileOutDated = (qt4bc->compareToImportFrom(makefile) != QmakeBuildConfiguration::MakefileMatches);
231
    if (m_forced || makefileOutDated)
232
        m_needToRunQMake = true;
233
    m_forced = false;
con's avatar
con committed
234

235 236 237
    ProcessParameters *pp = processParameters();
    pp->setMacroExpander(qt4bc->macroExpander());
    pp->setWorkingDirectory(workingDirectory);
238
    pp->setCommand(program.toString());
239 240
    pp->setArguments(args);
    pp->setEnvironment(qt4bc->environment());
241
    pp->resolveAll();
242

Tobias Hunger's avatar
Tobias Hunger committed
243
    setOutputParser(new QMakeParser);
dt's avatar
dt committed
244

245
    QmakeProFileNode *node = static_cast<QmakeProject *>(qt4bc->target()->project())->rootQmakeProjectNode();
dt's avatar
dt committed
246 247
    if (qt4bc->subNodeBuild())
        node = qt4bc->subNodeBuild();
248
    QString proFile = node->path().toString();
dt's avatar
dt committed
249

250
    QList<ProjectExplorer::Task> tasks = qtVersion->reportIssues(proFile, workingDirectory);
251
    Utils::sort(tasks);
252 253 254 255 256 257 258 259 260

    if (!tasks.isEmpty()) {
        bool canContinue = true;
        foreach (const ProjectExplorer::Task &t, tasks) {
            addTask(t);
            if (t.type == Task::Error)
                canContinue = false;
        }
        if (!canContinue) {
261
            emitFaultyConfigurationMessage();
262 263 264
            return false;
        }
    }
265

dt's avatar
dt committed
266
    m_scriptTemplate = node->projectType() == ScriptTemplate;
dt's avatar
dt committed
267

Tobias Hunger's avatar
Tobias Hunger committed
268
    return AbstractProcessStep::init();
con's avatar
con committed
269 270 271 272
}

void QMakeStep::run(QFutureInterface<bool> &fi)
{
dt's avatar
dt committed
273
    if (m_scriptTemplate) {
con's avatar
con committed
274 275 276
        fi.reportResult(true);
        return;
    }
277

278
    if (!m_needToRunQMake) {
279
        emit addOutput(tr("Configuration unchanged, skipping qmake step."), BuildStep::MessageOutput);
con's avatar
con committed
280
        fi.reportResult(true);
281
        emit finished();
con's avatar
con committed
282 283
        return;
    }
284

285
    m_needToRunQMake = false;
Tobias Hunger's avatar
Tobias Hunger committed
286
    AbstractProcessStep::run(fi);
con's avatar
con committed
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
}

void QMakeStep::setForced(bool b)
{
    m_forced = b;
}

bool QMakeStep::forced()
{
    return m_forced;
}

ProjectExplorer::BuildStepConfigWidget *QMakeStep::createConfigWidget()
{
    return new QMakeStepConfigWidget(this);
}

bool QMakeStep::immutable() const
{
dt's avatar
dt committed
306
    return false;
con's avatar
con committed
307 308 309 310
}

void QMakeStep::processStartupFailed()
{
311
    m_needToRunQMake = true;
con's avatar
con committed
312 313 314
    AbstractProcessStep::processStartupFailed();
}

315
bool QMakeStep::processSucceeded(int exitCode, QProcess::ExitStatus status)
con's avatar
con committed
316
{
317
    bool result = AbstractProcessStep::processSucceeded(exitCode, status);
con's avatar
con committed
318
    if (!result)
319
        m_needToRunQMake = true;
320
    QmakeProject *project = static_cast<QmakeProject *>(qmakeBuildConfiguration()->target()->project());
321
    project->emitBuildDirectoryInitialized();
con's avatar
con committed
322 323 324
    return result;
}

325
void QMakeStep::setUserArguments(const QString &arguments)
326
{
327 328
    if (m_userArgs == arguments)
        return;
dt's avatar
dt committed
329
    m_userArgs = arguments;
330

331
    emit userArgumentsChanged();
332

333 334
    qmakeBuildConfiguration()->emitQMakeBuildConfigurationChanged();
    qmakeBuildConfiguration()->emitProFileEvaluateNeeded();
335 336
}

337 338
bool QMakeStep::linkQmlDebuggingLibrary() const
{
339 340 341 342
    if (m_linkQmlDebuggingLibrary == DoLink)
        return true;
    if (m_linkQmlDebuggingLibrary == DoNotLink)
        return false;
343 344 345 346

    const Core::Context languages = project()->projectLanguages();
    if (!languages.contains(ProjectExplorer::Constants::LANG_QMLJS))
        return false;
347
    return (qmakeBuildConfiguration()->buildType() & BuildConfiguration::Debug);
348 349 350 351
}

void QMakeStep::setLinkQmlDebuggingLibrary(bool enable)
{
352 353
    if ((enable && (m_linkQmlDebuggingLibrary == DoLink))
            || (!enable && (m_linkQmlDebuggingLibrary == DoNotLink)))
354
        return;
355
    m_linkQmlDebuggingLibrary = enable ? DoLink : DoNotLink;
356 357 358

    emit linkQmlDebuggingLibraryChanged();

359 360
    qmakeBuildConfiguration()->emitQMakeBuildConfigurationChanged();
    qmakeBuildConfiguration()->emitProFileEvaluateNeeded();
361 362
}

363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
bool QMakeStep::useQtQuickCompiler() const
{
    return m_useQtQuickCompiler;
}

void QMakeStep::setUseQtQuickCompiler(bool enable)
{
    if (enable == m_useQtQuickCompiler)
        return;

    m_useQtQuickCompiler = enable;

    emit useQtQuickCompilerChanged();

    qmakeBuildConfiguration()->emitQMakeBuildConfigurationChanged();
    qmakeBuildConfiguration()->emitProFileEvaluateNeeded();
}

381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
bool QMakeStep::separateDebugInfo() const
{
    return m_separateDebugInfo;
}

void QMakeStep::setSeparateDebugInfo(bool enable)
{
    if (enable == m_separateDebugInfo)
        return;
    m_separateDebugInfo = enable;

    emit separateDebugInfoChanged();

    qmakeBuildConfiguration()->emitQMakeBuildConfigurationChanged();
    qmakeBuildConfiguration()->emitProFileEvaluateNeeded();
}

398 399 400
QStringList QMakeStep::parserArguments()
{
    QStringList result;
401
    for (QtcProcess::ConstArgIterator ait(allArguments()); ait.next(); )
402 403
        if (ait.isSimple())
            result << ait.value();
404
    return result;
405 406
}

407
QString QMakeStep::userArguments()
408
{
dt's avatar
dt committed
409
    return m_userArgs;
410 411
}

412
FileName QMakeStep::mkspec()
413 414
{
    QString additionalArguments = m_userArgs;
415
    for (QtcProcess::ArgIterator ait(&additionalArguments); ait.next(); ) {
416 417
        if (ait.value() == QLatin1String("-spec")) {
            if (ait.next())
418
                return FileName::fromUserInput(ait.value());
419 420 421
        }
    }

422
    return QmakeProjectManager::QmakeKitInformation::effectiveMkspec(target()->kit());
423 424
}

425
QVariantMap QMakeStep::toMap() const
426
{
427 428
    QVariantMap map(AbstractProcessStep::toMap());
    map.insert(QLatin1String(QMAKE_ARGUMENTS_KEY), m_userArgs);
429 430
    map.insert(QLatin1String(QMAKE_QMLDEBUGLIBAUTO_KEY), m_linkQmlDebuggingLibrary == DebugLink);
    map.insert(QLatin1String(QMAKE_QMLDEBUGLIB_KEY), m_linkQmlDebuggingLibrary == DoLink);
431
    map.insert(QLatin1String(QMAKE_FORCED_KEY), m_forced);
432
    map.insert(QLatin1String(QMAKE_USE_QTQUICKCOMPILER), m_useQtQuickCompiler);
433
    map.insert(QLatin1String(QMAKE_SEPARATEDEBUGINFO_KEY), m_separateDebugInfo);
434
    return map;
435 436
}

437
bool QMakeStep::fromMap(const QVariantMap &map)
438
{
439
    m_userArgs = map.value(QLatin1String(QMAKE_ARGUMENTS_KEY)).toString();
440
    m_forced = map.value(QLatin1String(QMAKE_FORCED_KEY), false).toBool();
441
    m_useQtQuickCompiler = map.value(QLatin1String(QMAKE_USE_QTQUICKCOMPILER), false).toBool();
442 443 444
    if (map.value(QLatin1String(QMAKE_QMLDEBUGLIBAUTO_KEY), false).toBool()) {
        m_linkQmlDebuggingLibrary = DebugLink;
    } else {
445
        if (map.value(QLatin1String(QMAKE_QMLDEBUGLIB_KEY), false).toBool())
446
            m_linkQmlDebuggingLibrary = DoLink;
447
        else
448 449
            m_linkQmlDebuggingLibrary = DoNotLink;
    }
450
    m_separateDebugInfo = map.value(QLatin1String(QMAKE_SEPARATEDEBUGINFO_KEY), false).toBool();
451

452
    return BuildStep::fromMap(map);
453 454
}

455 456 457 458
////
// QMakeStepConfigWidget
////

con's avatar
con committed
459
QMakeStepConfigWidget::QMakeStepConfigWidget(QMakeStep *step)
460
    : BuildStepConfigWidget(), m_ui(new Internal::Ui::QMakeStep), m_step(step),
461
      m_ignoreChange(false)
con's avatar
con committed
462
{
463
    m_ui->setupUi(this);
dt_'s avatar
dt_ committed
464 465 466

    m_ui->qmakeAdditonalArgumentsLineEdit->setText(m_step->userArguments());
    m_ui->qmlDebuggingLibraryCheckBox->setChecked(m_step->linkQmlDebuggingLibrary());
467
    m_ui->qtQuickCompilerCheckBox->setChecked(m_step->useQtQuickCompiler());
468
    m_ui->separateDebugInfoCheckBox->setChecked(m_step->separateDebugInfo());
dt_'s avatar
dt_ committed
469 470 471 472 473 474

    qmakeBuildConfigChanged();

    updateSummaryLabel();
    updateEffectiveQMakeCall();
    updateQmlDebuggingOption();
475
    updateQtQuickCompilerOption();
dt_'s avatar
dt_ committed
476

Robert Loehning's avatar
Robert Loehning committed
477
    connect(m_ui->qmakeAdditonalArgumentsLineEdit, SIGNAL(textEdited(QString)),
478
            this, SLOT(qmakeArgumentsLineEdited()));
479
    connect(m_ui->buildConfigurationComboBox, SIGNAL(currentIndexChanged(int)),
480
            this, SLOT(buildConfigurationSelected()));
481 482 483 484
    connect(m_ui->qmlDebuggingLibraryCheckBox, &QCheckBox::toggled,
            this, &QMakeStepConfigWidget::linkQmlDebuggingLibraryChecked);
    connect(m_ui->qmlDebuggingLibraryCheckBox, &QCheckBox::clicked,
            this, &QMakeStepConfigWidget::askForRebuild);
485 486
    connect(m_ui->qtQuickCompilerCheckBox, &QAbstractButton::toggled,
            this, &QMakeStepConfigWidget::useQtQuickCompilerChecked);
487 488
    connect(m_ui->qtQuickCompilerCheckBox, &QCheckBox::clicked,
            this, &QMakeStepConfigWidget::askForRebuild);
489 490 491 492
    connect(m_ui->separateDebugInfoCheckBox, &QAbstractButton::toggled,
            this, &QMakeStepConfigWidget::separateDebugInfoChecked);
    connect(m_ui->separateDebugInfoCheckBox, &QCheckBox::clicked,
            this, &QMakeStepConfigWidget::askForRebuild);
493 494
    connect(step, SIGNAL(userArgumentsChanged()),
            this, SLOT(userArgumentsChanged()));
495 496
    connect(step, SIGNAL(linkQmlDebuggingLibraryChanged()),
            this, SLOT(linkQmlDebuggingLibraryChanged()));
497 498
    connect(step->project(), &Project::projectLanguagesUpdated,
            this, &QMakeStepConfigWidget::linkQmlDebuggingLibraryChanged);
499 500
    connect(step, &QMakeStep::useQtQuickCompilerChanged,
            this, &QMakeStepConfigWidget::useQtQuickCompilerChanged);
501 502
    connect(step, &QMakeStep::separateDebugInfoChanged,
            this, &QMakeStepConfigWidget::separateDebugInfoChanged);
503
    connect(step->qmakeBuildConfiguration(), SIGNAL(qmakeBuildConfigurationChanged()),
504
            this, SLOT(qmakeBuildConfigChanged()));
Tobias Hunger's avatar
Tobias Hunger committed
505
    connect(step->target(), SIGNAL(kitChanged()), this, SLOT(qtVersionChanged()));
506 507
    connect(QtSupport::QtVersionManager::instance(), SIGNAL(dumpUpdatedFor(Utils::FileName)),
            this, SLOT(qtVersionChanged()));
508 509
}

510 511 512 513 514
QMakeStepConfigWidget::~QMakeStepConfigWidget()
{
    delete m_ui;
}

dt's avatar
dt committed
515 516 517 518 519
QString QMakeStepConfigWidget::summaryText() const
{
    return m_summaryText;
}

520 521 522 523 524
QString QMakeStepConfigWidget::additionalSummaryText() const
{
    return m_additionalSummaryText;
}

525 526 527 528 529
QString QMakeStepConfigWidget::displayName() const
{
    return m_step->displayName();
}

530
void QMakeStepConfigWidget::qtVersionChanged()
531
{
532
    updateSummaryLabel();
dt's avatar
dt committed
533
    updateEffectiveQMakeCall();
534
    updateQmlDebuggingOption();
535
    updateQtQuickCompilerOption();
536 537
}

538
void QMakeStepConfigWidget::qmakeBuildConfigChanged()
dt's avatar
dt committed
539
{
540
    QmakeBuildConfiguration *bc = m_step->qmakeBuildConfiguration();
541
    bool debug = bc->qmakeBuildConfiguration() & QtSupport::BaseQtVersion::DebugBuild;
542
    m_ignoreChange = true;
543
    m_ui->buildConfigurationComboBox->setCurrentIndex(debug? 0 : 1);
544 545 546 547
    m_ignoreChange = false;
    updateSummaryLabel();
    updateEffectiveQMakeCall();
}
dt's avatar
dt committed
548

549 550 551 552
void QMakeStepConfigWidget::userArgumentsChanged()
{
    if (m_ignoreChange)
        return;
553
    m_ui->qmakeAdditonalArgumentsLineEdit->setText(m_step->userArguments());
554 555
    updateSummaryLabel();
    updateEffectiveQMakeCall();
dt's avatar
dt committed
556 557
}

558 559 560 561
void QMakeStepConfigWidget::linkQmlDebuggingLibraryChanged()
{
    if (m_ignoreChange)
        return;
562
    m_ui->qmlDebuggingLibraryCheckBox->setChecked(m_step->linkQmlDebuggingLibrary());
563 564 565

    updateSummaryLabel();
    updateEffectiveQMakeCall();
566
    updateQmlDebuggingOption();
567 568
}

569 570 571 572 573 574 575 576
void QMakeStepConfigWidget::useQtQuickCompilerChanged()
{
    if (m_ignoreChange)
        return;

    updateSummaryLabel();
    updateEffectiveQMakeCall();
    updateQtQuickCompilerOption();
577
    updateQmlDebuggingOption();
578 579
}

580 581 582 583 584 585 586 587 588
void QMakeStepConfigWidget::separateDebugInfoChanged()
{
    if (m_ignoreChange)
        return;

    updateSummaryLabel();
    updateEffectiveQMakeCall();
}

589
void QMakeStepConfigWidget::qmakeArgumentsLineEdited()
con's avatar
con committed
590
{
591
    m_ignoreChange = true;
592
    m_step->setUserArguments(m_ui->qmakeAdditonalArgumentsLineEdit->text());
593
    m_ignoreChange = false;
594

595
    updateSummaryLabel();
596
    updateEffectiveQMakeCall();
con's avatar
con committed
597 598
}

599
void QMakeStepConfigWidget::buildConfigurationSelected()
con's avatar
con committed
600
{
601 602
    if (m_ignoreChange)
        return;
603
    QmakeBuildConfiguration *bc = m_step->qmakeBuildConfiguration();
604
    QtSupport::BaseQtVersion::QmakeBuildConfigs buildConfiguration = bc->qmakeBuildConfiguration();
605
    if (m_ui->buildConfigurationComboBox->currentIndex() == 0) { // debug
dt_'s avatar
dt_ committed
606 607 608
        buildConfiguration = buildConfiguration | QtSupport::BaseQtVersion::DebugBuild;
    } else {
        buildConfiguration = buildConfiguration & ~QtSupport::BaseQtVersion::DebugBuild;
con's avatar
con committed
609
    }
610 611 612
    m_ignoreChange = true;
    bc->setQMakeBuildConfiguration(buildConfiguration);
    m_ignoreChange = false;
con's avatar
con committed
613

614 615
    updateSummaryLabel();
    updateEffectiveQMakeCall();
con's avatar
con committed
616 617
}

618 619 620 621 622 623 624 625 626 627 628
void QMakeStepConfigWidget::linkQmlDebuggingLibraryChecked(bool checked)
{
    if (m_ignoreChange)
        return;

    m_ignoreChange = true;
    m_step->setLinkQmlDebuggingLibrary(checked);
    m_ignoreChange = false;

    updateSummaryLabel();
    updateEffectiveQMakeCall();
629
    updateQmlDebuggingOption();
630
}
631

632 633
void QMakeStepConfigWidget::askForRebuild()
{
hjk's avatar
hjk committed
634
    QMessageBox *question = new QMessageBox(Core::ICore::mainWindow());
635 636 637 638 639 640
    question->setWindowTitle(tr("QML Debugging"));
    question->setText(tr("The option will only take effect if the project is recompiled. Do you want to recompile now?"));
    question->setStandardButtons(QMessageBox::Yes | QMessageBox::No);
    question->setModal(true);
    connect(question, SIGNAL(finished(int)), this, SLOT(recompileMessageBoxFinished(int)));
    question->show();
641 642
}

643 644 645 646 647 648 649 650 651 652 653
void QMakeStepConfigWidget::useQtQuickCompilerChecked(bool checked)
{
    if (m_ignoreChange)
        return;

    m_ignoreChange = true;
    m_step->setUseQtQuickCompiler(checked);
    m_ignoreChange = false;

    updateSummaryLabel();
    updateEffectiveQMakeCall();
654
    updateQmlDebuggingOption();
655 656 657
    updateQtQuickCompilerOption();
}

658 659 660 661 662 663 664 665 666 667 668 669 670
void QMakeStepConfigWidget::separateDebugInfoChecked(bool checked)
{
    if (m_ignoreChange)
        return;

    m_ignoreChange = true;
    m_step->setSeparateDebugInfo(checked);
    m_ignoreChange = false;

    updateSummaryLabel();
    updateEffectiveQMakeCall();
}

671
void QMakeStepConfigWidget::updateSummaryLabel()
672
{
Tobias Hunger's avatar
Tobias Hunger committed
673
    QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(m_step->target()->kit());
674
    if (!qtVersion) {
675
        setSummaryText(tr("<b>qmake:</b> No Qt version set. Cannot run qmake."));
676
        return;
677 678
    }
    // We don't want the full path to the .pro file
679
    QString args = m_step->allArguments(true);
680
    // And we only use the .pro filename not the full path
681
    QString program = qtVersion->qmakeCommand().fileName();
682
    setSummaryText(tr("<b>qmake:</b> %1 %2").arg(program, args));
683 684
}

685
void QMakeStepConfigWidget::updateQmlDebuggingOption()
686
{
687
    QString warningText;
688
    bool supported = QtSupport::BaseQtVersion::isQmlDebuggingSupported(m_step->target()->kit(),
689
                                                                       &warningText);
690

691
    m_ui->qmlDebuggingLibraryCheckBox->setEnabled(supported);
692
    m_ui->debuggingLibraryLabel->setText(tr("Enable QML debugging and profiling:"));
693

694
    if (supported && m_step->linkQmlDebuggingLibrary())
695
        warningText = tr("Might make your application vulnerable. Only use in a safe environment.");
696

697 698
    m_ui->qmlDebuggingWarningText->setText(warningText);
    m_ui->qmlDebuggingWarningIcon->setVisible(!warningText.isEmpty());
699 700

    updateQtQuickCompilerOption(); // show or clear compiler warning text
701 702
}

703 704 705 706 707 708 709
void QMakeStepConfigWidget::updateQtQuickCompilerOption()
{
    QString warningText;
    bool supported = QtSupport::BaseQtVersion::isQtQuickCompilerSupported(m_step->target()->kit(),
                                                                          &warningText);
    m_ui->qtQuickCompilerCheckBox->setEnabled(supported);
    m_ui->qtQuickCompilerLabel->setText(tr("Enable Qt Quick Compiler:"));
710 711 712 713

    if (supported && m_step->useQtQuickCompiler() && m_step->linkQmlDebuggingLibrary())
        warningText = tr("Disables QML debugging. QML profiling will still work.");

714 715 716 717
    m_ui->qtQuickCompilerWarningText->setText(warningText);
    m_ui->qtQuickCompilerWarningIcon->setVisible(!warningText.isEmpty());
}

718 719
void QMakeStepConfigWidget::updateEffectiveQMakeCall()
{
Tobias Hunger's avatar
Tobias Hunger committed
720
    QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(m_step->target()->kit());
721
    QString program = tr("<No Qt version>");
dt's avatar
dt committed
722
    if (qtVersion)
723
        program = qtVersion->qmakeCommand().fileName();
724
    m_ui->qmakeArgumentsEdit->setPlainText(program + QLatin1Char(' ') + m_step->allArguments());
con's avatar
con committed
725 726
}

727 728 729
void QMakeStepConfigWidget::recompileMessageBoxFinished(int button)
{
    if (button == QMessageBox::Yes) {
730
        QmakeBuildConfiguration *bc = m_step->qmakeBuildConfiguration();
731 732 733 734
        if (!bc)
            return;

        QList<ProjectExplorer::BuildStepList *> stepLists;
hjk's avatar
hjk committed
735 736
        const Core::Id clean = ProjectExplorer::Constants::BUILDSTEPS_CLEAN;
        const Core::Id build = ProjectExplorer::Constants::BUILDSTEPS_BUILD;
737
        stepLists << bc->stepList(clean) << bc->stepList(build);
hjk's avatar
hjk committed
738
        BuildManager::buildLists(stepLists, QStringList() << ProjectExplorerPlugin::displayNameForStepId(clean)
739
                       << ProjectExplorerPlugin::displayNameForStepId(build));
740 741 742
    }
}

743 744 745 746 747 748 749 750
void QMakeStepConfigWidget::setSummaryText(const QString &text)
{
    if (text == m_summaryText)
        return;
    m_summaryText = text;
    emit updateSummary();
}

dt's avatar
dt committed
751 752 753 754
////
// QMakeStepFactory
////

755 756
QMakeStepFactory::QMakeStepFactory(QObject *parent) :
    ProjectExplorer::IBuildStepFactory(parent)
dt's avatar
dt committed
757 758 759 760 761 762 763
{
}

QMakeStepFactory::~QMakeStepFactory()
{
}

764
bool QMakeStepFactory::canCreate(BuildStepList *parent, Core::Id id) const
dt's avatar
dt committed
765
{
766
    if (parent->id() != ProjectExplorer::Constants::BUILDSTEPS_BUILD)
767
        return false;
768
    if (!qobject_cast<QmakeBuildConfiguration *>(parent->parent()))
769
        return false;
770
    return id == QMAKE_BS_ID;
dt's avatar
dt committed
771 772
}

773
ProjectExplorer::BuildStep *QMakeStepFactory::create(BuildStepList *parent, Core::Id id)
dt's avatar
dt committed
774
{
Tobias Hunger's avatar
Tobias Hunger committed
775
    if (!canCreate(parent, id))
776
        return 0;
Tobias Hunger's avatar
Tobias Hunger committed
777
    return new QMakeStep(parent);
778 779
}

Tobias Hunger's avatar
Tobias Hunger committed