toolchain.cpp 17.8 KB
Newer Older
1
2
3
4
5
6
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
hjk's avatar
hjk committed
26
** contact the sales department at http://qt.nokia.com/contact.
27
28
29
**
**************************************************************************/

dt's avatar
dt committed
30
#include "toolchain.h"
31
#include "project.h"
dt's avatar
dt committed
32
#include "cesdkhandler.h"
33
#include "projectexplorersettings.h"
Tobias Hunger's avatar
Tobias Hunger committed
34
35
#include "gccparser.h"
#include "msvcparser.h"
36

Tobias Hunger's avatar
Tobias Hunger committed
37
#include <QtCore/QDebug>
dt's avatar
dt committed
38
39
40
41
42
43
#include <QtCore/QFileInfo>
#include <QtCore/QProcess>
#include <QtCore/QSettings>
#include <QtCore/QDir>
#include <QtCore/QTemporaryFile>
#include <QtCore/QString>
44
#include <QtCore/QCoreApplication>
dt's avatar
dt committed
45
46
47
48

using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal;

49
50
51
#ifdef Q_OS_WIN64
static const char * MSVC_RegKey = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7";
#else
dt's avatar
dt committed
52
static const char * MSVC_RegKey = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VC7";
53
54
#endif

dt's avatar
dt committed
55
56
57
58
59
60
61
bool ToolChain::equals(ToolChain *a, ToolChain *b)
{
    if (a == b)
        return true;
    if (a == 0 || b == 0)
        return false;
    if (a->type() == b->type())
62
        return a->equals(b);
dt's avatar
dt committed
63
    return false;
dt's avatar
dt committed
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
}

ToolChain::ToolChain()
{
}

ToolChain::~ToolChain()
{
}

ToolChain *ToolChain::createGccToolChain(const QString &gcc)
{
    return new GccToolChain(gcc);
}

ToolChain *ToolChain::createMinGWToolChain(const QString &gcc, const QString &mingwPath)
{
    return new MinGWToolChain(gcc, mingwPath);
}

84
ToolChain *ToolChain::createMSVCToolChain(const QString &name, bool amd64 = false)
dt's avatar
dt committed
85
{
86
    return new MSVCToolChain(name, amd64);
dt's avatar
dt committed
87
88
89
90
91
92
93
94
95
}

ToolChain *ToolChain::createWinCEToolChain(const QString &name, const QString &platform)
{
    return new WinCEToolChain(name, platform);
}

QStringList ToolChain::availableMSVCVersions()
{
96
    QSettings registry(MSVC_RegKey, QSettings::NativeFormat);
dt's avatar
dt committed
97
98
99
100
    QStringList versions = registry.allKeys();
    return versions;
}

101
QList<ToolChain::ToolChainType> ToolChain::supportedToolChains()
102
{
103
104
105
106
107
    QList<ToolChain::ToolChainType> toolChains;
    for (int i = 0; i < LAST_VALID; ++i) {
        toolChains.append(ToolChainType(i));
    }
    return toolChains;
108
109
}

110
111
112
113
QString ToolChain::toolChainName(ToolChainType tc)
{
    switch (tc) {
    case GCC:
114
        return QCoreApplication::translate("ToolChain", "GCC");
115
116
//    case LinuxICC:
//        return QCoreApplication::translate("ToolChain", "Intel C++ Compiler (Linux)");
117
    case MinGW:
118
        return QString::fromLatin1("MinGW");
119
    case MSVC:
120
        return QCoreApplication::translate("ToolChain", "Microsoft Visual C++");
121
    case WINCE:
122
        return QCoreApplication::translate("ToolChain", "Windows CE");
123
124
125
126
    case WINSCW:
        return QCoreApplication::translate("ToolChain", "WINSCW");
    case GCCE:
        return QCoreApplication::translate("ToolChain", "GCCE");
127
128
129
130
    case GCCE_GNUPOC:
        return QCoreApplication::translate("ToolChain", "GCCE/GnuPoc");
    case RVCT_ARMV6_GNUPOC:
        return QCoreApplication::translate("ToolChain", "RVCT (ARMV6)/GnuPoc");
131
132
133
134
    case RVCT_ARMV5:
        return QCoreApplication::translate("ToolChain", "RVCT (ARMV5)");
    case RVCT_ARMV6:
        return QCoreApplication::translate("ToolChain", "RVCT (ARMV6)");
ck's avatar
ck committed
135
136
    case GCC_MAEMO:
        return QCoreApplication::translate("ToolChain", "GCC for Maemo");
137
138
139
140
141
142
    case OTHER:
        return QCoreApplication::translate("ToolChain", "Other");
    case INVALID:
        return QCoreApplication::translate("ToolChain", "<Invalid>");
    case UNKNOWN:
        break;
143
    default:
144
        Q_ASSERT("Missing name for Toolchaintype");
145
146
147
148
    };
    return QCoreApplication::translate("ToolChain", "<Unknown>");
}

