qmakeevaluator.cpp 55 KB
Newer Older
1
2
3
4
5
6
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
Eike Ziller's avatar
Eike Ziller committed
7
** Contact: http://www.qt-project.org/
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
**
**
** GNU Lesser General Public License Usage
**
** 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.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/

#include "qmakeevaluator.h"

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

#include <QByteArray>
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QList>
#include <QRegExp>
#include <QSet>
#include <QStack>
#include <QString>
#include <QStringList>
#ifdef PROEVALUATOR_THREAD_SAFE
# include <QThreadPool>
#endif

#ifdef Q_OS_UNIX
#include <unistd.h>
#include <sys/utsname.h>
#else
Yuchen Deng's avatar
Yuchen Deng committed
58
#include <windows.h>
59
60
61
62
63
64
65
66
67
68
#endif
#include <stdio.h>
#include <stdlib.h>

using namespace ProFileEvaluatorInternal;

QT_BEGIN_NAMESPACE

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

69

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

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

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

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

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

98
99
100
101
102
103
104
105
106
107
108
109
namespace ProFileEvaluatorInternal {
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
110
111
    statics.strCONFIG = ProKey("CONFIG");
    statics.strARGS = ProKey("ARGS");
112
113
114
115
    statics.strDot = QLatin1String(".");
    statics.strDotDot = QLatin1String("..");
    statics.strever = QLatin1String("ever");
    statics.strforever = QLatin1String("forever");
116
    statics.strhost_build = QLatin1String("host_build");
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
117
    statics.strTEMPLATE = ProKey("TEMPLATE");
118
#ifdef PROEVALUATOR_FULL
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
119
    statics.strREQUIRES = ProKey("REQUIRES");
120
#endif
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
146

    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
147
148
        { "QMAKE_FRAMEWORKDIR_FLAGS", "QMAKE_FRAMEWORKPATH_FLAGS" },
        { "IN_PWD", "PWD" }
149
150
    };
    for (unsigned i = 0; i < sizeof(mapInits)/sizeof(mapInits[0]); ++i)
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
151
        statics.varMap.insert(ProKey(mapInits[i].oldname), ProKey(mapInits[i].newname));
152
153
}

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


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

    // Configuration, more or less
173
    m_caller = 0;
174
#ifdef PROEVALUATOR_CUMULATIVE
175
    m_cumulative = false;
176
#endif
177
    m_hostBuild = false;
178
179

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

QMakeEvaluator::~QMakeEvaluator()
{
}

193
194
195
196
197
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;
198
    m_valuemapInited = true;
199
    m_qmakespec = other.m_qmakespec;
200
    m_qmakespecFull = other.m_qmakespecFull;
201
    m_qmakespecName = other.m_qmakespecName;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
202
    m_mkspecPaths = other.m_mkspecPaths;
203
    m_featureRoots = other.m_featureRoots;
204
205
}

206
207
208
209
210
211
212
213
214
215
216
217
//////// 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
218
    ProString ret(m_current.pro->items(), tokPtr - m_current.pro->tokPtr(), len);
219
220
221
222
223
    ret.setSource(m_current.pro);
    tokPtr += len;
    return ret;
}

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
224
ProKey QMakeEvaluator::getHashStr(const ushort *&tokPtr)
225
226
227
{
    uint hash = getBlockLen(tokPtr);
    uint len = *tokPtr++;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
228
    ProKey ret(m_current.pro->items(), tokPtr - m_current.pro->tokPtr(), len, hash);
229
230
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
    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();
267
268
    int parens = 0;
    for (int x = 0; x < vals_len; x++) {
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
        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
284
            ret << ProString(build).setSource(source);
285
286
287
288
289
290
            build.clear();
        } else {
            build += vals_data[x];
        }
    }
    if (!build.isEmpty())
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
291
        ret << ProString(build).setSource(source);
292
293
    if (parens)
        deprecationWarning(fL1S("Unmatched parentheses are deprecated."));
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
    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
