qmakeevaluator.cpp 64.7 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8
9
10
11
12
13
14
** 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
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23
**
hjk's avatar
hjk committed
24
25
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
29
30

#include "qmakeevaluator.h"
31
#include "qmakeevaluator_p.h"
32
33
34
35
36

#include "qmakeglobals.h"
#include "qmakeparser.h"
#include "ioutils.h"

37
38
39
40
41
42
43
44
45
46
47
48
#include <qbytearray.h>
#include <qdatetime.h>
#include <qdebug.h>
#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qlist.h>
#include <qregexp.h>
#include <qset.h>
#include <qstack.h>
#include <qstring.h>
#include <qstringlist.h>
49
#ifdef PROEVALUATOR_THREAD_SAFE
50
# include <qthreadpool.h>
51
52
53
54
55
56
#endif

#ifdef Q_OS_UNIX
#include <unistd.h>
#include <sys/utsname.h>
#else
Yuchen Deng's avatar
Yuchen Deng committed
57
#include <windows.h>
58
59
60
61
#endif
#include <stdio.h>
#include <stdlib.h>

62
using namespace QMakeInternal;
63
64
65
66
67

QT_BEGIN_NAMESPACE

#define fL1S(s) QString::fromLatin1(s)

68

69
70
71
72
73
74
75
QMakeBaseKey::QMakeBaseKey(const QString &_root, bool _hostBuild)
    : root(_root), hostBuild(_hostBuild)
{
}

uint qHash(const QMakeBaseKey &key)
{
Orgad Shaneh's avatar
Orgad Shaneh committed
76
    return qHash(key.root) ^ (uint)key.hostBuild;
77
78
79
80
81
82
83
}

bool operator==(const QMakeBaseKey &one, const QMakeBaseKey &two)
{
    return one.root == two.root && one.hostBuild == two.hostBuild;
}

84
85
86
87
88
89
90
91
92
93
94
95
96
QMakeBaseEnv::QMakeBaseEnv()
    : evaluator(0)
{
#ifdef PROEVALUATOR_THREAD_SAFE
    inProgress = false;
#endif
}

QMakeBaseEnv::~QMakeBaseEnv()
{
    delete evaluator;
}

97
namespace QMakeInternal {
98
99
100
101
102
103
104
105
106
107
108
QMakeStatics statics;
}

void QMakeEvaluator::initStatics()
{
    if (!statics.field_sep.isNull())
        return;

    statics.field_sep = QLatin1String(" ");
    statics.strtrue = QLatin1String("true");
    statics.strfalse = QLatin1String("false");
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
109
110
    statics.strCONFIG = ProKey("CONFIG");
    statics.strARGS = ProKey("ARGS");
111
112
113
114
    statics.strDot = QLatin1String(".");
    statics.strDotDot = QLatin1String("..");
    statics.strever = QLatin1String("ever");
    statics.strforever = QLatin1String("forever");
115
    statics.strhost_build = QLatin1String("host_build");
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
116
    statics.strTEMPLATE = ProKey("TEMPLATE");
117
#ifdef PROEVALUATOR_FULL
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
118
    statics.strREQUIRES = ProKey("REQUIRES");
119
#endif
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145

    statics.fakeValue = ProStringList(ProString("_FAKE_")); // It has to have a unique begin() value

    initFunctionStatics();

    static const struct {
        const char * const oldname, * const newname;
    } mapInits[] = {
        { "INTERFACES", "FORMS" },
        { "QMAKE_POST_BUILD", "QMAKE_POST_LINK" },
        { "TARGETDEPS", "POST_TARGETDEPS" },
        { "LIBPATH", "QMAKE_LIBDIR" },
        { "QMAKE_EXT_MOC", "QMAKE_EXT_CPP_MOC" },
        { "QMAKE_MOD_MOC", "QMAKE_H_MOD_MOC" },
        { "QMAKE_LFLAGS_SHAPP", "QMAKE_LFLAGS_APP" },
        { "PRECOMPH", "PRECOMPILED_HEADER" },
        { "PRECOMPCPP", "PRECOMPILED_SOURCE" },
        { "INCPATH", "INCLUDEPATH" },
        { "QMAKE_EXTRA_WIN_COMPILERS", "QMAKE_EXTRA_COMPILERS" },
        { "QMAKE_EXTRA_UNIX_COMPILERS", "QMAKE_EXTRA_COMPILERS" },
        { "QMAKE_EXTRA_WIN_TARGETS", "QMAKE_EXTRA_TARGETS" },
        { "QMAKE_EXTRA_UNIX_TARGETS", "QMAKE_EXTRA_TARGETS" },
        { "QMAKE_EXTRA_UNIX_INCLUDES", "QMAKE_EXTRA_INCLUDES" },
        { "QMAKE_EXTRA_UNIX_VARIABLES", "QMAKE_EXTRA_VARIABLES" },
        { "QMAKE_RPATH", "QMAKE_LFLAGS_RPATH" },
        { "QMAKE_FRAMEWORKDIR", "QMAKE_FRAMEWORKPATH" },
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
146
147
        { "QMAKE_FRAMEWORKDIR_FLAGS", "QMAKE_FRAMEWORKPATH_FLAGS" },
        { "IN_PWD", "PWD" }
148
149
    };
    for (unsigned i = 0; i < sizeof(mapInits)/sizeof(mapInits[0]); ++i)
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
150
        statics.varMap.insert(ProKey(mapInits[i].oldname), ProKey(mapInits[i].newname));
151
152
}

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
153
const ProKey &QMakeEvaluator::map(const ProKey &var)
154
{
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
155
    QHash<ProKey, ProKey>::ConstIterator it = statics.varMap.constFind(var);
156
157
    if (it == statics.varMap.constEnd())
        return var;
Robert Loehning's avatar
Robert Loehning committed
158
    deprecationWarning(fL1S("Variable %1 is deprecated; use %2 instead.")
159
160
                       .arg(var.toQString(), it.value().toQString()));
    return it.value();
161
162
163
164
}


