OSDN Git Service

It's 2011 now.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / projectexplorer / toolchain.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "toolchain.h"
35 #include "project.h"
36 #include "cesdkhandler.h"
37 #include "projectexplorersettings.h"
38 #include "gccparser.h"
39 #include "msvcparser.h"
40 #include "linuxiccparser.h"
41
42 #include <utils/synchronousprocess.h>
43 #include <utils/qtcprocess.h>
44
45 #include <QtCore/QDebug>
46 #include <QtCore/QFileInfo>
47 #include <QtCore/QProcess>
48 #include <QtCore/QSettings>
49 #include <QtCore/QDir>
50 #include <QtCore/QTemporaryFile>
51 #include <QtCore/QString>
52 #include <QtCore/QCoreApplication>
53
54 using namespace ProjectExplorer;
55 using namespace ProjectExplorer::Internal;
56
57 enum { debug = 0 };
58
59 #ifdef Q_OS_WIN64
60 static const char MSVC_RegKey[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7";
61 #else
62 static const char MSVC_RegKey[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VC7";
63 #endif
64
65 bool ToolChain::equals(const ToolChain *a, const ToolChain *b)
66 {
67     if (a == b)
68         return true;
69     if (a == 0 || b == 0)
70         return false;
71     if (a->type() == b->type())
72         return a->equals(b);
73     return false;
74 }
75
76 ToolChain::ToolChain()
77 {
78 }
79
80 ToolChain::~ToolChain()
81 {
82 }
83
84 ToolChain *ToolChain::createGccToolChain(const QString &gcc)
85 {
86     return new GccToolChain(gcc);
87 }
88
89 ToolChain *ToolChain::createMinGWToolChain(const QString &gcc, const QString &mingwPath)
90 {
91     return new MinGWToolChain(gcc, mingwPath);
92 }
93
94 ToolChain *ToolChain::createLinuxIccToolChain()
95 {
96     return new LinuxIccToolChain();
97 }
98
99 ToolChain *ToolChain::createMSVCToolChain(const QString &name, bool amd64)
100 {
101     return MSVCToolChain::create(name, amd64);
102 }
103
104 ToolChain *ToolChain::createWinCEToolChain(const QString &name, const QString &platform)
105 {
106     return WinCEToolChain::create(name, platform);
107 }
108
109 QStringList ToolChain::availableMSVCVersions()
110 {
111     QStringList rc;
112     foreach(const MSVCToolChain::Installation &i, MSVCToolChain::installations())
113         rc.push_back(i.name);
114     return rc;
115 }
116
117 QStringList ToolChain::availableMSVCVersions(bool amd64)
118 {
119     QStringList rc;
120     foreach(const MSVCToolChain::Installation &i, MSVCToolChain::installations())
121         if (i.is64bit() == amd64)
122             rc.push_back(i.name);
123     return rc;
124 }
125
126 QList<ToolChainType> ToolChain::supportedToolChains()
127 {
128     QList<ToolChainType> toolChains;
129     for (int i = 0; i < ToolChain_LAST_VALID; ++i) {
130         toolChains.append(ToolChainType(i));
131     }
132     return toolChains;
133 }
134
135 QString ToolChain::toolChainName(ToolChainType tc)
136 {
137     switch (tc) {
138     case ToolChain_GCC:
139         return QCoreApplication::translate("ToolChain", "GCC");
140     case ToolChain_LINUX_ICC:
141         return QCoreApplication::translate("ToolChain", "Intel C++ Compiler (Linux)");
142     case ToolChain_MinGW:
143         return QString::fromLatin1("MinGW");
144     case ToolChain_MSVC:
145         return QCoreApplication::translate("ToolChain", "Microsoft Visual C++");
146     case ToolChain_WINCE:
147         return QCoreApplication::translate("ToolChain", "Windows CE");
148     case ToolChain_WINSCW:
149         return QCoreApplication::translate("ToolChain", "WINSCW");
150     case ToolChain_GCCE:
151         return QCoreApplication::translate("ToolChain", "GCCE");
152     case ToolChain_GCCE_GNUPOC:
153         return QCoreApplication::translate("ToolChain", "GCCE/GnuPoc");
154     case ToolChain_RVCT_ARMV5_GNUPOC:
155         return QCoreApplication::translate("ToolChain", "RVCT (ARMV6)/GnuPoc");
156     case ToolChain_RVCT2_ARMV5:
157         return QCoreApplication::translate("ToolChain", "RVCT 2 (ARMV5)");
158     case ToolChain_RVCT2_ARMV6:
159         return QCoreApplication::translate("ToolChain", "RVCT 2 (ARMV6)");
160     case ToolChain_RVCT4_ARMV5:
161         return QCoreApplication::translate("ToolChain", "RVCT 4 (ARMV5)");
162     case ToolChain_RVCT4_ARMV6:
163         return QCoreApplication::translate("ToolChain", "RVCT 4 (ARMV6)");
164     case ToolChain_GCC_MAEMO:
165         return QCoreApplication::translate("ToolChain", "GCC for Maemo");
166     case ToolChain_OTHER:
167         return QCoreApplication::translate("ToolChain", "Other");
168     case ToolChain_INVALID:
169         return QCoreApplication::translate("ToolChain", "<Invalid>");
170     case ToolChain_UNKNOWN:
171         break;
172     default:
173         Q_ASSERT("Missing name for Toolchaintype");
174     };
175     return QCoreApplication::translate("ToolChain", "<Unknown>");
176 }
177
178 GccToolChain::GccToolChain(const QString &gcc)
179     : m_gcc(gcc)
180 {
181
182 }
183
184 ToolChainType GccToolChain::type() const
185 {
186     return ToolChain_GCC;
187 }
188
189 static QByteArray gccPredefinedMacros(const QString &gcc, const QStringList &env)
190 {
191     QStringList arguments;
192     arguments << QLatin1String("-xc++")
193               << QLatin1String("-E")
194               << QLatin1String("-dM")
195               << QLatin1String("-");
196
197     QProcess cpp;
198     cpp.setEnvironment(env);
199     cpp.start(gcc, arguments);
200     if (!cpp.waitForStarted()) {
201         qWarning("%s: Cannot start '%s': %s", Q_FUNC_INFO, qPrintable(gcc),
202             qPrintable(cpp.errorString()));
203         return QByteArray();
204     }
205     cpp.closeWriteChannel();
206     if (!cpp.waitForFinished()) {
207         Utils::SynchronousProcess::stopProcess(cpp);
208         qWarning("%s: Timeout running '%s'.", Q_FUNC_INFO, qPrintable(gcc));
209         return QByteArray();
210     }
211     if (cpp.exitStatus() != QProcess::NormalExit) {
212         qWarning("%s: '%s' crashed.", Q_FUNC_INFO, qPrintable(gcc));
213         return QByteArray();
214     }
215     QByteArray predefinedMacros = cpp.readAllStandardOutput();
216 #ifdef Q_OS_MAC
217     // Turn off flag indicating Apple's blocks support
218     const QByteArray blocksDefine("#define __BLOCKS__ 1");
219     const QByteArray blocksUndefine("#undef __BLOCKS__");
220     const int idx = predefinedMacros.indexOf(blocksDefine);
221     if (idx != -1) {
222         predefinedMacros.replace(idx, blocksDefine.length(), blocksUndefine);
223     }
224
225     // Define __strong and __weak (used for Apple's GC extension of C) to be empty
226     predefinedMacros.append("#define __strong\n");
227     predefinedMacros.append("#define __weak\n");
228 #endif // Q_OS_MAC
229     return predefinedMacros;
230 }
231
232 QByteArray GccToolChain::predefinedMacros()
233 {
234     if (m_predefinedMacros.isEmpty()) {
235         Utils::Environment env = Utils::Environment::systemEnvironment();
236         addToEnvironment(env);
237         m_predefinedMacros = gccPredefinedMacros(m_gcc, env.toStringList());
238     }
239     return m_predefinedMacros;
240 }
241
242 static QList<HeaderPath> gccSystemHeaderPaths(const QString &gcc, Utils::Environment env)
243 {
244     QList<HeaderPath> systemHeaderPaths;
245     QStringList arguments;
246     arguments << QLatin1String("-xc++")
247               << QLatin1String("-E")
248               << QLatin1String("-v")
249               << QLatin1String("-");
250
251     QProcess cpp;
252     env.set(QLatin1String("LC_ALL"), QLatin1String("C"));   //override current locale settings
253     cpp.setEnvironment(env.toStringList());
254     cpp.setReadChannelMode(QProcess::MergedChannels);
255     cpp.start(gcc, arguments);
256     if (!cpp.waitForStarted()) {
257         qWarning("%s: Cannot start '%s': %s", Q_FUNC_INFO, qPrintable(gcc),
258             qPrintable(cpp.errorString()));
259         return systemHeaderPaths;
260     }
261     cpp.closeWriteChannel();
262     if (!cpp.waitForFinished()) {
263         Utils::SynchronousProcess::stopProcess(cpp);
264         qWarning("%s: Timeout running '%s'.", Q_FUNC_INFO, qPrintable(gcc));
265         return systemHeaderPaths;
266     }
267     if (cpp.exitStatus() != QProcess::NormalExit) {
268         qWarning("%s: '%s' crashed.", Q_FUNC_INFO, qPrintable(gcc));
269         return systemHeaderPaths;
270     }
271     QByteArray line;
272     while (cpp.canReadLine()) {
273         line = cpp.readLine();
274         if (line.startsWith("#include"))
275             break;
276     }
277
278     if (! line.isEmpty() && line.startsWith("#include")) {
279         HeaderPath::Kind kind = HeaderPath::UserHeaderPath;
280         while (cpp.canReadLine()) {
281             line = cpp.readLine();
282             if (line.startsWith("#include")) {
283                 kind = HeaderPath::GlobalHeaderPath;
284             } else if (! line.isEmpty() && QChar(line.at(0)).isSpace()) {
285                 HeaderPath::Kind thisHeaderKind = kind;
286
287                 line = line.trimmed();
288                 if (line.endsWith('\n'))
289                     line.chop(1);
290
291                 const int index = line.indexOf(" (framework directory)");
292                 if (index != -1) {
293                     line.truncate(index);
294                     thisHeaderKind = HeaderPath::FrameworkHeaderPath;
295                 }
296
297                 systemHeaderPaths.append(HeaderPath(QFile::decodeName(line), thisHeaderKind));
298             } else if (line.startsWith("End of search list.")) {
299                 break;
300             } else {
301                 qWarning() << "ignore line:" << line;
302             }
303         }
304     }
305     return systemHeaderPaths;
306 }
307
308 QList<HeaderPath> GccToolChain::systemHeaderPaths()
309 {
310     if (m_systemHeaderPaths.isEmpty()) {
311         Utils::Environment env = Utils::Environment::systemEnvironment();
312         addToEnvironment(env);
313         m_systemHeaderPaths = gccSystemHeaderPaths(m_gcc, env);
314     }
315     return m_systemHeaderPaths;
316 }
317
318 void GccToolChain::addToEnvironment(Utils::Environment &env)
319 {
320     Q_UNUSED(env)
321 }
322
323 QString GccToolChain::makeCommand() const
324 {
325     return QLatin1String("make");
326 }
327
328 IOutputParser *GccToolChain::outputParser() const
329 {
330     return new GccParser;
331 }
332
333 bool GccToolChain::equals(const ToolChain *other) const
334 {
335     return (m_gcc == static_cast<const GccToolChain *>(other)->m_gcc);
336 }
337
338 MinGWToolChain::MinGWToolChain(const QString &gcc, const QString &mingwPath)
339     : GccToolChain(gcc), m_mingwPath(mingwPath)
340 {
341
342 }
343
344 ToolChainType MinGWToolChain::type() const
345 {
346     return ToolChain_MinGW;
347 }
348
349 bool MinGWToolChain::equals(const ToolChain *other) const
350 {
351     const MinGWToolChain *o = static_cast<const MinGWToolChain *>(other);
352     return (m_mingwPath == o->m_mingwPath && this->GccToolChain::equals(other));
353 }
354
355 void MinGWToolChain::addToEnvironment(Utils::Environment &env)
356 {
357     if (debug)
358         qDebug() << "MinGWToolChain::addToEnvironment" << m_mingwPath;
359     if (m_mingwPath.isEmpty())
360         return;
361     const QString binDir = m_mingwPath + "/bin";
362     if (QFileInfo(binDir).exists())
363         env.prependOrSetPath(binDir);
364 }
365
366 QString MinGWToolChain::makeCommand() const
367 {
368     return QLatin1String("mingw32-make.exe");
369 }
370
371 IOutputParser *MinGWToolChain::outputParser() const
372 {
373     return new GccParser;
374 }
375
376 LinuxIccToolChain::LinuxIccToolChain()
377     : GccToolChain(QLatin1String("icpc"))
378 {
379 }
380
381 ToolChainType LinuxIccToolChain::type() const
382 {
383     return ToolChain_LINUX_ICC;
384 }
385
386 IOutputParser *LinuxIccToolChain::outputParser() const
387 {
388     return new LinuxIccParser;
389 }
390
391 // ---------------- MSVC installation location code
392
393 // Format the name of an SDK or VC installation version with platform
394 static inline QString installationName(const QString &name,
395                                        MSVCToolChain::Installation::Type t,
396                                        MSVCToolChain::Installation::Platform p)
397 {
398     if (t == MSVCToolChain::Installation::WindowsSDK) {
399         QString sdkName = name;
400         sdkName += QLatin1String(" (");
401         sdkName += MSVCToolChain::Installation::platformName(p);
402         sdkName += QLatin1Char(')');
403         return sdkName;
404     }
405     // Comes as "9.0" from the registry
406     QString vcName = QLatin1String("Microsoft Visual C++ Compilers ");
407     vcName += name;
408     vcName+= QLatin1String(" (");
409     vcName += MSVCToolChain::Installation::platformName(p);
410     vcName += QLatin1Char(')');
411     return vcName;
412 }
413
414 MSVCToolChain::Installation::Installation(Type t, const QString &n, Platform p,
415                                           const QString &v, const QString &a) :
416     type(t), name(installationName(n, t, p)), platform(p), varsBat(v), varsBatArg(a)
417 {
418 }
419
420 MSVCToolChain::Installation::Installation() : platform(s32)
421 {
422 }
423
424 QString MSVCToolChain::Installation::platformName(Platform t)
425 {
426     switch (t) {
427     case s32:
428         return QLatin1String("x86");
429     case s64:
430         return QLatin1String("x64");
431     case ia64:
432         return QLatin1String("ia64");
433     case amd64:
434         return QLatin1String("amd64");
435     }
436     return QString();
437 }
438
439 bool MSVCToolChain::Installation::is64bit() const
440 {
441     return platform != s32;
442 }
443
444 MSVCToolChain::InstallationList MSVCToolChain::installations()
445 {
446     static InstallationList installs;
447     static bool firstTime = true;
448     if (firstTime) {
449         firstTime = false;
450         // 1) Installed SDKs preferred over standalone Visual studio
451         const char sdk_RegKeyC[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows";
452         const QSettings sdkRegistry(sdk_RegKeyC, QSettings::NativeFormat);
453         const QString defaultSdkPath = sdkRegistry.value(QLatin1String("CurrentInstallFolder")).toString();
454         if (!defaultSdkPath.isEmpty()) {
455             foreach(const QString &sdkKey, sdkRegistry.childGroups()) {
456                 const QString name = sdkRegistry.value(sdkKey + QLatin1String("/ProductName")).toString();
457                 const QString folder = sdkRegistry.value(sdkKey + QLatin1String("/InstallationFolder")).toString();
458                 if (!folder.isEmpty()) {
459                     const QString sdkVcVarsBat = folder + QLatin1String("bin\\SetEnv.cmd");
460                     if (QFileInfo(sdkVcVarsBat).exists()) {
461                         // Add all platforms
462                         InstallationList newInstalls;
463                         newInstalls.push_back(Installation(Installation::WindowsSDK, name, Installation::s32, sdkVcVarsBat, QLatin1String("/x86")));
464 #ifdef Q_OS_WIN64
465                         newInstalls.push_back(Installation(Installation::WindowsSDK, name, Installation::s64, sdkVcVarsBat, QLatin1String("/x64")));
466                         newInstalls.push_back(Installation(Installation::WindowsSDK, name, Installation::ia64, sdkVcVarsBat, QLatin1String("/ia64")));
467 #endif
468                         // Make sure the default is front.
469                         if (folder == defaultSdkPath && !installs.empty()) {
470                             const InstallationList old = installs;
471                             installs = newInstalls + old;
472                         } else {
473                             installs.append(newInstalls);
474                         }
475                     } // bat exists
476                 } // folder
477             } // foreach
478         }
479         // 2) Installed MSVCs
480         const QSettings vsRegistry(MSVC_RegKey, QSettings::NativeFormat);
481         foreach(const QString &vsName, vsRegistry.allKeys()) {
482             const int dotPos = vsName.indexOf(QLatin1Char('.'));
483             if (dotPos != -1) { // Scan for version major.minor
484                 const QString path = vsRegistry.value(vsName).toString();
485                 const int version = vsName.left(dotPos).toInt();
486                 // Check existence of various install scripts
487                 const QString vcvars32bat = path + QLatin1String("bin\\vcvars32.bat");
488                 if (QFileInfo(vcvars32bat).isFile())
489                     installs.push_back(Installation(Installation::VS, vsName, Installation::s32, vcvars32bat));
490                 if (version >= 10) {
491                     // Just one common file
492                     const QString vcvarsAllbat = path + QLatin1String("vcvarsall.bat");
493                     if (QFileInfo(vcvarsAllbat).isFile()) {
494                         installs.push_back(Installation(Installation::VS, vsName, Installation::s32, vcvarsAllbat, QLatin1String("x86")));
495                         installs.push_back(Installation(Installation::VS, vsName, Installation::amd64, vcvarsAllbat, QLatin1String("amd64")));
496                         installs.push_back(Installation(Installation::VS, vsName, Installation::s64, vcvarsAllbat, QLatin1String("x64")));
497                         installs.push_back(Installation(Installation::VS, vsName, Installation::ia64, vcvarsAllbat, QLatin1String("ia64")));
498                     } else {
499                         qWarning("Unable to find MSVC setup script %s in version %d", qPrintable(vcvarsAllbat), version);
500                     }
501                 } else {
502                     // Amd 64 is the preferred 64bit platform
503                     const QString vcvarsAmd64bat = path + QLatin1String("bin\\amd64\\vcvarsamd64.bat");
504                     if (QFileInfo(vcvarsAmd64bat).isFile())
505                         installs.push_back(Installation(Installation::VS, vsName, Installation::amd64, vcvarsAmd64bat));
506                     const QString vcvarsAmd64bat2 = path + QLatin1String("bin\\vcvarsx86_amd64.bat");
507                     if (QFileInfo(vcvarsAmd64bat2).isFile())
508                         installs.push_back(Installation(Installation::VS, vsName, Installation::amd64, vcvarsAmd64bat2));
509                     const QString vcvars64bat = path + QLatin1String("bin\\vcvars64.bat");
510                     if (QFileInfo(vcvars64bat).isFile())
511                         installs.push_back(Installation(Installation::VS, vsName, Installation::s64, vcvars64bat));
512                     const QString vcvarsIA64bat = path + QLatin1String("bin\\vcvarsx86_ia64.bat");
513                     if (QFileInfo(vcvarsIA64bat).isFile())
514                         installs.push_back(Installation(Installation::VS, vsName, Installation::ia64, vcvarsIA64bat));
515                 }
516             }
517         }
518     }
519     if (debug)
520         foreach(const Installation &i, installs)
521             qDebug() << i;
522     return installs;
523 }
524
525 // Return a substring to match the MSVC official version against by mkSpec name.
526 static inline const QString msvcVersionStringFromMkSpec(const QString &mkSpec)
527 {
528     if (mkSpec.isEmpty())
529         return QString();
530     if (mkSpec.endsWith(QLatin1String("msvc2002")))
531        return QLatin1String(" 7.0");
532     if (mkSpec.endsWith(QLatin1String("msvc2003")))
533        return QLatin1String(" 7.1");
534     if (mkSpec.endsWith(QLatin1String("msvc2005")))
535        return QLatin1String(" 8.0");
536     if (mkSpec.endsWith(QLatin1String("msvc2008")))
537         return QLatin1String(" 9.0");
538     if (mkSpec.endsWith(QLatin1String("msvc2010")))
539         return QLatin1String(" 10.0");
540     return QString();
541 }
542
543 MSVCToolChain::Installation MSVCToolChain::findInstallationByMkSpec(bool is64Bit,
544                                                                     const QString &mkSpec,
545                                                                     bool excludeSDK)
546 {
547     const QString mkSpecMatchString = msvcVersionStringFromMkSpec(mkSpec);
548     if (!mkSpecMatchString.isEmpty()) {
549         foreach(const Installation &i, installations()) {
550             if ((i.type == Installation::VS) && (i.is64bit() == is64Bit)
551                 && (i.name.indexOf(mkSpecMatchString) != -1))
552                     return i;
553         }
554     }
555     return findInstallationByName(is64Bit, QString(), excludeSDK);
556 }
557
558 MSVCToolChain::Installation MSVCToolChain::findInstallationByName(bool is64Bit,
559                                                             const QString &name,
560                                                             bool excludeSDK)
561 {
562     if (debug)
563         qDebug() << "find" << (is64Bit ? 64 : 32) << name << excludeSDK;
564     foreach(const Installation &i, installations()) {
565         if (i.type != Installation::WindowsSDK || !excludeSDK) {
566             if ((i.is64bit() == is64Bit) && (name.isEmpty() || name == i.name))
567                 return i;
568         }
569     }
570     return Installation();
571 }
572
573 namespace ProjectExplorer {
574 PROJECTEXPLORER_EXPORT QDebug operator<<(QDebug in, const MSVCToolChain::Installation &i)
575 {
576     QDebug nsp = in.nospace();
577     nsp << "Type: " << i.type << " Platform: " << i.platform << " Name: " << i.name
578         << "\nSetup: " << i.varsBat;
579     if (!i.varsBatArg.isEmpty())
580         nsp << "\nSetup argument: " << i.varsBatArg;
581     return in;
582 }
583 }
584
585 MSVCToolChain *MSVCToolChain::create(const QString &name, bool amd64)
586 {
587     return new MSVCToolChain(MSVCToolChain::findInstallationByName(amd64, name));
588 }
589
590 MSVCToolChain::MSVCToolChain(const Installation &in) :
591     m_installation(in),
592     m_valuesSet(false)
593 {
594     if (debug)
595         qDebug() << "\nMSVCToolChain::CT\n" << m_installation;
596 }
597
598 ToolChainType MSVCToolChain::type() const
599 {
600     return ToolChain_MSVC;
601 }
602
603 bool MSVCToolChain::equals(const ToolChain *other) const
604 {
605     const MSVCToolChain *o = static_cast<const MSVCToolChain *>(other);
606     return (m_installation.name == o->m_installation.name);
607 }
608
609 QByteArray msvcCompilationFile() {
610     static const char* macros[] = {"_ATL_VER", "_CHAR_UNSIGNED", "__CLR_VER",
611                                    "__cplusplus_cli", "__COUNTER__", "__cplusplus",
612                                    "_CPPLIB_VER", "_CPPRTTI", "_CPPUNWIND",
613                                    "_DEBUG", "_DLL", "__FUNCDNAME__",
614                                    "__FUNCSIG__","__FUNCTION__","_INTEGRAL_MAX_BITS",
615                                    "_M_ALPHA","_M_CEE","_M_CEE_PURE",
616                                    "_M_CEE_SAFE","_M_IX86","_M_IA64",
617                                    "_M_IX86_FP","_M_MPPC","_M_MRX000",
618                                    "_M_PPC","_M_X64","_MANAGED",
619                                    "_MFC_VER","_MSC_BUILD", /* "_MSC_EXTENSIONS", */
620                                    "_MSC_FULL_VER","_MSC_VER","__MSVC_RUNTIME_CHECKS",
621                                    "_MT", "_NATIVE_WCHAR_T_DEFINED", "_OPENMP",
622                                    "_VC_NODEFAULTLIB", "_WCHAR_T_DEFINED", "_WIN32",
623                                    "_WIN32_WCE", "_WIN64", "_Wp64", "__DATE__",
624                                     "__DATE__", "__TIME__", "__TIMESTAMP__",
625                                    0};
626     QByteArray file = "#define __PPOUT__(x) V##x=x\n\n";
627     int i =0;
628     while (macros[i] != 0) {
629         const QByteArray macro(macros[i]);
630         file += "#if defined(" + macro + ")\n__PPOUT__("
631                 + macro + ")\n#endif\n";
632         ++i;
633     }
634     file += "\nvoid main(){}\n\n";
635     return file;
636 }
637
638 // Run MSVC 'cl' compiler to obtain #defines.
639 static QByteArray msvcPredefinedMacros(const QStringList &env)
640 {
641     QByteArray predefinedMacros = "#define __MSVCRT__\n"
642                       "#define __w64\n"
643                       "#define __int64 long long\n"
644                       "#define __int32 long\n"
645                       "#define __int16 short\n"
646                       "#define __int8 char\n"
647                       "#define __ptr32\n"
648                       "#define __ptr64\n";
649
650     QString tmpFilePath;
651     {
652         // QTemporaryFile is buggy and will not unlock the file for cl.exe
653         QTemporaryFile tmpFile(QDir::tempPath()+"/envtestXXXXXX.cpp");
654         tmpFile.setAutoRemove(false);
655         if (!tmpFile.open())
656             return predefinedMacros;
657         tmpFilePath = QFileInfo(tmpFile).canonicalFilePath();
658         tmpFile.write(msvcCompilationFile());
659         tmpFile.close();
660     }
661     QProcess cpp;
662     cpp.setEnvironment(env);
663     cpp.setWorkingDirectory(QDir::tempPath());
664     QStringList arguments;
665     const QString binary = QLatin1String("cl.exe");
666     arguments << QLatin1String("/EP") << QDir::toNativeSeparators(tmpFilePath);
667     cpp.start(QLatin1String("cl.exe"), arguments);
668     if (!cpp.waitForStarted()) {
669         qWarning("%s: Cannot start '%s': %s", Q_FUNC_INFO, qPrintable(binary),
670             qPrintable(cpp.errorString()));
671         return predefinedMacros;
672     }
673     cpp.closeWriteChannel();
674     if (!cpp.waitForFinished()) {
675         Utils::SynchronousProcess::stopProcess(cpp);
676         qWarning("%s: Timeout running '%s'.", Q_FUNC_INFO, qPrintable(binary));
677         return predefinedMacros;
678     }
679     if (cpp.exitStatus() != QProcess::NormalExit) {
680         qWarning("%s: '%s' crashed.", Q_FUNC_INFO, qPrintable(binary));
681         return predefinedMacros;
682     }
683
684     const QList<QByteArray> output = cpp.readAllStandardOutput().split('\n');
685     foreach (const QByteArray& line, output) {
686         if (line.startsWith('V')) {
687             QList<QByteArray> split = line.split('=');
688             const QByteArray key = split.at(0).mid(1);
689             QByteArray value = split.at(1);
690             if (!value.isEmpty()) {
691                 value.chop(1); //remove '\n'
692             }
693             predefinedMacros += "#define ";
694             predefinedMacros += key;
695             predefinedMacros += ' ';
696             predefinedMacros += value;
697             predefinedMacros += '\n';
698         }
699     }
700     QFile::remove(tmpFilePath);
701     return predefinedMacros;
702 }
703
704 QByteArray MSVCToolChain::predefinedMacros()
705 {
706     if (m_predefinedMacros.isEmpty()) {
707         Utils::Environment env = Utils::Environment::systemEnvironment();
708         addToEnvironment(env);
709         m_predefinedMacros = msvcPredefinedMacros(env.toStringList());
710     }
711     return m_predefinedMacros;
712 }
713
714 QList<HeaderPath> MSVCToolChain::systemHeaderPaths()
715 {
716     //TODO fix this code
717     Utils::Environment env = Utils::Environment::systemEnvironment();
718     addToEnvironment(env);
719     QList<HeaderPath> headerPaths;
720     foreach(const QString &path, env.value("INCLUDE").split(QLatin1Char(';'))) {
721         headerPaths.append(HeaderPath(path, HeaderPath::GlobalHeaderPath));
722     }
723     return headerPaths;
724 }
725
726 MSVCToolChain::StringStringPairList MSVCToolChain::readEnvironmentSetting(const QString &varsBat,
727                                                                           const QStringList &args,
728                                                                           const Utils::Environment &env)
729 {
730     const StringStringPairList rc = readEnvironmentSettingI(varsBat, args, env);
731     if (debug) {
732         qDebug() << "Running: " << varsBat << args;
733         if (debug > 1) {
734             qDebug() << "Incoming: " << env.toStringList();
735             foreach(const StringStringPair &e, rc)
736                 qDebug() << e.first << e.second;
737         } else {
738             qDebug() << "Read: " << rc.size() << " variables.";
739         }
740     }
741     return rc;
742 }
743
744 // Windows: Expand the delayed evaluation references returned by the
745 // SDK setup scripts: "PATH=!Path!;foo". Some values might expand
746 // to empty and should not be added
747 static inline QString winExpandDelayedEnvReferences(QString in, const Utils::Environment &env)
748 {
749     const QChar exclamationMark = QLatin1Char('!');
750     for (int pos = 0; pos < in.size(); ) {
751         // Replace "!REF!" by its value in process environment
752         pos = in.indexOf(exclamationMark, pos);
753         if (pos == -1)
754             break;
755         const int nextPos = in.indexOf(exclamationMark, pos + 1);
756         if (nextPos == -1)
757             break;
758         const QString var = in.mid(pos + 1, nextPos - pos - 1);
759         const QString replacement = env.value(var.toUpper());
760         in.replace(pos, nextPos + 1 - pos, replacement);
761         pos += replacement.size();
762     }
763     return in;
764 }
765
766 MSVCToolChain::StringStringPairList MSVCToolChain::readEnvironmentSettingI(const QString &varsBat,
767                                                                            const QStringList &args,
768                                                                            const Utils::Environment &env)
769 {
770     // Run the setup script and extract the variables
771     if (!QFileInfo(varsBat).exists())
772         return StringStringPairList();
773     const QString tempOutputFileName = QDir::tempPath() + QLatin1String("\\qtcreator-msvc-environment.txt");
774     QTemporaryFile tf(QDir::tempPath() + "\\XXXXXX.bat");
775     tf.setAutoRemove(true);
776     if (!tf.open())
777         return StringStringPairList();
778     const QString filename = tf.fileName();
779     QByteArray call = "call ";
780     call += Utils::QtcProcess::quoteArg(varsBat).toLocal8Bit();
781     if (!args.isEmpty()) {
782         call += ' ';
783         call += Utils::QtcProcess::joinArgs(args).toLocal8Bit();
784     }
785     call += "\r\n";
786     tf.write(call);
787     const QByteArray redirect = "set > " + Utils::QtcProcess::quoteArg(
788                 QDir::toNativeSeparators(tempOutputFileName)).toLocal8Bit() + "\r\n";
789     tf.write(redirect);
790     tf.flush();
791     tf.waitForBytesWritten(30000);
792
793     QProcess run;
794     run.setEnvironment(env.toStringList());
795     const QString cmdPath = QString::fromLocal8Bit(qgetenv("COMSPEC"));
796     run.start(cmdPath, QStringList()<< QLatin1String("/c")<<QDir::toNativeSeparators(filename));
797     if (!run.waitForStarted()) {
798         qWarning("%s: Unable to run '%s': %s", Q_FUNC_INFO, qPrintable(varsBat),
799             qPrintable(run.errorString()));
800         return StringStringPairList();
801     }
802     if (!run.waitForFinished()) {
803         qWarning("%s: Timeout running '%s'", Q_FUNC_INFO, qPrintable(varsBat));
804         Utils::SynchronousProcess::stopProcess(run);
805         return StringStringPairList();
806     }
807     tf.close();
808
809     QFile varsFile(tempOutputFileName);
810     if (!varsFile.open(QIODevice::ReadOnly|QIODevice::Text))
811         return StringStringPairList();
812
813     QRegExp regexp(QLatin1String("(\\w*)=(.*)"));
814     StringStringPairList rc;
815     while (!varsFile.atEnd()) {
816         const QString line = QString::fromLocal8Bit(varsFile.readLine()).trimmed();
817         if (regexp.exactMatch(line)) {
818             const QString varName = regexp.cap(1);
819             const QString expandedValue = winExpandDelayedEnvReferences(regexp.cap(2), env);
820             if (!expandedValue.isEmpty())
821                 rc.append(StringStringPair(varName, expandedValue));
822         }
823     }
824     varsFile.close();
825     varsFile.remove();
826     return rc;
827 }
828
829 void MSVCToolChain::addToEnvironment(Utils::Environment &env)
830 {
831     if (debug)
832         qDebug() << "MSVCToolChain::addToEnvironment" << m_installation.name;
833     if (m_installation.name.isEmpty() || m_installation.varsBat.isEmpty()) {
834         qWarning("%s: Attempt to set up invalid MSVC Toolchain.", Q_FUNC_INFO);
835         return;
836     }
837     // We cache the full environment (incoming + modifications by setup script).
838     if (!m_valuesSet || env != m_lastEnvironment) {
839         m_lastEnvironment = env;
840         const QStringList args = m_installation.varsBatArg.isEmpty() ?
841                                  QStringList() :  QStringList(m_installation.varsBatArg);
842         m_values = readEnvironmentSetting(m_installation.varsBat, args, env);
843         m_valuesSet = true;
844     }
845
846     const StringStringPairList::const_iterator end = m_values.constEnd();
847     for (StringStringPairList::const_iterator it = m_values.constBegin(); it != end; ++it)
848         env.set((*it).first, (*it).second);
849 }
850
851 QString MSVCToolChain::makeCommand() const
852 {
853     if (ProjectExplorerPlugin::instance()->projectExplorerSettings().useJom) {
854         // We want jom! Try to find it.
855         QString jom = QCoreApplication::applicationDirPath() + QLatin1String("/jom.exe");
856         if (QFileInfo(jom).exists())
857             return jom;
858         else
859             return QLatin1String("jom.exe");
860     }
861     return QLatin1String("nmake.exe");
862 }
863
864 IOutputParser *MSVCToolChain::outputParser() const
865 {
866     return new MsvcParser;
867 }
868
869 WinCEToolChain *WinCEToolChain::create(const QString &name, const QString &platform)
870 {
871     const bool excludeSDK = true;
872     return new WinCEToolChain(findInstallationByName(false, name, excludeSDK), platform);
873 }
874
875 WinCEToolChain::WinCEToolChain(const Installation &in, const QString &platform) :
876         MSVCToolChain(in),
877         m_platform(platform)
878 {
879 }
880
881 ToolChainType WinCEToolChain::type() const
882 {
883     return ToolChain_WINCE;
884 }
885
886 bool WinCEToolChain::equals(const ToolChain *other) const
887 {
888     const WinCEToolChain *o = static_cast<const WinCEToolChain *>(other);
889     return (m_platform == o->m_platform && this->MSVCToolChain::equals(other));
890 }
891
892 QByteArray WinCEToolChain::predefinedMacros()
893 {
894     //TODO
895     return MSVCToolChain::predefinedMacros();
896 }
897
898 QList<HeaderPath> WinCEToolChain::systemHeaderPaths()
899 {
900     //TODO fix this code
901     Utils::Environment env = Utils::Environment::systemEnvironment();
902     addToEnvironment(env);
903
904     QList<HeaderPath> headerPaths;
905
906     const QStringList includes = env.value("INCLUDE").split(QLatin1Char(';'));
907
908     foreach (const QString &path, includes) {
909         const HeaderPath headerPath(path, HeaderPath::GlobalHeaderPath);
910         headerPaths.append(headerPath);
911     }
912
913     return headerPaths;
914 }
915
916 void WinCEToolChain::addToEnvironment(Utils::Environment &env)
917 {
918     MSVCToolChain::addToEnvironment(env);
919     QSettings registry(MSVC_RegKey, QSettings::NativeFormat);
920     QString path = registry.value(m_installation.name).toString();
921
922     // Find MSVC path
923
924     path += QLatin1Char('/');
925
926     // Find Platform name
927     CeSdkHandler cesdkhandler;
928     cesdkhandler.parse(path);
929     cesdkhandler.find(m_platform).addToEnvironment(env);
930 }