318
void QMakeEvaluator::removeEach(ProStringList *varlist, const ProStringList &value)
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
{
    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);
        if (!val.isSharedWith(copy)) {
            if (val.isEmpty()) {
                varit = varlist->erase(varit);
            } else {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
336
                (*varit).setValue(val);
337
338
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
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
                ++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)
{
    if (joined)
        *ret << ProString();
    bool pending = false;
    forever {
        ushort tok = *tokPtr++;
        if (tok & TokNewStr)
            pending = false;
        ushort maskedTok = tok & TokMask;
        switch (maskedTok) {
        case TokLine:
            m_current.line = *tokPtr++;
            break;
        case TokLiteral:
            addStr(getStr(tokPtr), ret, pending, joined);
            break;
        case TokHashLiteral:
            addStr(getHashStr(tokPtr), ret, pending, joined);
            break;
        case TokVariable:
            addStrList(values(map(getHashStr(tokPtr))), tok, ret, pending, joined);
            break;
        case TokProperty:
425
            addStr(propertyValue(getHashStr(tokPtr)).setSource(currentProFile()),
426
427
428
429
430
431
432
                   ret, pending, joined);
            break;
        case TokEnvVar:
            addStrList(split_value_list(m_option->getEnv(getStr(tokPtr).toQString(m_tmp1))),
                       tok, ret, pending, joined);
            break;
        case TokFuncName: {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
433
            const ProKey &func = getHashStr(tokPtr);
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
            addStrList(evaluateExpandFunction(func, tokPtr), tok, ret, pending, joined);
            break; }
        default:
            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:
466
            case TokProperty:
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
                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)
{
    ProStringList curr;
    bool okey = true, or_op = false, invert = false;
    uint blockLen;
    while (ushort tok = *tokPtr++) {
498
        VisitReturn ret;
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
        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) {
514
#ifdef PROEVALUATOR_CUMULATIVE
515
516
517
518
519
520
521
522
523
524
525
526
527
                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--;
528
#endif
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
            } else {
                if (okey)
                    ret = blockLen ? visitProBlock(tokPtr) : ReturnTrue;
                tokPtr += blockLen;
                blockLen = getBlockLen(tokPtr);
                if (!okey)
                    ret = blockLen ? visitProBlock(tokPtr) : ReturnTrue;
            }
            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
548
                const ProKey &variable = getHashStr(tokPtr);
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
                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);
                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
567
                const ProKey &name = getHashStr(tokPtr);
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
                blockLen = getBlockLen(tokPtr);
                visitProFunctionDef(tok, name, tokPtr);
            } else {
                skipHashStr(tokPtr);
                blockLen = getBlockLen(tokPtr);
            }
            tokPtr += blockLen;
            okey = true, or_op = false; // force next evaluation
            continue;
        case TokNot:
            invert ^= true;
            continue;
        case TokAnd:
            or_op = false;
            continue;
        case TokOr:
            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 {
                    okey = isActiveConfig(curr.at(0).toQString(m_tmp2), true) ^ invert;
                }
            }
            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 {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
608
                    ret = evaluateConditionalFunction(curr.at(0).toKey(), tokPtr);
609
610
611
612
613
614
615
616
                    switch (ret) {
                    case ReturnTrue: okey = true; break;
                    case ReturnFalse: okey = false; break;
                    default: return ret;
                    }
                    okey ^= invert;
                }
            } else if (m_cumulative) {
617
#ifdef PROEVALUATOR_CUMULATIVE
618
619
620
621
                m_skipLevel++;
                if (curr.size() != 1)
                    skipExpression(tokPtr);
                else
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
622
                    evaluateConditionalFunction(curr.at(0).toKey(), tokPtr);
623
                m_skipLevel--;
624
#endif
625
626
627
628
629
630
631
632
633
634
635
636
637
638
            } else {
                skipExpression(tokPtr);
            }
            or_op = !okey; // tentatively force next evaluation
            invert = false;
            curr.clear();
            continue;
        default: {
                const ushort *oTokPtr = --tokPtr;
                evaluateExpression(tokPtr, &curr, false);
                if (tokPtr != oTokPtr)
                    continue;
            }
            Q_ASSERT_X(false, "visitProBlock", "unexpected item type");