QMakeEvaluator::QMakeEvaluator(QMakeGlobals *option,
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
165
                               QMakeParser *parser, QMakeHandler *handler)
166
167
168
169
170
  :
#ifdef PROEVALUATOR_DEBUG
    m_debugLevel(option->debugLevel),
#endif
    m_option(option), m_parser(parser), m_handler(handler)
171
172
173
174
175
{
    // So that single-threaded apps don't have to call initialize() for now.
    initStatics();

    // Configuration, more or less
176
    m_caller = 0;
177
#ifdef PROEVALUATOR_CUMULATIVE
178
    m_cumulative = false;
179
#endif
180
    m_hostBuild = false;
181
182

    // Evaluator state
183
#ifdef PROEVALUATOR_CUMULATIVE
184
    m_skipLevel = 0;
185
#endif
186
    m_listCount = 0;
187
    m_valuemapStack.push(ProValueMap());
188
    m_valuemapInited = false;
189
190
191
192
193
194
}

QMakeEvaluator::~QMakeEvaluator()
{
}

195
196
197
198
199
void QMakeEvaluator::initFrom(const QMakeEvaluator &other)
{
    Q_ASSERT_X(&other, "QMakeEvaluator::visitProFile", "Project not prepared");
    m_functionDefs = other.m_functionDefs;
    m_valuemapStack = other.m_valuemapStack;
200
    m_valuemapInited = true;
201
202
    m_qmakespec = other.m_qmakespec;
    m_qmakespecName = other.m_qmakespecName;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
203
    m_mkspecPaths = other.m_mkspecPaths;
204
    m_featureRoots = other.m_featureRoots;
205
    m_dirSep = other.m_dirSep;
206
207
}

208
209
210
211
212
213
214
215
216
217
218
219
//////// Evaluator tools /////////

uint QMakeEvaluator::getBlockLen(const ushort *&tokPtr)
{
    uint len = *tokPtr++;
    len |= (uint)*tokPtr++ << 16;
    return len;
}

ProString QMakeEvaluator::getStr(const ushort *&tokPtr)
{
    uint len = *tokPtr++;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
220
    ProString ret(m_current.pro->items(), tokPtr - m_current.pro->tokPtr(), len);
221
222
223
224
225
    ret.setSource(m_current.pro);
    tokPtr += len;
    return ret;
}

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
226
ProKey QMakeEvaluator::getHashStr(const ushort *&tokPtr)
227
228
229
{
    uint hash = getBlockLen(tokPtr);
    uint len = *tokPtr++;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
230
    ProKey ret(m_current.pro->items(), tokPtr - m_current.pro->tokPtr(), len, hash);
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
    tokPtr += len;
    return ret;
}

void QMakeEvaluator::skipStr(const ushort *&tokPtr)
{
    uint len = *tokPtr++;
    tokPtr += len;
}

void QMakeEvaluator::skipHashStr(const ushort *&tokPtr)
{
    tokPtr += 2;
    uint len = *tokPtr++;
    tokPtr += len;
}

// FIXME: this should not build new strings for direct sections.
// Note that the E_SPRINTF and E_LIST implementations rely on the deep copy.
ProStringList QMakeEvaluator::split_value_list(const QString &vals, const ProFile *source)
{
    QString build;
    ProStringList ret;
    QStack<char> quote;

    const ushort SPACE = ' ';
    const ushort LPAREN = '(';
    const ushort RPAREN = ')';
    const ushort SINGLEQUOTE = '\'';
    const ushort DOUBLEQUOTE = '"';
    const ushort BACKSLASH = '\\';

    if (!source)
        source = currentProFile();

    ushort unicode;
    const QChar *vals_data = vals.data();
    const int vals_len = vals.length();
269
270
    int parens = 0;
    for (int x = 0; x < vals_len; x++) {
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
        unicode = vals_data[x].unicode();
        if (x != (int)vals_len-1 && unicode == BACKSLASH &&
            (vals_data[x+1].unicode() == SINGLEQUOTE || vals_data[x+1].unicode() == DOUBLEQUOTE)) {
            build += vals_data[x++]; //get that 'escape'
        } else if (!quote.isEmpty() && unicode == quote.top()) {
            quote.pop();
        } else if (unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE) {
            quote.push(unicode);
        } else if (unicode == RPAREN) {
            --parens;
        } else if (unicode == LPAREN) {
            ++parens;
        }

        if (!parens && quote.isEmpty() && vals_data[x] == SPACE) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
286
            ret << ProString(build).setSource(source);
287
288
289
290
291
292
            build.clear();
        } else {
            build += vals_data[x];
        }
    }
    if (!build.isEmpty())
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
293
        ret << ProString(build).setSource(source);
294
295
    if (parens)
        deprecationWarning(fL1S("Unmatched parentheses are deprecated."));
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
    return ret;
}

static void zipEmpty(ProStringList *value)
{
    for (int i = value->size(); --i >= 0;)
        if (value->at(i).isEmpty())
            value->remove(i);
}

static void insertUnique(ProStringList *varlist, const ProStringList &value)
{
    foreach (const ProString &str, value)
        if (!str.isEmpty() && !varlist->contains(str))
            varlist->append(str);
}

static void removeAll(ProStringList *varlist, const ProString &value)
{
    for (int i = varlist->size(); --i >= 0; )
        if (varlist->at(i) == value)
            varlist->remove(i);
}

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
320
void QMakeEvaluator::removeEach(ProStringList *varlist, const ProStringList &value)
321
322
323
324
325
326
327
328
329
330
331
332
333
{
    foreach (const ProString &str, value)
        if (!str.isEmpty())
            removeAll(varlist, str);
}