dt's avatar
dt committed
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
GccToolChain::GccToolChain(const QString &gcc)
    : m_gcc(gcc)
{

}

ToolChain::ToolChainType GccToolChain::type() const
{
    return ToolChain::GCC;
}

QByteArray GccToolChain::predefinedMacros()
{
    if (m_predefinedMacros.isEmpty()) {
        QStringList arguments;
        arguments << QLatin1String("-xc++")
                  << QLatin1String("-E")
                  << QLatin1String("-dM")
                  << QLatin1String("-");

        QProcess cpp;
170
171
172
        ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment();
        addToEnvironment(env);
        cpp.setEnvironment(env.toStringList());
dt's avatar
dt committed
173
174
175
176
        cpp.start(m_gcc, arguments);
        cpp.closeWriteChannel();
        cpp.waitForFinished();
        m_predefinedMacros = cpp.readAllStandardOutput();
177
178

#ifdef Q_OS_MAC
179
        // Turn off flag indicating Apple's blocks support
180
181
        int idx = m_predefinedMacros.indexOf("#define __BLOCKS__ 1");
        if (idx != -1) {
Roberto Raggi's avatar
Roberto Raggi committed
182
            idx = m_predefinedMacros.indexOf('1', idx);
183
            m_predefinedMacros[idx] = '0';
Roberto Raggi's avatar
Roberto Raggi committed
184
        }
185
186

        // Define __strong and __weak (used for Apple's GC extension of C) to be empty
Erik Verbruggen's avatar
Erik Verbruggen committed
187
188
        m_predefinedMacros.append("#define __strong\n");
        m_predefinedMacros.append("#define __weak\n");
189
#endif // Q_OS_MAC
dt's avatar
dt committed
190
191
192
193
194
195
196
197
198
199
200
201
202
203
    }
    return m_predefinedMacros;
}

QList<HeaderPath> GccToolChain::systemHeaderPaths()
{
    if (m_systemHeaderPaths.isEmpty()) {
        QStringList arguments;
        arguments << QLatin1String("-xc++")
                  << QLatin1String("-E")
                  << QLatin1String("-v")
                  << QLatin1String("-");

        QProcess cpp;
204
205
        ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment();
        addToEnvironment(env);
206
        env.set(QLatin1String("LC_ALL"), QLatin1String("C"));   //override current locale settings
207
        cpp.setEnvironment(env.toStringList());
dt's avatar
dt committed
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
        cpp.setReadChannelMode(QProcess::MergedChannels);
        cpp.start(m_gcc, arguments);
        cpp.closeWriteChannel();
        cpp.waitForFinished();

        QByteArray line;
        while (cpp.canReadLine()) {
            line = cpp.readLine();
            if (line.startsWith("#include"))
                break;
        }

        if (! line.isEmpty() && line.startsWith("#include")) {
            HeaderPath::Kind kind = HeaderPath::UserHeaderPath;
            while (cpp.canReadLine()) {
                line = cpp.readLine();
                if (line.startsWith("#include")) {
                    kind = HeaderPath::GlobalHeaderPath;
                } else if (! line.isEmpty() && QChar(line.at(0)).isSpace()) {
                    HeaderPath::Kind thisHeaderKind = kind;

                    line = line.trimmed();
                    if (line.endsWith('\n'))
                        line.chop(1);

                    int index = line.indexOf(" (framework directory)");
                    if (index != -1) {
                        line = line.left(index);
                        thisHeaderKind = HeaderPath::FrameworkHeaderPath;
                    }

                    m_systemHeaderPaths.append(HeaderPath(QFile::decodeName(line), thisHeaderKind));
                } else if (line.startsWith("End of search list.")) {
                    break;
                } else {
                    qWarning() << "ignore line:" << line;
                }
            }
        }
    }
    return m_systemHeaderPaths;
}