639
            continue;
640
641
        }
        if (ret != ReturnTrue && ret != ReturnFalse)
642
            return ret;
643
    }
644
    return returnBool(okey);
645
646
647
648
}


void QMakeEvaluator::visitProFunctionDef(
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
649
        ushort tok, const ProKey &name, const ushort *tokPtr)
650
{
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
651
    QHash<ProKey, ProFunctionDef> *hash =
652
653
654
655
656
657
658
            (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
659
        const ProKey &_variable, const ushort *exprPtr, const ushort *tokPtr)
660
661
662
663
{
    VisitReturn ret = ReturnTrue;
    bool infinite = false;
    int index = 0;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
664
    ProKey variable;
665
666
667
668
669
670
671
672
673
674
    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
675
        oldVarVal = values(variable);
676
    }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
677
    ProStringList list = values(it_list.toKey());
678
679
680
681
682
683
684
685
686
687
688
689
690
691
    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
692
                                list << ProString(QString::number(i));
693
694
                        } else {
                            for (int i = start; i >= end; i--)
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
695
                                list << ProString(QString::number(i));
696
697
698
699
700
701
702
703
704
705
706
                        }
                    }
                }
            }
        }
    }

    m_loopLevel++;
    forever {
        if (infinite) {
            if (!variable.isEmpty())
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
707
                m_valuemapStack.top()[variable] = ProStringList(ProString(QString::number(index++)));
708
            if (index > 1000) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
709
                evalError(fL1S("Ran into infinite loop (> 1000 iterations)."));
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
                break;
            }
        } else {
            ProString val;
            do {
                if (index >= list.count())
                    goto do_break;
                val = list.at(index++);
            } while (val.isEmpty()); // stupid, but qmake is like that
            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:
    m_loopLevel--;

    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
756
    const ProKey &varName = map(curr.first());
757
758
759
760
761
762
763

    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
764
            evalError(fL1S("The ~= operator can handle only the s/// function."));
765
766
767
768
769
            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
770
            evalError(fL1S("The s/// function expects 3 or 4 arguments."));
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
            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);

787
788
789
        // 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);
790
791
792
793
794
    } else {
        ProStringList varVal = expandVariableReferences(tokPtr, sizeHint);
        switch (tok) {
        default: // whatever - cannot happen
        case TokAssign:          // =
795
            zipEmpty(&varVal);
796
            if (!m_cumulative) {
797
798
799
                // FIXME: add check+warning about accidental value removal.
                // This may be a bit too noisy, though.
                m_valuemapStack.top()[varName] = varVal;
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
            } 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;
                    }
                }
            }
            break;
        case TokAppendUnique:    // *=
822
            insertUnique(&valuesRef(varName), varVal);
823
824
            break;
        case TokAppend:          // +=
825
826
            zipEmpty(&varVal);
            valuesRef(varName) += varVal;
827
828
829
            break;
        case TokRemove:       // -=
            if (!m_cumulative) {
830
                removeEach(&valuesRef(varName), varVal);
831
832
833
834
835
836
            } else {
                // We are stingy with our values, too.
            }
            break;
        }
    }
837
838
839

    if (varName == statics.strTEMPLATE)
        setTemplate();
840
841
842
843
#ifdef PROEVALUATOR_FULL
    else if (varName == statics.strREQUIRES)
        checkRequirements(values(varName));
#endif
844
845
846
847
848
}

void QMakeEvaluator::setTemplate()
{
    ProStringList &values = valuesRef(statics.strTEMPLATE);
849
850
    if (!m_option->user_template.isEmpty()) {
        // Don't allow override
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
851
        values = ProStringList(ProString(m_option->user_template));
852
853
    } else {
        if (values.isEmpty())
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
854
            values.append(ProString("app"));
855
856
857
858
859
860
861
        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
862
            values = ProStringList(ProString(val));
863
864
        }
    }