static void replaceInList(ProStringList *varlist,
        const QRegExp &regexp, const QString &replace, bool global, QString &tmp)
{
    for (ProStringList::Iterator varit = varlist->begin(); varit != varlist->end(); ) {
        QString val = varit->toQString(tmp);
        QString copy = val; // Force detach and have a reference value
        val.replace(regexp, replace);
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
334
        if (!val.isSharedWith(copy) && val != copy) {
335
336
337
            if (val.isEmpty()) {
                varit = varlist->erase(varit);
            } else {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
338
                (*varit).setValue(val);
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
                ++varit;
            }
            if (!global)
                break;
        } else {
            ++varit;
        }
    }
}

//////// Evaluator /////////

static ALWAYS_INLINE void addStr(
        const ProString &str, ProStringList *ret, bool &pending, bool joined)
{
    if (joined) {
        ret->last().append(str, &pending);
    } else {
        if (!pending) {
            pending = true;
            *ret << str;
        } else {
            ret->last().append(str);
        }
    }
}

static ALWAYS_INLINE void addStrList(
        const ProStringList &list, ushort tok, ProStringList *ret, bool &pending, bool joined)
{
    if (!list.isEmpty()) {
        if (joined) {
            ret->last().append(list, &pending, !(tok & TokQuoted));
        } else {
            if (tok & TokQuoted) {
                if (!pending) {
                    pending = true;
                    *ret << ProString();
                }
                ret->last().append(list);
            } else {
                if (!pending) {
                    // Another qmake bizzarity: if nothing is pending and the
                    // first element is empty, it will be eaten
                    if (!list.at(0).isEmpty()) {
                        // The common case
                        pending = true;
                        *ret += list;
                        return;
                    }
                } else {
                    ret->last().append(list.at(0));
                }
                // This is somewhat slow, but a corner case
                for (int j = 1; j < list.size(); ++j) {
                    pending = true;
                    *ret << list.at(j);
                }
            }
        }
    }
}

void QMakeEvaluator::evaluateExpression(
        const ushort *&tokPtr, ProStringList *ret, bool joined)
{
405
    debugMsg(2, joined ? "evaluating joined expression" : "evaluating expression");
406
407
408
409
410
    if (joined)
        *ret << ProString();
    bool pending = false;
    forever {
        ushort tok = *tokPtr++;
411
412
        if (tok & TokNewStr) {
            debugMsg(2, "new string");
413
            pending = false;
414
        }
415
416
417
418
419
        ushort maskedTok = tok & TokMask;
        switch (maskedTok) {
        case TokLine:
            m_current.line = *tokPtr++;
            break;
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
        case TokLiteral: {
            const ProString &val = getStr(tokPtr);
            debugMsg(2, "literal %s", dbgStr(val));
            addStr(val, ret, pending, joined);
            break; }
        case TokHashLiteral: {
            const ProKey &val = getHashStr(tokPtr);
            debugMsg(2, "hashed literal %s", dbgStr(val.toString()));
            addStr(val, ret, pending, joined);
            break; }
        case TokVariable: {
            const ProKey &var = getHashStr(tokPtr);
            const ProStringList &val = values(map(var));
            debugMsg(2, "variable %s => %s", dbgKey(var), dbgStrList(val));
            addStrList(val, tok, ret, pending, joined);
            break; }
        case TokProperty: {
            const ProKey &var = getHashStr(tokPtr);
            const ProString &val = propertyValue(var);
            debugMsg(2, "property %s => %s", dbgKey(var), dbgStr(val));
            addStr(val, ret, pending, joined);
            break; }
        case TokEnvVar: {
            const ProString &var = getStr(tokPtr);
444
445
446
            const ProString &val = ProString(m_option->getEnv(var.toQString(m_tmp1)));
            debugMsg(2, "env var %s => %s", dbgStr(var), dbgStr(val));
            addStr(val, ret, pending, joined);
447
            break; }
448
        case TokFuncName: {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
449
            const ProKey &func = getHashStr(tokPtr);
450
            debugMsg(2, "function %s", dbgKey(func));
451
452
453
            addStrList(evaluateExpandFunction(func, tokPtr), tok, ret, pending, joined);
            break; }
        default:
454
            debugMsg(2, "evaluated expression => %s", dbgStrList(*ret));
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
            tokPtr--;
            return;
        }
    }
}

void QMakeEvaluator::skipExpression(const ushort *&pTokPtr)
{
    const ushort *tokPtr = pTokPtr;
    forever {
        ushort tok = *tokPtr++;
        switch (tok) {
        case TokLine:
            m_current.line = *tokPtr++;
            break;
        case TokValueTerminator:
        case TokFuncTerminator:
            pTokPtr = tokPtr;
            return;
        case TokArgSeparator:
            break;
        default:
            switch (tok & TokMask) {
            case TokLiteral:
            case TokEnvVar:
                skipStr(tokPtr);
                break;
            case TokHashLiteral:
            case TokVariable:
484
            case TokProperty:
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
                skipHashStr(tokPtr);
                break;
            case TokFuncName:
                skipHashStr(tokPtr);
                pTokPtr = tokPtr;
                skipExpression(pTokPtr);
                tokPtr = pTokPtr;
                break;
            default:
                Q_ASSERT_X(false, "skipExpression", "Unrecognized token");
                break;
            }
        }
    }
}

QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock(
        ProFile *pro, const ushort *tokPtr)
{
    m_current.pro = pro;
    m_current.line = 0;
    return visitProBlock(tokPtr);
}

QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock(
        const ushort *tokPtr)
{
512
    traceMsg("entering block");
513
514
515
516
    ProStringList curr;
    bool okey = true, or_op = false, invert = false;
    uint blockLen;
    while (ushort tok = *tokPtr++) {
517
        VisitReturn ret;
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
        switch (tok) {
        case TokLine:
            m_current.line = *tokPtr++;
            continue;
        case TokAssign:
        case TokAppend:
        case TokAppendUnique:
        case TokRemove:
        case TokReplace:
            visitProVariable(tok, curr, tokPtr);
            curr.clear();
            continue;
        case TokBranch:
            blockLen = getBlockLen(tokPtr);
            if (m_cumulative) {
533
#ifdef PROEVALUATOR_CUMULATIVE
534
535
536
537
538
539
540
541
542
543
544
545
546
                if (!okey)
                    m_skipLevel++;
                ret = blockLen ? visitProBlock(tokPtr) : ReturnTrue;
                tokPtr += blockLen;
                blockLen = getBlockLen(tokPtr);
                if (!okey)
                    m_skipLevel--;
                else
                    m_skipLevel++;
                if ((ret == ReturnTrue || ret == ReturnFalse) && blockLen)
                    ret = visitProBlock(tokPtr);
                if (okey)
                    m_skipLevel--;
547
#endif
548
            } else {
549
550
                if (okey) {
                    traceMsg("taking 'then' branch");
551
                    ret = blockLen ? visitProBlock(tokPtr) : ReturnTrue;
552
553
                    traceMsg("finished 'then' branch");
                }
554
555
                tokPtr += blockLen;
                blockLen = getBlockLen(tokPtr);
556
557
                if (!okey) {
                    traceMsg("taking 'else' branch");
558
                    ret = blockLen ? visitProBlock(tokPtr) : ReturnTrue;
559
560
                    traceMsg("finished 'else' branch");
                }
561
562
563
564
565
566
567
568
569
570
571
572
            }
            tokPtr += blockLen;
            okey = true, or_op = false; // force next evaluation
            break;
        case TokForLoop:
            if (m_cumulative) { // This is a no-win situation, so just pretend it's no loop
                skipHashStr(tokPtr);
                uint exprLen = getBlockLen(tokPtr);
                tokPtr += exprLen;
                blockLen = getBlockLen(tokPtr);
                ret = visitProBlock(tokPtr);
            } else if (okey != or_op) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
573
                const ProKey &variable = getHashStr(tokPtr);
574
575
576
577
578
579
580
581
582
583
                uint exprLen = getBlockLen(tokPtr);
                const ushort *exprPtr = tokPtr;
                tokPtr += exprLen;
                blockLen = getBlockLen(tokPtr);
                ret = visitProLoop(variable, exprPtr, tokPtr);
            } else {
                skipHashStr(tokPtr);
                uint exprLen = getBlockLen(tokPtr);
                tokPtr += exprLen;
                blockLen = getBlockLen(tokPtr);
584
                traceMsg("skipped loop");
585
586
587
588
589
590
591
592
                ret = ReturnTrue;
            }
            tokPtr += blockLen;
            okey = true, or_op = false; // force next evaluation
            break;
        case TokTestDef:
        case TokReplaceDef:
            if (m_cumulative || okey != or_op) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
593
                const ProKey &name = getHashStr(tokPtr);
594
595
                blockLen = getBlockLen(tokPtr);
                visitProFunctionDef(tok, name, tokPtr);
596
597
                traceMsg("defined %s function %s",
                      tok == TokTestDef ? "test" : "replace", dbgKey(name));
598
            } else {
599
                traceMsg("skipped function definition");
600
601
602
603
604
605
606
                skipHashStr(tokPtr);
                blockLen = getBlockLen(tokPtr);
            }
            tokPtr += blockLen;
            okey = true, or_op = false; // force next evaluation
            continue;
        case TokNot:
607
            traceMsg("NOT");
608
609
610
            invert ^= true;
            continue;
        case TokAnd:
611
            traceMsg("AND");
612
613
614
            or_op = false;
            continue;
        case TokOr:
615
            traceMsg("OR");
616
617
618
619
620
621
622
623
624
            or_op = true;
            continue;
        case TokCondition:
            if (!m_skipLevel && okey != or_op) {
                if (curr.size() != 1) {
                    if (!m_cumulative || !curr.isEmpty())
                        evalError(fL1S("Conditional must expand to exactly one word."));
                    okey = false;
                } else {
625
626
627
                    okey = isActiveConfig(curr.at(0).toQString(m_tmp2), true);
                    traceMsg("condition %s is %s", dbgStr(curr.at(0)), dbgBool(okey));
                    okey ^= invert;
628
                }
629
630
            } else {
                traceMsg("skipped condition %s", curr.size() == 1 ? dbgStr(curr.at(0)) : "<invalid>");
631
632
633
634
635
636
637
638
639
640
641
642
643
            }
            or_op = !okey; // tentatively force next evaluation
            invert = false;
            curr.clear();
            continue;
        case TokTestCall:
            if (!m_skipLevel && okey != or_op) {
                if (curr.size() != 1) {
                    if (!m_cumulative || !curr.isEmpty())
                        evalError(fL1S("Test name must expand to exactly one word."));
                    skipExpression(tokPtr);
                    okey = false;
                } else {
644
                    traceMsg("evaluating test function %s", dbgStr(curr.at(0)));
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
645
                    ret = evaluateConditionalFunction(curr.at(0).toKey(), tokPtr);
646
647
648
                    switch (ret) {
                    case ReturnTrue: okey = true; break;
                    case ReturnFalse: okey = false; break;
649
650
651
                    default:
                        traceMsg("aborting block, function status: %s", dbgReturn(ret));
                        return ret;
652
                    }
653
                    traceMsg("test function returned %s", dbgBool(okey));
654
655
656
                    okey ^= invert;
                }
            } else if (m_cumulative) {
657
#ifdef PROEVALUATOR_CUMULATIVE
658
659
660
661
                m_skipLevel++;
                if (curr.size() != 1)
                    skipExpression(tokPtr);
                else
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
662
                    evaluateConditionalFunction(curr.at(0).toKey(), tokPtr);
663
                m_skipLevel--;
664
#endif
665
666
            } else {
                skipExpression(tokPtr);
667
                traceMsg("skipped test function %s", curr.size() == 1 ? dbgStr(curr.at(0)) : "<invalid>");
668
669
670
671
672
            }
            or_op = !okey; // tentatively force next evaluation
            invert = false;
            curr.clear();
            continue;
673
674
675
676
677
678
679
680
681
682
683
        case TokReturn:
            m_returnValue = curr;
            curr.clear();
            ret = ReturnReturn;
            goto ctrlstm;
        case TokBreak:
            ret = ReturnBreak;
            goto ctrlstm;
        case TokNext:
            ret = ReturnNext;
          ctrlstm:
684
685
            if (!m_skipLevel && okey != or_op) {
                traceMsg("flow control statement '%s', aborting block", dbgReturn(ret));
686
                return ret;
687
688
            }
            traceMsg("skipped flow control statement '%s'", dbgReturn(ret));
689
690
            okey = false, or_op = true; // force next evaluation
            continue;
691
692
693
694
695
696
697
        default: {
                const ushort *oTokPtr = --tokPtr;
                evaluateExpression(tokPtr, &curr, false);
                if (tokPtr != oTokPtr)
                    continue;
            }
            Q_ASSERT_X(false, "visitProBlock", "unexpected item type");
698
            continue;
699
        }