void GccToolChain::addToEnvironment(ProjectExplorer::Environment &env)
{
    Q_UNUSED(env)
}

256
257
QString GccToolChain::makeCommand() const
{
Tobias Hunger's avatar
Tobias Hunger committed
258
259
260
261
262
263
    return QLatin1String("make");
}

IOutputParser *GccToolChain::outputParser() const
{
    return new GccParser;
264
265
}

dt's avatar
dt committed
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
bool GccToolChain::equals(ToolChain *other) const
{
    return (m_gcc == static_cast<GccToolChain *>(other)->m_gcc);
}

MinGWToolChain::MinGWToolChain(const QString &gcc, const QString &mingwPath)
    : GccToolChain(gcc), m_mingwPath(mingwPath)
{

}

ToolChain::ToolChainType MinGWToolChain::type() const
{
    return ToolChain::MinGW;
}

bool MinGWToolChain::equals(ToolChain *other) const
{
    MinGWToolChain *o = static_cast<MinGWToolChain *>(other);
    return (m_mingwPath == o->m_mingwPath && this->GccToolChain::equals(other));
}

void MinGWToolChain::addToEnvironment(ProjectExplorer::Environment &env)
{
290
291
    if (m_mingwPath.isEmpty())
        return;
dt's avatar
dt committed
292
293
294
295
296
    QString binDir = m_mingwPath + "/bin";
    if (QFileInfo(binDir).exists())
        env.prependOrSetPath(binDir);
}

297
298
QString MinGWToolChain::makeCommand() const
{
Tobias Hunger's avatar
Tobias Hunger committed
299
    return QLatin1String("mingw32-make.exe");
300
301
}

Tobias Hunger's avatar
Tobias Hunger committed
302
303
304
305
IOutputParser *MinGWToolChain::outputParser() const
{
    return new GccParser;
}
dt's avatar
dt committed
306

307
308
MSVCToolChain::MSVCToolChain(const QString &name, bool amd64)
    : m_name(name), m_valuesSet(false), m_amd64(amd64)
dt's avatar
dt committed
309
{
310
    if (m_name.isEmpty()) { // Could be because system qt doesn't set this
311
        QSettings registry(MSVC_RegKey, QSettings::NativeFormat);
312
313
314
        QStringList keys = registry.allKeys();
        if (keys.count())
            m_name = keys.first();
315
    }
dt's avatar
dt committed
316
317
318
319
320
321
322
323
324
325
326
327
328
}

ToolChain::ToolChainType MSVCToolChain::type() const
{
    return ToolChain::MSVC;
}

bool MSVCToolChain::equals(ToolChain *other) const
{
    MSVCToolChain *o = static_cast<MSVCToolChain *>(other);
    return (m_name == o->m_name);
}

329
330
331
332
333
334
335
336
337
338
QByteArray msvcCompilationFile() {
    static const char* macros[] = {"_ATL_VER", "_CHAR_UNSIGNED", "__CLR_VER",
                                   "__cplusplus_cli", "__COUNTER__", "__cplusplus",
                                   "_CPPLIB_VER", "_CPPRTTI", "_CPPUNWIND",
                                   "_DEBUG", "_DLL", "__FUNCDNAME__",
                                   "__FUNCSIG__","__FUNCTION__","_INTEGRAL_MAX_BITS",
                                   "_M_ALPHA","_M_CEE","_M_CEE_PURE",
                                   "_M_CEE_SAFE","_M_IX86","_M_IA64",
                                   "_M_IX86_FP","_M_MPPC","_M_MRX000",
                                   "_M_PPC","_M_X64","_MANAGED",
339
                                   "_MFC_VER","_MSC_BUILD", /* "_MSC_EXTENSIONS", */
340
341
342
                                   "_MSC_FULL_VER","_MSC_VER","__MSVC_RUNTIME_CHECKS",
                                   "_MT", "_NATIVE_WCHAR_T_DEFINED", "_OPENMP",
                                   "_VC_NODEFAULTLIB", "_WCHAR_T_DEFINED", "_WIN32",
343
344
                                   "_WIN32_WCE", "_WIN64", "_Wp64", "__DATE__",
                                    "__DATE__", "__TIME__", "__TIMESTAMP__",
345
346
347
348
349
350
351
352
353
354
355
356
357
                                   0};
    QByteArray file = "#define __PPOUT__(x) V##x=x\n\n";
    int i =0;
    while (macros[i] != 0) {
        const QByteArray macro(macros[i]);
        file += "#if defined(" + macro + ")\n__PPOUT__("
                + macro + ")\n#endif\n";
        ++i;
    }
    file += "\nvoid main(){}\n\n";
    return file;
}