865
866
}

867
868
869
870
void QMakeEvaluator::loadDefaults()
{
    ProValueMap &vars = m_valuemapStack.top();

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
871
872
873
    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());
874
    if (!m_option->qmake_abslocation.isEmpty())
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
875
        vars[ProKey("QMAKE_QMAKE")] << ProString(m_option->qmake_abslocation);
876
#if defined(Q_OS_WIN32)
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
877
    vars[ProKey("QMAKE_HOST.os")] << ProString("Windows");
878
879
880
881

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

    QSysInfo::WinVersion ver = QSysInfo::WindowsVersion;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
885
    vars[ProKey("QMAKE_HOST.version")] << ProString(QString::number(ver));
886
887
    ProString verStr;
    switch (ver) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
888
889
890
891
892
893
894
895
896
    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;
897
    }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
898
    vars[ProKey("QMAKE_HOST.version_string")] << verStr;
899
900
901
902
903
904
905

    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
906
        archStr = ProString("x86_64");
907
908
909
        break;
# endif
    case PROCESSOR_ARCHITECTURE_INTEL:
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
910
        archStr = ProString("x86");
911
912
913
914
915
        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
916
        archStr = ProString("IA64");
917
918
        break;
    default:
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
919
        archStr = ProString("Unknown");
920
921
        break;
    }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
922
    vars[ProKey("QMAKE_HOST.arch")] << archStr;
923
924

# if defined(Q_CC_MSVC) // ### bogus condition, but nobody x-builds for msvc with a different qmake
925
926
927
928
929
930
931
932
933
934
    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"));
935
936
    if (paths.contains(vcBin64, Qt::CaseInsensitive)
            || paths.contains(vcBinX86_64, Qt::CaseInsensitive))
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
937
        vars[ProKey("QMAKE_TARGET.arch")] << ProString("x86_64");
938
    else
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
939
        vars[ProKey("QMAKE_TARGET.arch")] << ProString("x86");
940
# endif
941
942
943
#elif defined(Q_OS_UNIX)
    struct utsname name;
    if (!uname(&name)) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
944
945
946
947
948
        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);
949
950
    }
#endif
951
952

    m_valuemapInited = true;
953
954
}

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
955
bool QMakeEvaluator::prepareProject(const QString &inDir)
956
{
957
    QString superdir;
958
    if (m_option->do_cache) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
959
        QString conffile;
960
961
962
963
        QString cachefile = m_option->cachefile;
        if (cachefile.isEmpty())  { //find it as it has not been specified
            if (m_outputDir.isEmpty())
                goto no_cache;
964
            superdir = m_outputDir;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
965
966
967
968
969
970
971
972
973
974
975
976
977
            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
978
            QString sdir = inDir;
979
            QString dir = m_outputDir;
980
            forever {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
981
982
983
                conffile = sdir + QLatin1String("/.qmake.conf");
                if (!IoUtils::exists(conffile))
                    conffile.clear();
984
                cachefile = dir + QLatin1String("/.qmake.cache");
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
985
986
987
                if (!IoUtils::exists(cachefile))
                    cachefile.clear();
                if (!conffile.isEmpty() || !cachefile.isEmpty()) {
988
989
                    if (dir != sdir)
                        m_sourceRoot = sdir;
990
                    m_buildRoot = dir;
991
992
                    break;
                }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
993
994
                if (dir == superdir)
                    goto no_cache;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
995
                QFileInfo qsdfi(sdir);
996
                QFileInfo qdfi(dir);
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
997
                if (qsdfi.isRoot() || qdfi.isRoot())
998
                    goto no_cache;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
999
                sdir = qsdfi.path();
1000
                dir = qdfi.path();
1001
            }
1002
1003
        } else {
            m_buildRoot = QFileInfo(cachefile).path();
1004
        }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1005
        m_conffile = conffile;
1006
        m_cachefile = cachefile;
1007
    }