700
701
        if (ret != ReturnTrue && ret != ReturnFalse) {
            traceMsg("aborting block, status: %s", dbgReturn(ret));
702
            return ret;
703
        }
704
    }
705
    traceMsg("leaving block, okey=%s", dbgBool(okey));
706
    return returnBool(okey);
707
708
709
710
}


void QMakeEvaluator::visitProFunctionDef(
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
711
        ushort tok, const ProKey &name, const ushort *tokPtr)
712
{
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
713
    QHash<ProKey, ProFunctionDef> *hash =
714
715
716
717
718
719
720
            (tok == TokTestDef
             ? &m_functionDefs.testFunctions
             : &m_functionDefs.replaceFunctions);
    hash->insert(name, ProFunctionDef(m_current.pro, tokPtr - m_current.pro->tokPtr()));
}

QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop(
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
721
        const ProKey &_variable, const ushort *exprPtr, const ushort *tokPtr)
722
723
724
725
{
    VisitReturn ret = ReturnTrue;
    bool infinite = false;
    int index = 0;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
726
    ProKey variable;
727
728
729
730
731
732
733
734
735
736
    ProStringList oldVarVal;
    ProString it_list = expandVariableReferences(exprPtr, 0, true).at(0);
    if (_variable.isEmpty()) {
        if (it_list != statics.strever) {
            evalError(fL1S("Invalid loop expression."));
            return ReturnFalse;
        }
        it_list = ProString(statics.strforever);
    } else {
        variable = map(_variable);
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
737
        oldVarVal = values(variable);
738
    }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
739
    ProStringList list = values(it_list.toKey());
740
741
742
743
744
745
746
747
748
749
750
751
752
753
    if (list.isEmpty()) {
        if (it_list == statics.strforever) {
            infinite = true;
        } else {
            const QString &itl = it_list.toQString(m_tmp1);
            int dotdot = itl.indexOf(statics.strDotDot);
            if (dotdot != -1) {
                bool ok;
                int start = itl.left(dotdot).toInt(&ok);
                if (ok) {
                    int end = itl.mid(dotdot+2).toInt(&ok);
                    if (ok) {
                        if (start < end) {
                            for (int i = start; i <= end; i++)
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
754
                                list << ProString(QString::number(i));
755
756
                        } else {
                            for (int i = start; i >= end; i--)
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
757
                                list << ProString(QString::number(i));
758
759
760
761
762
763
764
                        }
                    }
                }
            }
        }
    }

765
766
767
768
769
    if (infinite)
        traceMsg("entering infinite loop for %s", dbgKey(variable));
    else
        traceMsg("entering loop for %s over %s", dbgKey(variable), dbgStrList(list));

770
771
772
    forever {
        if (infinite) {
            if (!variable.isEmpty())
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
773
                m_valuemapStack.top()[variable] = ProStringList(ProString(QString::number(index++)));
774
            if (index > 1000) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
775
                evalError(fL1S("Ran into infinite loop (> 1000 iterations)."));
776
777
                break;
            }
778
            traceMsg("loop iteration %d", index);
779
780
781
782
783
784
785
        } else {
            ProString val;
            do {
                if (index >= list.count())
                    goto do_break;
                val = list.at(index++);
            } while (val.isEmpty()); // stupid, but qmake is like that
786
            traceMsg("loop iteration %s", dbgStr(val));
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
            m_valuemapStack.top()[variable] = ProStringList(val);
        }

        ret = visitProBlock(tokPtr);
        switch (ret) {
        case ReturnTrue:
        case ReturnFalse:
            break;
        case ReturnNext:
            ret = ReturnTrue;
            break;
        case ReturnBreak:
            ret = ReturnTrue;
            goto do_break;
        default:
            goto do_break;
        }
    }
  do_break:

807
808
    traceMsg("done looping");

809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
    if (!variable.isEmpty())
        m_valuemapStack.top()[variable] = oldVarVal;
    return ret;
}