dt's avatar
dt committed
358
359
QByteArray MSVCToolChain::predefinedMacros()
{
360
361
    if (m_predefinedMacros.isEmpty()) {
        m_predefinedMacros += "#define __MSVCRT__\n"
362
                              "#define __w64\n"
363
364
365
366
367
368
                              "#define __int64 long long\n"
                              "#define __int32 long\n"
                              "#define __int16 short\n"
                              "#define __int8 char\n"
                              "#define __ptr32\n"
                              "#define __ptr64\n";
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

        QString tmpFilePath;
        {
            // QTemporaryFile is buggy and will not unlock the file for cl.exe
            QTemporaryFile tmpFile(QDir::tempPath()+"/envtestXXXXXX.cpp");
            tmpFile.setAutoRemove(false);
            if (!tmpFile.open())
                return m_predefinedMacros;
            tmpFilePath = QFileInfo(tmpFile).canonicalFilePath();
            tmpFile.write(msvcCompilationFile());
            tmpFile.close();
        }
        ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment();
        addToEnvironment(env);
        QProcess cpp;
        cpp.setEnvironment(env.toStringList());
        cpp.setWorkingDirectory(QDir::tempPath());
        QStringList arguments;
        arguments << "/EP" << QDir::toNativeSeparators(tmpFilePath);
        cpp.start(QLatin1String("cl.exe"), arguments);
        cpp.closeWriteChannel();
        cpp.waitForFinished();
        QList<QByteArray> output = cpp.readAllStandardOutput().split('\n');
        foreach (const QByteArray& line, output) {
            if (line.startsWith('V')) {
                QList<QByteArray> split = line.split('=');
                QByteArray key = split.at(0).mid(1);
                QByteArray value = split.at(1);
                if (!value.isEmpty()) {
398
                    value.chop(1); //remove '\n'
399
                }
400
                QByteArray newDefine = "#define " + key + ' ' + value + '\n';
401
                m_predefinedMacros.append(newDefine);
402
            }
403
404
405
406
        }
        QFile::remove(tmpFilePath);
    }
    return m_predefinedMacros;
dt's avatar
dt committed
407
408
409
410
411
412
413
}

QList<HeaderPath> MSVCToolChain::systemHeaderPaths()
{
    //TODO fix this code
    ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment();
    addToEnvironment(env);
414
415
416
417
418
    QList<HeaderPath> headerPaths;
    foreach(const QString &path, env.value("INCLUDE").split(QLatin1Char(';'))) {
        headerPaths.append(HeaderPath(path, HeaderPath::GlobalHeaderPath));
    }
    return headerPaths;
dt's avatar
dt committed
419
420
421
422
}