1008
  no_cache:
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030

    // 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();
    }

1031
    return true;
1032
1033
}

1034
bool QMakeEvaluator::loadSpec()
1035
{
1036
1037
    QString qmakespec = m_option->expandEnvVars(
                m_hostBuild ? m_option->qmakespec : m_option->xqmakespec);
1038
1039
1040

    {
        QMakeEvaluator evaluator(m_option, m_parser, m_handler);
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1041
        if (!m_superfile.isEmpty()) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1042
            valuesRef(ProKey("_QMAKE_SUPER_CACHE_")) << ProString(m_superfile);
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1043
1044
1045
            if (!evaluator.evaluateFileDirect(m_superfile, QMakeHandler::EvalConfigFile, LoadProOnly))
                return false;
        }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1046
        if (!m_conffile.isEmpty()) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1047
            valuesRef(ProKey("_QMAKE_CONF_")) << ProString(m_conffile);
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1048
1049
1050
            if (!evaluator.evaluateFileDirect(m_conffile, QMakeHandler::EvalConfigFile, LoadProOnly))
                return false;
        }
1051
        if (!m_cachefile.isEmpty()) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1052
            valuesRef(ProKey("_QMAKE_CACHE_")) << ProString(m_cachefile);
1053
1054
1055
            if (!evaluator.evaluateFileDirect(m_cachefile, QMakeHandler::EvalConfigFile, LoadProOnly))
                return false;
        }
1056
1057
        if (qmakespec.isEmpty()) {
            if (!m_hostBuild)
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1058
                qmakespec = evaluator.first(ProKey("XQMAKESPEC")).toQString();
1059
            if (qmakespec.isEmpty())
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1060
                qmakespec = evaluator.first(ProKey("QMAKESPEC")).toQString();
1061
        }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1062
1063
        m_qmakepath = evaluator.values(ProKey("QMAKEPATH")).toQStringList();
        m_qmakefeatures = evaluator.values(ProKey("QMAKEFEATURES")).toQStringList();
1064
1065
    }

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1066
    updateMkspecPaths();
1067
    if (qmakespec.isEmpty())
1068
        qmakespec = m_hostBuild ? QLatin1String("default-host") : QLatin1String("default");
1069
    if (IoUtils::isRelativePath(qmakespec)) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1070
        foreach (const QString &root, m_mkspecPaths) {
1071
1072
1073
1074
1075
1076
            QString mkspec = root + QLatin1Char('/') + qmakespec;
            if (IoUtils::exists(mkspec)) {
                qmakespec = mkspec;
                goto cool;
            }
        }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1077
        evalError(fL1S("Could not find qmake configuration file %1.").arg(qmakespec));
1078
        return false;
1079
1080
    }
  cool:
1081
    m_qmakespec = QDir::cleanPath(qmakespec);
1082

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1083
1084
1085
1086
    if (!m_superfile.isEmpty()
        && !evaluateFileDirect(m_superfile, QMakeHandler::EvalConfigFile, LoadProOnly)) {
        return false;
    }
1087
1088
    if (!evaluateFeatureFile(QLatin1String("spec_pre.prf")))
        return false;
1089
    QString spec = m_qmakespec + QLatin1String("/qmake.conf");
1090
    if (!evaluateFileDirect(spec, QMakeHandler::EvalConfigFile, LoadProOnly)) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1091
        evalError(fL1S("Could not read qmake configuration file %1.").arg(spec));
1092
        return false;
1093
1094
    }
#ifdef Q_OS_UNIX
1095
    m_qmakespecFull = QFileInfo(m_qmakespec).canonicalFilePath();
1096
#else
1097
1098
1099
    // 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.
1100
    const ProString &orig_spec = first(ProKey("QMAKESPEC_ORIGINAL"));
1101
    m_qmakespecFull = orig_spec.isEmpty() ? m_qmakespec : orig_spec.toQString();
1102
#endif
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1103
    valuesRef(ProKey("QMAKESPEC")) << ProString(m_qmakespecFull);
