1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
10 ** GNU Lesser General Public License Usage
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
31 **************************************************************************/
33 #include "msvctoolchain.h"
35 #include "msvcparser.h"
36 #include "projectexplorerconstants.h"
37 #include "headerpath.h"
39 #include <projectexplorer/projectexplorer.h>
40 #include <projectexplorer/projectexplorersettings.h>
42 #include <utils/qtcprocess.h>
43 #include <utils/qtcassert.h>
44 #include <utils/synchronousprocess.h>
45 #include <utils/winutils.h>
47 #include <QtCore/QCoreApplication>
48 #include <QtCore/QDir>
49 #include <QtCore/QFileInfo>
50 #include <QtCore/QSettings>
51 #include <QtCore/QUrl>
52 #include <QtCore/QTemporaryFile>
53 #include <QtGui/QLabel>
54 #include <QtGui/QFormLayout>
55 #include <QtGui/QDesktopServices>
57 static const char debuggerCommandKeyC[] = "ProjectExplorer.MsvcToolChain.Debugger";
61 namespace ProjectExplorer {
64 // --------------------------------------------------------------------------
66 // --------------------------------------------------------------------------
68 static QString platformName(MsvcToolChain::Platform t)
71 case MsvcToolChain::s32:
72 return QLatin1String(" (x86)");
73 case MsvcToolChain::s64:
74 return QLatin1String(" (x64)");
75 case MsvcToolChain::ia64:
76 return QLatin1String(" (ia64)");
77 case MsvcToolChain::amd64:
78 return QLatin1String(" (amd64)");
83 static Abi findAbiOfMsvc(MsvcToolChain::Type type, MsvcToolChain::Platform platform, const QString &version)
85 Abi::Architecture arch = Abi::X86Architecture;
86 Abi::OSFlavor flavor = Abi::UnknownFlavor;
91 case ProjectExplorer::Internal::MsvcToolChain::s32:
94 case ProjectExplorer::Internal::MsvcToolChain::ia64:
95 arch = Abi::ItaniumArchitecture;
97 case ProjectExplorer::Internal::MsvcToolChain::s64:
98 case ProjectExplorer::Internal::MsvcToolChain::amd64:
102 QString msvcVersionString = version;
103 if (type == MsvcToolChain::WindowsSDK) {
104 if (version.startsWith(QLatin1String("7.")))
105 msvcVersionString = QLatin1String("10.0");
106 else if (version.startsWith(QLatin1String("6.1"))
107 || (version.startsWith(QLatin1String("6.0")) && version != QLatin1String("6.0")))
108 // The 6.0 SDK is shipping MSVC2005, Starting at 6.0a it is MSVC2008.
109 msvcVersionString = QLatin1String("9.0");
111 msvcVersionString = QLatin1String("8.0");
113 if (msvcVersionString.startsWith(QLatin1String("10.")))
114 flavor = Abi::WindowsMsvc2010Flavor;
115 else if (msvcVersionString.startsWith(QLatin1String("9.")))
116 flavor = Abi::WindowsMsvc2008Flavor;
118 flavor = Abi::WindowsMsvc2005Flavor;
120 return Abi(arch, Abi::WindowsOS, flavor, Abi::PEFormat, wordWidth);
123 static QString generateDisplayName(const QString &name,
124 MsvcToolChain::Type t,
125 MsvcToolChain::Platform p)
127 if (t == MsvcToolChain::WindowsSDK) {
128 QString sdkName = name;
129 sdkName += platformName(p);
132 // Comes as "9.0" from the registry
133 QString vcName = QLatin1String("Microsoft Visual C++ Compiler ");
135 vcName += platformName(p);
139 static QByteArray msvcCompilationFile()
141 static const char* macros[] = {"_ATL_VER", "_CHAR_UNSIGNED", "__CLR_VER",
142 "__cplusplus_cli", "__COUNTER__", "__cplusplus",
143 "_CPPLIB_VER", "_CPPRTTI", "_CPPUNWIND",
144 "_DEBUG", "_DLL", "__FUNCDNAME__",
145 "__FUNCSIG__","__FUNCTION__","_INTEGRAL_MAX_BITS",
146 "_M_ALPHA","_M_CEE","_M_CEE_PURE",
147 "_M_CEE_SAFE","_M_IX86","_M_IA64",
148 "_M_IX86_FP","_M_MPPC","_M_MRX000",
149 "_M_PPC","_M_X64","_MANAGED",
150 "_MFC_VER","_MSC_BUILD", /* "_MSC_EXTENSIONS", */
151 "_MSC_FULL_VER","_MSC_VER","__MSVC_RUNTIME_CHECKS",
152 "_MT", "_NATIVE_WCHAR_T_DEFINED", "_OPENMP",
153 "_VC_NODEFAULTLIB", "_WCHAR_T_DEFINED", "_WIN32",
154 "_WIN32_WCE", "_WIN64", "_Wp64", "__DATE__",
155 "__DATE__", "__TIME__", "__TIMESTAMP__",
157 QByteArray file = "#define __PPOUT__(x) V##x=x\n\n";
158 for (int i = 0; macros[i] != 0; ++i) {
159 const QByteArray macro(macros[i]);
160 file += "#if defined(" + macro + ")\n__PPOUT__("
161 + macro + ")\n#endif\n";
163 file += "\nvoid main(){}\n\n";
167 // Run MSVC 'cl' compiler to obtain #defines.
168 static QByteArray msvcPredefinedMacros(const Utils::Environment &env)
170 QByteArray predefinedMacros = "#define __MSVCRT__\n"
172 "#define __int64 long long\n"
173 "#define __int32 long\n"
174 "#define __int16 short\n"
175 "#define __int8 char\n"
181 // QTemporaryFile is buggy and will not unlock the file for cl.exe
182 QTemporaryFile tmpFile(QDir::tempPath()+"/envtestXXXXXX.cpp");
183 tmpFile.setAutoRemove(false);
185 return predefinedMacros;
186 tmpFilePath = QFileInfo(tmpFile).canonicalFilePath();
187 tmpFile.write(msvcCompilationFile());
191 cpp.setEnvironment(env.toStringList());
192 cpp.setWorkingDirectory(QDir::tempPath());
193 QStringList arguments;
194 const QString binary = env.searchInPath(QLatin1String("cl.exe"));
195 if (binary.isEmpty()) {
196 qWarning("%s: The compiler binary cl.exe could not be found in the path.", Q_FUNC_INFO);
197 return predefinedMacros;
200 arguments << QLatin1String("/EP") << QDir::toNativeSeparators(tmpFilePath);
201 cpp.start(binary, arguments);
202 if (!cpp.waitForStarted()) {
203 qWarning("%s: Cannot start '%s': %s", Q_FUNC_INFO, qPrintable(binary),
204 qPrintable(cpp.errorString()));
205 return predefinedMacros;
207 cpp.closeWriteChannel();
208 if (!cpp.waitForFinished()) {
209 Utils::SynchronousProcess::stopProcess(cpp);
210 qWarning("%s: Timeout running '%s'.", Q_FUNC_INFO, qPrintable(binary));
211 return predefinedMacros;
213 if (cpp.exitStatus() != QProcess::NormalExit) {
214 qWarning("%s: '%s' crashed.", Q_FUNC_INFO, qPrintable(binary));
215 return predefinedMacros;
218 const QList<QByteArray> output = cpp.readAllStandardOutput().split('\n');
219 foreach (const QByteArray& line, output) {
220 if (line.startsWith('V')) {
221 QList<QByteArray> split = line.split('=');
222 const QByteArray key = split.at(0).mid(1);
223 QByteArray value = split.at(1);
224 if (!value.isEmpty()) {
225 value.chop(1); //remove '\n'
227 predefinedMacros += "#define ";
228 predefinedMacros += key;
229 predefinedMacros += ' ';
230 predefinedMacros += value;
231 predefinedMacros += '\n';
234 QFile::remove(tmpFilePath);
236 qDebug() << "msvcPredefinedMacros" << predefinedMacros;
237 return predefinedMacros;
240 // Windows: Expand the delayed evaluation references returned by the
241 // SDK setup scripts: "PATH=!Path!;foo". Some values might expand
242 // to empty and should not be added
243 static QString winExpandDelayedEnvReferences(QString in, const Utils::Environment &env)
245 const QChar exclamationMark = QLatin1Char('!');
246 for (int pos = 0; pos < in.size(); ) {
247 // Replace "!REF!" by its value in process environment
248 pos = in.indexOf(exclamationMark, pos);
251 const int nextPos = in.indexOf(exclamationMark, pos + 1);
254 const QString var = in.mid(pos + 1, nextPos - pos - 1);
255 const QString replacement = env.value(var.toUpper());
256 in.replace(pos, nextPos + 1 - pos, replacement);
257 pos += replacement.size();
262 static Utils::Environment msvcReadEnvironmentSetting(const QString &varsBat,
264 const Utils::Environment &env)
266 // Run the setup script and extract the variables
267 Utils::Environment result = env;
268 if (!QFileInfo(varsBat).exists())
271 const QString tempOutputFileName = QDir::tempPath() + QLatin1String("\\qtcreator-msvc-environment.txt");
272 QTemporaryFile tf(QDir::tempPath() + "\\XXXXXX.bat");
273 tf.setAutoRemove(true);
277 const QString filename = tf.fileName();
279 QByteArray call = "call ";
280 call += Utils::QtcProcess::quoteArg(varsBat).toLocal8Bit();
281 if (!args.isEmpty()) {
283 call += args.toLocal8Bit();
287 const QByteArray redirect = "set > " + Utils::QtcProcess::quoteArg(
288 QDir::toNativeSeparators(tempOutputFileName)).toLocal8Bit() + "\r\n";
291 tf.waitForBytesWritten(30000);
293 Utils::QtcProcess run;
294 run.setEnvironment(env);
295 const QString cmdPath = QString::fromLocal8Bit(qgetenv("COMSPEC"));
296 // Windows SDK setup scripts require command line switches for environment expansion.
297 QString cmdArguments = QLatin1String(" /E:ON /V:ON /c \"");
298 cmdArguments += QDir::toNativeSeparators(filename);
299 cmdArguments += QLatin1Char('"');
300 run.setCommand(cmdPath, cmdArguments);
302 qDebug() << "msvcReadEnvironmentSetting: " << call << cmdPath << cmdArguments
303 << " Env: " << env.size();
306 if (!run.waitForStarted()) {
307 qWarning("%s: Unable to run '%s': %s", Q_FUNC_INFO, qPrintable(varsBat),
308 qPrintable(run.errorString()));
311 if (!run.waitForFinished()) {
312 qWarning("%s: Timeout running '%s'", Q_FUNC_INFO, qPrintable(varsBat));
313 Utils::SynchronousProcess::stopProcess(run);
318 QFile varsFile(tempOutputFileName);
319 if (!varsFile.open(QIODevice::ReadOnly|QIODevice::Text))
322 QRegExp regexp(QLatin1String("(\\w*)=(.*)"));
323 while (!varsFile.atEnd()) {
324 const QString line = QString::fromLocal8Bit(varsFile.readLine()).trimmed();
325 if (regexp.exactMatch(line)) {
326 const QString varName = regexp.cap(1);
327 const QString expandedValue = winExpandDelayedEnvReferences(regexp.cap(2), env);
328 if (!expandedValue.isEmpty())
329 result.set(varName, expandedValue);
335 const QStringList newVars = result.toStringList();
336 const QStringList oldVars = env.toStringList();
337 QDebug nsp = qDebug().nospace();
338 foreach (const QString &n, newVars) {
339 if (!oldVars.contains(n))
346 // --------------------------------------------------------------------------
348 // --------------------------------------------------------------------------
350 MsvcToolChain::MsvcToolChain(const QString &name, const Abi &abi,
351 const QString &varsBat, const QString &varsBatArg, bool autodetect) :
352 ToolChain(QLatin1String(Constants::MSVC_TOOLCHAIN_ID), autodetect),
354 m_varsBatArg(varsBatArg),
355 m_lastEnvironment(Utils::Environment::systemEnvironment()),
358 Q_ASSERT(!name.isEmpty());
359 Q_ASSERT(!m_varsBat.isEmpty());
360 Q_ASSERT(QFileInfo(m_varsBat).exists());
361 Q_ASSERT(abi.os() == Abi::WindowsOS);
362 Q_ASSERT(abi.binaryFormat() == Abi::PEFormat);
363 Q_ASSERT(abi.osFlavor() != Abi::WindowsMSysFlavor);
365 setId(QString::fromLatin1("%1:%2.%3.%4").arg(Constants::MSVC_TOOLCHAIN_ID).arg(m_varsBat)
366 .arg(m_varsBatArg).arg(m_debuggerCommand));
368 setDisplayName(name);
371 QString MsvcToolChain::typeName() const
373 return MsvcToolChainFactory::tr("MSVC");
376 Abi MsvcToolChain::targetAbi() const
381 bool MsvcToolChain::isValid() const
383 return !m_varsBat.isEmpty();
386 QByteArray MsvcToolChain::predefinedMacros() const
388 if (m_predefinedMacros.isEmpty()) {
389 Utils::Environment env(m_lastEnvironment);
390 addToEnvironment(env);
391 m_predefinedMacros = msvcPredefinedMacros(env);
393 return m_predefinedMacros;
396 QList<HeaderPath> MsvcToolChain::systemHeaderPaths() const
398 if (m_headerPaths.isEmpty()) {
399 Utils::Environment env(m_lastEnvironment);
400 addToEnvironment(env);
401 foreach (const QString &path, env.value("INCLUDE").split(QLatin1Char(';')))
402 m_headerPaths.append(HeaderPath(path, HeaderPath::GlobalHeaderPath));
404 return m_headerPaths;
407 void MsvcToolChain::addToEnvironment(Utils::Environment &env) const
409 // We cache the full environment (incoming + modifications by setup script).
410 if (!m_resultEnvironment.size() || env != m_lastEnvironment) {
412 qDebug() << "addToEnvironment: " << displayName();
413 m_lastEnvironment = env;
414 m_resultEnvironment = msvcReadEnvironmentSetting(m_varsBat, m_varsBatArg, env);
416 env = m_resultEnvironment;
419 QString MsvcToolChain::makeCommand() const
421 if (ProjectExplorerPlugin::instance()->projectExplorerSettings().useJom) {
422 // We want jom! Try to find it.
423 const QString jom = QLatin1String("jom.exe");
424 const QFileInfo installedJom = QFileInfo(QCoreApplication::applicationDirPath()
425 + QLatin1Char('/') + jom);
426 if (installedJom.isFile() && installedJom.isExecutable()) {
427 return installedJom.absoluteFilePath();
432 return QLatin1String("nmake.exe");
435 void MsvcToolChain::setDebuggerCommand(const QString &d)
437 if (m_debuggerCommand == d)
439 m_debuggerCommand = d;
443 QString MsvcToolChain::debuggerCommand() const
445 return m_debuggerCommand;
448 QVariantMap MsvcToolChain::toMap() const
450 QVariantMap data = ToolChain::toMap();
451 data.insert(QLatin1String(debuggerCommandKeyC), m_debuggerCommand);
455 bool MsvcToolChain::fromMap(const QVariantMap &data)
457 if (!ToolChain::fromMap(data))
460 m_debuggerCommand= data.value(QLatin1String(debuggerCommandKeyC)).toString();
464 IOutputParser *MsvcToolChain::outputParser() const
466 return new MsvcParser;
469 ToolChainConfigWidget *MsvcToolChain::configurationWidget()
471 return new MsvcToolChainConfigWidget(this);
474 bool MsvcToolChain::canClone() const
479 ToolChain *MsvcToolChain::clone() const
481 return new MsvcToolChain(*this);
484 // --------------------------------------------------------------------------
485 // MsvcDebuggerConfigLabel
486 // --------------------------------------------------------------------------
488 static const char dgbToolsDownloadLink32C[] = "http://www.microsoft.com/whdc/devtools/debugging/installx86.Mspx";
489 static const char dgbToolsDownloadLink64C[] = "http://www.microsoft.com/whdc/devtools/debugging/install64bit.Mspx";
491 QString MsvcDebuggerConfigLabel::labelText()
494 const bool is64bit = Utils::winIs64BitSystem();
496 const bool is64bit = false;
498 const QString link = is64bit ? QLatin1String(dgbToolsDownloadLink64C) : QLatin1String(dgbToolsDownloadLink32C);
499 //: Label text for path configuration. %2 is "x-bit version".
501 "<html><body><p>Specify the path to the "
502 "<a href=\"%1\">Windows Console Debugger executable</a>"
504 "</body></html>").arg(link, (is64bit ? tr("64-bit version")
505 : tr("32-bit version")));
508 MsvcDebuggerConfigLabel::MsvcDebuggerConfigLabel(QWidget *parent) :
509 QLabel(labelText(), parent)
511 connect(this, SIGNAL(linkActivated(QString)), this, SLOT(slotLinkActivated(QString)));
512 setTextInteractionFlags(Qt::TextBrowserInteraction);
515 void MsvcDebuggerConfigLabel::slotLinkActivated(const QString &link)
517 QDesktopServices::openUrl(QUrl(link));
520 // --------------------------------------------------------------------------
521 // MsvcToolChainConfigWidget
522 // --------------------------------------------------------------------------
524 MsvcToolChainConfigWidget::MsvcToolChainConfigWidget(ToolChain *tc) :
525 ToolChainConfigWidget(tc)
527 QFormLayout *formLayout = new QFormLayout(this);
528 formLayout->addRow(new QLabel(tc->displayName()));
529 formLayout->addRow(new MsvcDebuggerConfigLabel);
530 addDebuggerCommandControls(formLayout, QStringList(QLatin1String("-version")));
531 addDebuggerAutoDetection(this, SLOT(autoDetectDebugger()));
532 addErrorLabel(formLayout);
536 void MsvcToolChainConfigWidget::apply()
538 MsvcToolChain *tc = static_cast<MsvcToolChain *>(toolChain());
539 QTC_ASSERT(tc, return; );
540 tc->setDebuggerCommand(debuggerCommand());
543 void MsvcToolChainConfigWidget::setFromToolChain()
545 MsvcToolChain *tc = static_cast<MsvcToolChain *>(toolChain());
546 QTC_ASSERT(tc, return);
547 setDebuggerCommand(tc->debuggerCommand());
550 bool MsvcToolChainConfigWidget::isDirty() const
552 MsvcToolChain *tc = static_cast<MsvcToolChain *>(toolChain());
553 QTC_ASSERT(tc, return false);
554 return debuggerCommand() != tc->debuggerCommand();
557 void MsvcToolChainConfigWidget::autoDetectDebugger()
559 QStringList directories;
560 const QString cdbExecutable = MsvcToolChain::autoDetectCdbDebugger(&directories);
561 if (cdbExecutable.isEmpty()) {
562 const QString msg = tr("The CDB debugger could not be found in %1").arg(directories.join(QLatin1String(", ")));
563 setErrorMessage(msg);
566 if (cdbExecutable != debuggerCommand()) {
567 setDebuggerCommand(cdbExecutable);
573 // --------------------------------------------------------------------------
574 // MsvcToolChainFactory
575 // --------------------------------------------------------------------------
577 QString MsvcToolChainFactory::displayName() const
582 QString MsvcToolChainFactory::id() const
584 return QLatin1String(Constants::MSVC_TOOLCHAIN_ID);
587 QList<ToolChain *> MsvcToolChainFactory::autoDetect()
589 QList<ToolChain *> results;
592 // 1) Installed SDKs preferred over standalone Visual studio
593 const QSettings sdkRegistry("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows",
594 QSettings::NativeFormat);
595 const QString defaultSdkPath = sdkRegistry.value(QLatin1String("CurrentInstallFolder")).toString();
596 if (!defaultSdkPath.isEmpty()) {
597 foreach (const QString &sdkKey, sdkRegistry.childGroups()) {
598 const QString name = sdkRegistry.value(sdkKey + QLatin1String("/ProductName")).toString();
599 const QString version = sdkRegistry.value(sdkKey + QLatin1String("/ProductVersion")).toString();
600 const QString folder = sdkRegistry.value(sdkKey + QLatin1String("/InstallationFolder")).toString();
601 if (folder.isEmpty())
604 const QString sdkVcVarsBat = folder + QLatin1String("bin\\SetEnv.cmd");
605 if (!QFileInfo(sdkVcVarsBat).exists())
607 QList<ToolChain *> tmp;
609 tmp.append(new MsvcToolChain(generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::s32),
610 findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::s32, version),
611 sdkVcVarsBat, QLatin1String("/x86"), true));
614 tmp.append(new MsvcToolChain(generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::s64),
615 findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::s64, version),
616 sdkVcVarsBat, QLatin1String("/x64"), true));
617 tmp.append(new MsvcToolChain(generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::ia64),
618 findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::ia64, version),
619 sdkVcVarsBat, QLatin1String("/ia64"), true));
621 // Make sure the default is front.
622 if (folder == defaultSdkPath)
623 results = tmp + results;
629 // 2) Installed MSVCs
630 const QSettings vsRegistry(
632 QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7"),
634 QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VC7"),
636 QSettings::NativeFormat);
637 foreach (const QString &vsName, vsRegistry.allKeys()) {
638 // Scan for version major.minor
639 const int dotPos = vsName.indexOf(QLatin1Char('.'));
643 const QString path = vsRegistry.value(vsName).toString();
644 const int version = vsName.left(dotPos).toInt();
645 // Check existence of various install scripts
646 const QString vcvars32bat = path + QLatin1String("bin\\vcvars32.bat");
647 if (QFileInfo(vcvars32bat).isFile())
648 results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::s32),
649 findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::s32, vsName),
650 vcvars32bat, QString(), true));
652 // Just one common file
653 const QString vcvarsAllbat = path + QLatin1String("vcvarsall.bat");
654 if (QFileInfo(vcvarsAllbat).isFile()) {
655 results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::s32),
656 findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::s32, vsName),
657 vcvarsAllbat, QLatin1String("x86"), true));
658 results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::amd64),
659 findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::amd64, vsName),
660 vcvarsAllbat, QLatin1String("amd64"), true));
661 results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::s64),
662 findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::s64, vsName),
663 vcvarsAllbat, QLatin1String("x64"), true));
664 results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::ia64),
665 findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::ia64, vsName),
666 vcvarsAllbat, QLatin1String("ia64"), true));
668 qWarning("Unable to find MSVC setup script %s in version %d", qPrintable(vcvarsAllbat), version);
671 // Amd 64 is the preferred 64bit platform
672 const QString vcvarsAmd64bat = path + QLatin1String("bin\\amd64\\vcvarsamd64.bat");
673 if (QFileInfo(vcvarsAmd64bat).isFile())
674 results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::amd64),
675 findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::amd64, vsName),
676 vcvarsAmd64bat, QString(), true));
677 const QString vcvarsAmd64bat2 = path + QLatin1String("bin\\vcvarsx86_amd64.bat");
678 if (QFileInfo(vcvarsAmd64bat2).isFile())
679 results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::amd64),
680 findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::amd64, vsName),
681 vcvarsAmd64bat2, QString(), true));
682 const QString vcvars64bat = path + QLatin1String("bin\\vcvars64.bat");
683 if (QFileInfo(vcvars64bat).isFile())
684 results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::s64),
685 findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::s64, vsName),
686 vcvars64bat, QString(), true));
687 const QString vcvarsIA64bat = path + QLatin1String("bin\\vcvarsx86_ia64.bat");
688 if (QFileInfo(vcvarsIA64bat).isFile())
689 results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::ia64),
690 findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::ia64, vsName),
691 vcvarsIA64bat, QString(), true));
695 if (!results.isEmpty()) { // Detect debugger
696 const QString cdbDebugger = MsvcToolChain::autoDetectCdbDebugger();
697 if (!cdbDebugger.isEmpty()) {
698 foreach (ToolChain *tc, results)
699 static_cast<MsvcToolChain *>(tc)->setDebuggerCommand(cdbDebugger);
705 // Check the CDB executable and accumulate the list of checked paths
707 static QString checkCdbExecutable(const QString &programDir, const QString &postfix,
708 QStringList *checkedDirectories = 0)
710 QString executable = programDir;
711 executable += QLatin1String("/Debugging Tools For Windows");
712 executable += postfix;
713 if (checkedDirectories)
714 checkedDirectories->push_back(QDir::toNativeSeparators(executable));
715 executable += QLatin1String("/cdb.exe");
716 const QFileInfo fi(executable);
717 return fi.isFile() && fi.isExecutable() ? fi.absoluteFilePath() : QString();
720 QString MsvcToolChain::autoDetectCdbDebugger(QStringList *checkedDirectories /* = 0 */)
722 // Look for $ProgramFiles/"Debugging Tools For Windows <bit-idy>/cdb.exe" and its
723 // " (x86)", " (x64)" variations.
724 static const char *postFixes[] = {"", " (x64)", " 64-bit", " (x86)", " (x32)" };
726 if (checkedDirectories)
727 checkedDirectories->clear();
729 const QString programDir = QString::fromLocal8Bit(qgetenv("ProgramFiles"));
730 if (programDir.isEmpty())
733 // Try the post fixes
735 for (unsigned i = 0; i < sizeof(postFixes)/sizeof(const char*); i++) {
736 outPath = checkCdbExecutable(programDir, QLatin1String(postFixes[i]), checkedDirectories);
737 if (!outPath.isEmpty())
740 // A 32bit-compile running on a 64bit system sees the 64 bit installation
741 // as "$ProgramFiles (x64)/Debugging Tools..." and (untested), a 64 bit-
742 // compile running on a 64bit system sees the 32 bit installation as
743 // "$ProgramFiles (x86)/Debugging Tools..." (assuming this works at all)
745 outPath = checkCdbExecutable(programDir + QLatin1String(" (x32)"), QString(), checkedDirectories);
746 if (!outPath.isEmpty())
749 // A 32bit process on 64 bit sees "ProgramFiles\Debg.. (x64)".
750 if (programDir.endsWith(QLatin1String(" (x86)"))) {
751 const QString programDir64 = programDir.left(programDir.size() - 6);
752 for (unsigned i = 0; i < sizeof(postFixes)/sizeof(const char*); i++) {
753 outPath = checkCdbExecutable(programDir64, QLatin1String(postFixes[i]), checkedDirectories);
754 if (!outPath.isEmpty())
762 } // namespace Internal
763 } // namespace ProjectExplorer