void QMakeEvaluator::visitProVariable(
        ushort tok, const ProStringList &curr, const ushort *&tokPtr)
{
    int sizeHint = *tokPtr++;

    if (curr.size() != 1) {
        skipExpression(tokPtr);
        if (!m_cumulative || !curr.isEmpty())
            evalError(fL1S("Left hand side of assignment must expand to exactly one word."));
        return;
    }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
825
    const ProKey &varName = map(curr.first());
826
827
828
829
830
831
832

    if (tok == TokReplace) {      // ~=
        // DEFINES ~= s/a/b/?[gqi]

        const ProStringList &varVal = expandVariableReferences(tokPtr, sizeHint, true);
        const QString &val = varVal.at(0).toQString(m_tmp1);
        if (val.length() < 4 || val.at(0) != QLatin1Char('s')) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
833
            evalError(fL1S("The ~= operator can handle only the s/// function."));
834
835
836
837
838
            return;
        }
        QChar sep = val.at(1);
        QStringList func = val.split(sep);
        if (func.count() < 3 || func.count() > 4) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
839
            evalError(fL1S("The s/// function expects 3 or 4 arguments."));
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
            return;
        }

        bool global = false, quote = false, case_sense = false;
        if (func.count() == 4) {
            global = func[3].indexOf(QLatin1Char('g')) != -1;
            case_sense = func[3].indexOf(QLatin1Char('i')) == -1;
            quote = func[3].indexOf(QLatin1Char('q')) != -1;
        }
        QString pattern = func[1];
        QString replace = func[2];
        if (quote)
            pattern = QRegExp::escape(pattern);

        QRegExp regexp(pattern, case_sense ? Qt::CaseSensitive : Qt::CaseInsensitive);

856
857
858
        // We could make a union of modified and unmodified values,
        // but this will break just as much as it fixes, so leave it as is.
        replaceInList(&valuesRef(varName), regexp, replace, global, m_tmp2);
859
        debugMsg(2, "replaced %s with %s", dbgQStr(pattern), dbgQStr(replace));
860
861
862
863
864
    } else {
        ProStringList varVal = expandVariableReferences(tokPtr, sizeHint);
        switch (tok) {
        default: // whatever - cannot happen
        case TokAssign:          // =
865
            zipEmpty(&varVal);
866
            if (!m_cumulative) {
867
868
869
                // FIXME: add check+warning about accidental value removal.
                // This may be a bit too noisy, though.
                m_valuemapStack.top()[varName] = varVal;
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
            } else {
                if (!varVal.isEmpty()) {
                    // We are greedy for values. But avoid exponential growth.
                    ProStringList &v = valuesRef(varName);
                    if (v.isEmpty()) {
                        v = varVal;
                    } else {
                        ProStringList old = v;
                        v = varVal;
                        QSet<ProString> has;
                        has.reserve(v.size());
                        foreach (const ProString &s, v)
                            has.insert(s);
                        v.reserve(v.size() + old.size());
                        foreach (const ProString &s, old)
                            if (!has.contains(s))
                                v << s;
                    }
                }
            }
890
            debugMsg(2, "assigning");
891
892
            break;
        case TokAppendUnique:    // *=
893
            insertUnique(&valuesRef(varName), varVal);
894
            debugMsg(2, "appending unique");
895
896
            break;
        case TokAppend:          // +=
897
898
            zipEmpty(&varVal);
            valuesRef(varName) += varVal;
899
            debugMsg(2, "appending");
900
901
902
            break;
        case TokRemove:       // -=
            if (!m_cumulative) {
903
                removeEach(&valuesRef(varName), varVal);
904
905
906
            } else {
                // We are stingy with our values, too.
            }
907
            debugMsg(2, "removing");
908
909
910
            break;
        }
    }
911
    traceMsg("%s := %s", dbgKey(varName), dbgStrList(values(varName)));
912
913
914

    if (varName == statics.strTEMPLATE)
        setTemplate();
915
916
917
918
#ifdef PROEVALUATOR_FULL
    else if (varName == statics.strREQUIRES)
        checkRequirements(values(varName));
#endif
919
920
921
922
923
}

void QMakeEvaluator::setTemplate()
{
    ProStringList &values = valuesRef(statics.strTEMPLATE);
924
925
    if (!m_option->user_template.isEmpty()) {
        // Don't allow override
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
926
        values = ProStringList(ProString(m_option->user_template));
927
928
    } else {
        if (values.isEmpty())
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
929
            values.append(ProString("app"));
930
931
932
933
934
935
936
        else
            values.erase(values.begin() + 1, values.end());
    }
    if (!m_option->user_template_prefix.isEmpty()) {
        QString val = values.first().toQString(m_tmp1);
        if (!val.startsWith(m_option->user_template_prefix)) {
            val.prepend(m_option->user_template_prefix);
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
937
            values = ProStringList(ProString(val));
938
939
        }
    }
940
941
}

942
943
944
945
void QMakeEvaluator::loadDefaults()
{
    ProValueMap &vars = m_valuemapStack.top();

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
946
947
948
    vars[ProKey("DIR_SEPARATOR")] << ProString(m_option->dir_sep);
    vars[ProKey("DIRLIST_SEPARATOR")] << ProString(m_option->dirlist_sep);
    vars[ProKey("_DATE_")] << ProString(QDateTime::currentDateTime().toString());
949
    if (!m_option->qmake_abslocation.isEmpty())
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
950
        vars[ProKey("QMAKE_QMAKE")] << ProString(m_option->qmake_abslocation);
951
#if defined(Q_OS_WIN32)
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
952
    vars[ProKey("QMAKE_HOST.os")] << ProString("Windows");
953
954
955
956

    DWORD name_length = 1024;
    wchar_t name[1024];
    if (GetComputerName(name, &name_length))
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
957
        vars[ProKey("QMAKE_HOST.name")] << ProString(QString::fromWCharArray(name));
958
959

    QSysInfo::WinVersion ver = QSysInfo::WindowsVersion;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
960
    vars[ProKey("QMAKE_HOST.version")] << ProString(QString::number(ver));
961
962
    ProString verStr;
    switch (ver) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
963
964
965
966
967
968
969
970
971
    case QSysInfo::WV_Me: verStr = ProString("WinMe"); break;
    case QSysInfo::WV_95: verStr = ProString("Win95"); break;
    case QSysInfo::WV_98: verStr = ProString("Win98"); break;
    case QSysInfo::WV_NT: verStr = ProString("WinNT"); break;
    case QSysInfo::WV_2000: verStr = ProString("Win2000"); break;
    case QSysInfo::WV_2003: verStr = ProString("Win2003"); break;
    case QSysInfo::WV_XP: verStr = ProString("WinXP"); break;
    case QSysInfo::WV_VISTA: verStr = ProString("WinVista"); break;
    default: verStr = ProString("Unknown"); break;
972
    }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