1104
    m_qmakespecName = IoUtils::fileName(m_qmakespecFull).toString();
1105
1106
    if (!evaluateFeatureFile(QLatin1String("spec_post.prf")))
        return false;
1107
    updateFeaturePaths(); // The spec extends the feature search path, so rebuild the cache.
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1108
1109
1110
1111
    if (!m_conffile.isEmpty()
        && !evaluateFileDirect(m_conffile, QMakeHandler::EvalConfigFile, LoadProOnly)) {
        return false;
    }
1112
1113
    if (!m_cachefile.isEmpty()
        && !evaluateFileDirect(m_cachefile, QMakeHandler::EvalConfigFile, LoadProOnly)) {
1114
1115
1116
        return false;
    }
    return true;
1117
1118
}

1119
1120
1121
void QMakeEvaluator::setupProject()
{
    setTemplate();
1122
    ProValueMap &vars = m_valuemapStack.top();
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1123
1124
1125
1126
    vars[ProKey("TARGET")] << ProString(QFileInfo(currentFileName()).baseName());
    vars[ProKey("_PRO_FILE_")] << ProString(currentFileName());
    vars[ProKey("_PRO_FILE_PWD_")] << ProString(currentDirectory());
    vars[ProKey("OUT_PWD")] << ProString(m_outputDir);
1127
1128
}

1129
1130
1131
1132
void QMakeEvaluator::visitCmdLine(const QString &cmds)
{
    if (!cmds.isEmpty()) {
        if (ProFile *pro = m_parser->parsedProBlock(fL1S("(command line)"), cmds)) {
1133
1134
1135
1136
1137
            if (pro->isOk()) {
                m_locationStack.push(m_current);
                visitProBlock(pro, pro->tokPtr());
                m_current = m_locationStack.pop();
            }
1138
1139
1140
1141
1142
1143
            pro->deref();
        }
    }
}

QMakeEvaluator::VisitReturn QMakeEvaluator::visitProFile(
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1144
        ProFile *pro, QMakeHandler::EvalFileType type, LoadFlags flags)