void MSVCToolChain::addToEnvironment(ProjectExplorer::Environment &env)
{
423
424
    if (!m_valuesSet || env != m_lastEnvironment) {
        m_lastEnvironment = env;
425
        QSettings registry(MSVC_RegKey, QSettings::NativeFormat);
426
427
        if (m_name.isEmpty())
            return;
dt's avatar
dt committed
428
429
        QString path = registry.value(m_name).toString();
        QString desc;
430
431
        QString varsbat;
        if (m_amd64)
con's avatar
con committed
432
            varsbat = path + "bin\\amd64\\vcvarsamd64.bat";
433
        else
con's avatar
con committed
434
            varsbat = path + "bin\\vcvars32.bat";
dt's avatar
dt committed
435
436
437
438
439
440
441
442
443
444
        if (QFileInfo(varsbat).exists()) {
            QTemporaryFile tf(QDir::tempPath() + "\\XXXXXX.bat");
            if (!tf.open())
                return;
            QString filename = tf.fileName();
            tf.write("call \"" + varsbat.toLocal8Bit()+"\"\r\n");
            tf.write(("set > \"" + QDir::tempPath() + "\\qtcreator-msvc-environment.txt\"\r\n").toLocal8Bit());
            tf.flush();
            tf.waitForBytesWritten(30000);

445
446
            QProcess run;
            run.setEnvironment(env.toStringList());
dt's avatar
dt committed
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
            QString cmdPath = env.searchInPath("cmd");
            run.start(cmdPath, QStringList()<<"/c"<<filename);
            run.waitForFinished();
            tf.close();

            QFile vars(QDir::tempPath() + "\\qtcreator-msvc-environment.txt");
            if (vars.exists() && vars.open(QIODevice::ReadOnly)) {
                while (!vars.atEnd()) {
                    QByteArray line = vars.readLine();
                    QString line2 = QString::fromLocal8Bit(line);
                    line2 = line2.trimmed();
                    QRegExp regexp("(\\w*)=(.*)");
                    if (regexp.exactMatch(line2)) {
                        QString variable = regexp.cap(1);
                        QString value = regexp.cap(2);
                        m_values.append(QPair<QString, QString>(variable, value));
                    }
                }
                vars.close();
                vars.remove();
            }
        }
        m_valuesSet = true;
    }

    QList< QPair<QString, QString> >::const_iterator it, end;
    end = m_values.constEnd();
    for (it = m_values.constBegin(); it != end; ++it) {
        env.set((*it).first, (*it).second);
    }
}

479
480
QString MSVCToolChain::makeCommand() const
{
481
482
483
484
485
486
    if (ProjectExplorerPlugin::instance()->projectExplorerSettings().useJom) {
        // We want jom! Try to find it.
        QString jom = QCoreApplication::applicationDirPath() + QLatin1String("/jom.exe");
        if (QFileInfo(jom).exists())
            return jom;
        else
Tobias Hunger's avatar
Tobias Hunger committed
487
            return QLatin1String("jom.exe");
488
    }
Tobias Hunger's avatar
Tobias Hunger committed
489
490
491
492
493
494
    return QLatin1String("nmake.exe");
}

IOutputParser *MSVCToolChain::outputParser() const
{
    return new MsvcParser;
495
496
}

dt's avatar
dt committed
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
WinCEToolChain::WinCEToolChain(const QString &name, const QString &platform)
    : MSVCToolChain(name), m_platform(platform)
{

}

ToolChain::ToolChainType WinCEToolChain::type() const
{
    return ToolChain::WINCE;
}

bool WinCEToolChain::equals(ToolChain *other) const
{
    WinCEToolChain *o = static_cast<WinCEToolChain *>(other);
    return (m_platform == o->m_platform && this->MSVCToolChain::equals(other));
}

QByteArray WinCEToolChain::predefinedMacros()
{
    //TODO
    return MSVCToolChain::predefinedMacros();
}

QList<HeaderPath> WinCEToolChain::systemHeaderPaths()
{
    //TODO fix this code
    ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment();
    addToEnvironment(env);
Roberto Raggi's avatar
Compile    
Roberto Raggi committed
525
526
527
528
529
530
531
532
533
534
535

    QList<HeaderPath> headerPaths;

    const QStringList includes = env.value("INCLUDE").split(QLatin1Char(';'));

    foreach (const QString &path, includes) {
        const HeaderPath headerPath(path, HeaderPath::GlobalHeaderPath);
        headerPaths.append(headerPath);
    }

    return headerPaths;
dt's avatar
dt committed
536
537
538
539
540
}

void WinCEToolChain::addToEnvironment(ProjectExplorer::Environment &env)
{
    MSVCToolChain::addToEnvironment(env);
541
    QSettings registry(MSVC_RegKey, QSettings::NativeFormat);
dt's avatar
dt committed
542
    QString path = registry.value(m_name).toString();
543

dt's avatar
dt committed
544
545
    // Find MSVC path

546
    path += QLatin1Char('/');
dt's avatar
dt committed
547
548
549
550
551
552

    // Find Platform name
    CeSdkHandler cesdkhandler;
    cesdkhandler.parse(path);
    cesdkhandler.find(m_platform).addToEnvironment(env);
}