973
    vars[ProKey("QMAKE_HOST.version_string")] << verStr;
974
975
976
977
978
979
980

    SYSTEM_INFO info;
    GetSystemInfo(&info);
    ProString archStr;
    switch (info.wProcessorArchitecture) {
# ifdef PROCESSOR_ARCHITECTURE_AMD64
    case PROCESSOR_ARCHITECTURE_AMD64:
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
981
        archStr = ProString("x86_64");
982
983
984
        break;
# endif
    case PROCESSOR_ARCHITECTURE_INTEL:
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
985
        archStr = ProString("x86");
986
987
988
989
990
        break;
    case PROCESSOR_ARCHITECTURE_IA64:
# ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
    case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
# endif
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
991
        archStr = ProString("IA64");
992
993
        break;
    default:
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
994
        archStr = ProString("Unknown");
995
996
        break;
    }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
997
    vars[ProKey("QMAKE_HOST.arch")] << archStr;
998
999

# if defined(Q_CC_MSVC) // ### bogus condition, but nobody x-builds for msvc with a different qmake
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
    QLatin1Char backslash('\\');
    QString paths = m_option->getEnv(QLatin1String("PATH"));
    QString vcBin64 = m_option->getEnv(QLatin1String("VCINSTALLDIR"));
    if (!vcBin64.endsWith(backslash))
        vcBin64.append(backslash);
    vcBin64.append(QLatin1String("bin\\amd64"));
    QString vcBinX86_64 = m_option->getEnv(QLatin1String("VCINSTALLDIR"));
    if (!vcBinX86_64.endsWith(backslash))
        vcBinX86_64.append(backslash);
    vcBinX86_64.append(QLatin1String("bin\\x86_amd64"));
1010
1011
    if (paths.contains(vcBin64, Qt::CaseInsensitive)
            || paths.contains(vcBinX86_64, Qt::CaseInsensitive))
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1012
        vars[ProKey("QMAKE_TARGET.arch")] << ProString("x86_64");
1013
    else
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1014
        vars[ProKey("QMAKE_TARGET.arch")] << ProString("x86");
1015
# endif
1016
1017
1018
#elif defined(Q_OS_UNIX)
    struct utsname name;
    if (!uname(&name)) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1019
1020
1021
1022
1023
        vars[ProKey("QMAKE_HOST.os")] << ProString(name.sysname);
        vars[ProKey("QMAKE_HOST.name")] << ProString(QString::fromLocal8Bit(name.nodename));
        vars[ProKey("QMAKE_HOST.version")] << ProString(name.release);
        vars[ProKey("QMAKE_HOST.version_string")] << ProString(name.version);
        vars[ProKey("QMAKE_HOST.arch")] << ProString(name.machine);
1024
1025
    }
#endif
1026
1027

    m_valuemapInited = true;
1028
1029
}

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1030
bool QMakeEvaluator::prepareProject(const QString &inDir)
1031
{
1032
    QString superdir;
1033
    if (m_option->do_cache) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1034
        QString conffile;
1035
1036
1037
1038
        QString cachefile = m_option->cachefile;
        if (cachefile.isEmpty())  { //find it as it has not been specified
            if (m_outputDir.isEmpty())
                goto no_cache;
1039
            superdir = m_outputDir;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
            forever {
                QString superfile = superdir + QLatin1String("/.qmake.super");
                if (IoUtils::exists(superfile)) {
                    m_superfile = superfile;
                    break;
                }
                QFileInfo qdfi(superdir);
                if (qdfi.isRoot()) {
                    superdir.clear();
                    break;
                }
                superdir = qdfi.path();
            }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1053
            QString sdir = inDir;
1054
            QString dir = m_outputDir;
1055
            forever {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1056
1057
1058
                conffile = sdir + QLatin1String("/.qmake.conf");
                if (!IoUtils::exists(conffile))
                    conffile.clear();
1059
                cachefile = dir + QLatin1String("/.qmake.cache");
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1060
1061
1062
                if (!IoUtils::exists(cachefile))
                    cachefile.clear();
                if (!conffile.isEmpty() || !cachefile.isEmpty()) {
1063
1064
                    if (dir != sdir)
                        m_sourceRoot = sdir;
1065
                    m_buildRoot = dir;
1066
1067
                    break;
                }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1068
1069
                if (dir == superdir)
                    goto no_cache;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1070
                QFileInfo qsdfi(sdir);
1071
                QFileInfo qdfi(dir);
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1072
                if (qsdfi.isRoot() || qdfi.isRoot())
1073
                    goto no_cache;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1074
                sdir = qsdfi.path();
1075
                dir = qdfi.path();
1076
            }
1077
1078
        } else {
            m_buildRoot = QFileInfo(cachefile).path();
1079
        }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1080
        m_conffile = conffile;
1081
        m_cachefile = cachefile;
1082
    }