1145
1146
1147
1148
{
    if (!m_cumulative && !pro->isOk())
        return ReturnFalse;

1149
    if (flags & LoadPreFiles) {
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1150
        if (!prepareProject(pro->directoryName()))
1151
1152
            return ReturnFalse;

1153
1154
        m_hostBuild = pro->isHostBuild();

1155
1156
1157
#ifdef PROEVALUATOR_THREAD_SAFE
        m_option->mutex.lock();
#endif
1158
        QMakeBaseEnv **baseEnvPtr = &m_option->baseEnvs[QMakeBaseKey(m_buildRoot, m_hostBuild)];
1159
1160
1161
1162
        if (!*baseEnvPtr)
            *baseEnvPtr = new QMakeBaseEnv;
        QMakeBaseEnv *baseEnv = *baseEnvPtr;

1163
1164
#ifdef PROEVALUATOR_THREAD_SAFE
        {
1165
1166
1167
            QMutexLocker locker(&baseEnv->mutex);
            m_option->mutex.unlock();
            if (baseEnv->inProgress) {
1168
                QThreadPool::globalInstance()->releaseThread();
1169
                baseEnv->cond.wait(&baseEnv->mutex);
1170
                QThreadPool::globalInstance()->reserveThread();
1171
                if (!baseEnv->isOk)
1172
                    return ReturnFalse;
1173
1174
            } else
#endif
1175
            if (!baseEnv->evaluator) {
1176
#ifdef PROEVALUATOR_THREAD_SAFE
1177
                baseEnv->inProgress = true;
1178
1179
1180
                locker.unlock();
#endif

1181
1182
                QMakeEvaluator *baseEval = new QMakeEvaluator(m_option, m_parser, m_handler);
                baseEnv->evaluator = baseEval;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1183
                baseEval->m_superfile = m_superfile;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1184
                baseEval->m_conffile = m_conffile;
1185
                baseEval->m_cachefile = m_cachefile;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1186
                baseEval->m_sourceRoot = m_sourceRoot;
1187
                baseEval->m_buildRoot = m_buildRoot;
1188
                baseEval->m_hostBuild = m_hostBuild;
1189
                bool ok = baseEval->loadSpec();
1190
1191
1192

#ifdef PROEVALUATOR_THREAD_SAFE
                locker.relock();
1193
1194
1195
                baseEnv->isOk = ok;
                baseEnv->inProgress = false;
                baseEnv->cond.wakeAll();
1196
#endif
1197
1198
1199

                if (!ok)
                    return ReturnFalse;
1200
1201
1202
1203
1204
            }
#ifdef PROEVALUATOR_THREAD_SAFE
        }
#endif

1205
        initFrom(*baseEnv->evaluator);
1206
    } else {
1207
        if (!m_valuemapInited)
1208
            loadDefaults();
1209
1210
1211
1212
    }

    m_handler->aboutToEval(currentProFile(), pro, type);
    m_profileStack.push(pro);
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1213
    valuesRef(ProKey("PWD")) = ProStringList(ProString(currentDirectory()));
1214
    if (flags & LoadPreFiles) {
1215
1216
        setupProject();

1217
1218
1219
1220
1221
1222
1223
        evaluateFeatureFile(QLatin1String("default_pre.prf"));

        visitCmdLine(m_option->precmds);
    }

    visitProBlock(pro, pro->tokPtr());

1224
    if (flags & LoadPostFiles) {
1225
1226
1227
1228
1229
1230
1231
        visitCmdLine(m_option->postcmds);

        evaluateFeatureFile(QLatin1String("default_post.prf"));

        QSet<QString> processed;
        forever {
            bool finished = true;
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1232
            ProStringList configs = values(statics.strCONFIG);
1233
1234
1235
1236
1237
            for (int i = configs.size() - 1; i >= 0; --i) {
                QString config = configs.at(i).toQString(m_tmp1).toLower();
                if (!processed.contains(config)) {
                    config.detach();
                    processed.insert(config);
1238
                    if (evaluateFeatureFile(config, true)) {
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
                        finished = false;
                        break;
                    }
                }
            }
            if (finished)
                break;
        }
    }
    m_profileStack.pop();
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1249
    valuesRef(ProKey("PWD")) = ProStringList(ProString(currentDirectory()));
1250
1251
1252
1253
1254
1255
    m_handler->doneWithEval(currentProFile());

    return ReturnTrue;
}


Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1256
void QMakeEvaluator::updateMkspecPaths()
1257
1258
1259
1260
{
    QStringList ret;
    const QString concat = QLatin1String("/mkspecs");

1261
1262
    foreach (const QString &it, m_option->getPathListEnv(QLatin1String("QMAKEPATH")))
        ret << it + concat;
1263

1264
1265
1266
    foreach (const QString &it, m_qmakepath)
        ret << it + concat;

1267
1268
1269
1270
    if (!m_buildRoot.isEmpty())
        ret << m_buildRoot + concat;
    if (!m_sourceRoot.isEmpty())
        ret << m_sourceRoot + concat;
1271

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1272
    ret << m_option->propertyValue(ProKey("QT_HOST_DATA/get")) + concat;
1273
1274

    ret.removeDuplicates();
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1275
    m_mkspecPaths = ret;
1276
1277
}

1278
void QMakeEvaluator::updateFeaturePaths()
1279
1280
{
    QString mkspecs_concat = QLatin1String("/mkspecs");
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1281
    QString features_concat = QLatin1String("/features/");
1282
1283
1284

    QStringList feature_roots;

1285
    foreach (const QString &f, m_option->getPathListEnv(QLatin1String("QMAKEFEATURES")))
1286
        feature_roots += f;
1287

1288
1289
    feature_roots += m_qmakefeatures;

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1290
    feature_roots += m_option->propertyValue(ProKey("QMAKEFEATURES")).toQString(m_mtmp).split(