1083
  no_cache:
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105

    // Look for mkspecs/ in source and build. First to win determines the root.
    QString sdir = inDir;
    QString dir = m_outputDir;
    while (dir != m_buildRoot) {
        if ((dir != sdir && QFileInfo(sdir, QLatin1String("mkspecs")).isDir())
                || QFileInfo(dir, QLatin1String("mkspecs")).isDir()) {
            if (dir != sdir)
                m_sourceRoot = sdir;
            m_buildRoot = dir;
            break;
        }
        if (dir == superdir)
            break;
        QFileInfo qsdfi(sdir);
        QFileInfo qdfi(dir);
        if (qsdfi.isRoot() || qdfi.isRoot())
            break;
        sdir = qsdfi.path();
        dir = qdfi.path();
    }

1106
    return true;
1107
1108
}

1109
1110
1111
1112
1113
bool QMakeEvaluator::loadSpecInternal()
{
    if (!evaluateFeatureFile(QLatin1String("spec_pre.prf")))
        return false;
    QString spec = m_qmakespec + QLatin1String("/qmake.conf");
1114
    if (!evaluateFile(spec, QMakeHandler::EvalConfigFile, LoadProOnly)) {
1115
1116
1117
        evalError(fL1S("Could not read qmake configuration file %1.").arg(spec));
        return false;
    }
1118
1119
1120
#ifndef QT_BUILD_QMAKE
    // Legacy support for Qt4 default specs
#  ifdef Q_OS_UNIX
1121
1122
1123
1124
1125
1126
    if (m_qmakespec.endsWith(QLatin1String("/default-host"))
        || m_qmakespec.endsWith(QLatin1String("/default"))) {
        QString rspec = QFileInfo(m_qmakespec).readLink();
        if (!rspec.isEmpty())
            m_qmakespec = QDir::cleanPath(QDir(m_qmakespec).absoluteFilePath(rspec));
    }
1127
#  else
1128
1129
1130
1131
    // We can't resolve symlinks as they do on Unix, so configure.exe puts
    // the source of the qmake.conf at the end of the default/qmake.conf in
    // the QMAKESPEC_ORIGINAL variable.
    const ProString &orig_spec = first(ProKey("QMAKESPEC_ORIGINAL"));
1132
1133
    if (!orig_spec.isEmpty())
        m_qmakespec = orig_spec.toQString();
1134
#  endif
1135
#endif
1136
1137
    valuesRef(ProKey("QMAKESPEC")) << ProString(m_qmakespec);
    m_qmakespecName = IoUtils::fileName(m_qmakespec).toString();
1138
1139
1140
1141
1142
1143
1144
    if (!evaluateFeatureFile(QLatin1String("spec_post.prf")))
        return false;
    // The MinGW and x-build specs may change the separator; $$shell_{path,quote}() need it
    m_dirSep = first(ProKey("QMAKE_DIR_SEP"));
    return true;
}

1145
bool QMakeEvaluator::loadSpec()
1146
{
1147
1148
    QString qmakespec = m_option->expandEnvVars(
                m_hostBuild ? m_option->qmakespec : m_option->xqmakespec);
1149
1150
1151

    {
        QMakeEvaluator evaluator(m_option, m_parser, m_handler);
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1152
        if (!m_superfile.isEmpty()) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1153
            valuesRef(ProKey("_QMAKE_SUPER_CACHE_")) << ProString(m_superfile);
1154
            if (!evaluator.evaluateFile(m_superfile, QMakeHandler::EvalConfigFile, LoadProOnly))
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1155
1156
                return false;
        }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1157
        if (!m_conffile.isEmpty()) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1158
            valuesRef(ProKey("_QMAKE_CONF_")) << ProString(m_conffile);
1159
            if (!evaluator.evaluateFile(m_conffile, QMakeHandler::EvalConfigFile, LoadProOnly))
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1160
1161
                return false;
        }
1162
        if (!m_cachefile.isEmpty()) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1163
            valuesRef(ProKey("_QMAKE_CACHE_")) << ProString(m_cachefile);
1164
            if (!evaluator.evaluateFile(m_cachefile, QMakeHandler::EvalConfigFile, LoadProOnly))
1165
1166
                return false;
        }
1167
1168
        if (qmakespec.isEmpty()) {
            if (!m_hostBuild)
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1169
                qmakespec = evaluator.first(ProKey("XQMAKESPEC")).toQString();
1170
            if (qmakespec.isEmpty())
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1171
                qmakespec = evaluator.first(ProKey("QMAKESPEC")).toQString();
1172
        }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1173
1174
        m_qmakepath = evaluator.values(ProKey("QMAKEPATH")).toQStringList();
        m_qmakefeatures = evaluator.values(ProKey("QMAKEFEATURES")).toQStringList();
1175
1176
    }

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1177
    updateMkspecPaths();
1178
1179
1180
1181
    if (qmakespec.isEmpty())
        qmakespec = propertyValue(ProKey(m_hostBuild ? "QMAKE_SPEC" : "QMAKE_XSPEC")).toQString();
#ifndef QT_BUILD_QMAKE
    // Legacy support for Qt4 qmake in Qt Creator, etc.
1182
    if (qmakespec.isEmpty())
1183
        qmakespec = m_hostBuild ? QLatin1String("default-host") : QLatin1String("default");
1184
#endif
1185
    if (IoUtils::isRelativePath(qmakespec)) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1186
        foreach (const QString &root, m_mkspecPaths) {
1187
1188
1189
1190
1191
1192
            QString mkspec = root + QLatin1Char('/') + qmakespec;
            if (IoUtils::exists(mkspec)) {
                qmakespec = mkspec;
                goto cool;
            }
        }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1193
        evalError(fL1S("Could not find qmake configuration file %1.").arg(qmakespec));
1194
        return false;
1195
1196
    }
  cool:
1197
    m_qmakespec = QDir::cleanPath(qmakespec);
1198

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1199
    if (!m_superfile.isEmpty()
1200
        && !evaluateFile(m_superfile, QMakeHandler::EvalConfigFile, LoadProOnly)) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1201
1202
        return false;
    }
1203
    if (!loadSpecInternal())
1204
        return false;