PageRenderTime 49ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/qt-creator-2.5.0-src/src/plugins/projectexplorer/msvctoolchain.cpp

#
C++ | 728 lines | 585 code | 74 blank | 69 comment | 101 complexity | 461a53fee72b5f069a338b92ef0b5f12 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, CC0-1.0
  1. /**************************************************************************
  2. **
  3. ** This file is part of Qt Creator
  4. **
  5. ** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
  6. **
  7. ** Contact: Nokia Corporation (qt-info@nokia.com)
  8. **
  9. **
  10. ** GNU Lesser General Public License Usage
  11. **
  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.
  18. **
  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.
  22. **
  23. ** Other Usage
  24. **
  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.
  27. **
  28. ** If you have questions regarding the use of this file, please contact
  29. ** Nokia at qt-info@nokia.com.
  30. **
  31. **************************************************************************/
  32. #include "msvctoolchain.h"
  33. #include "msvcparser.h"
  34. #include "projectexplorerconstants.h"
  35. #include "headerpath.h"
  36. #include <projectexplorer/projectexplorer.h>
  37. #include <projectexplorer/projectexplorersettings.h>
  38. #include <utils/fileutils.h>
  39. #include <utils/synchronousprocess.h>
  40. #include <utils/winutils.h>
  41. #include <utils/qtcassert.h>
  42. #include <QDir>
  43. #include <QFileInfo>
  44. #include <QProcess>
  45. #include <QSettings>
  46. #include <QUrl>
  47. #include <QFormLayout>
  48. #include <QDesktopServices>
  49. #define KEY_ROOT "ProjectExplorer.MsvcToolChain."
  50. static const char debuggerCommandKeyC[] = KEY_ROOT"Debugger";
  51. static const char varsBatKeyC[] = KEY_ROOT"VarsBat";
  52. static const char varsBatArgKeyC[] = KEY_ROOT"VarsBatArg";
  53. static const char supportedAbiKeyC[] = KEY_ROOT"SupportedAbi";
  54. enum { debug = 0 };
  55. namespace ProjectExplorer {
  56. namespace Internal {
  57. // --------------------------------------------------------------------------
  58. // Helpers:
  59. // --------------------------------------------------------------------------
  60. static QString platformName(MsvcToolChain::Platform t)
  61. {
  62. switch (t) {
  63. case MsvcToolChain::s32:
  64. return QLatin1String(" (x86)");
  65. case MsvcToolChain::s64:
  66. return QLatin1String(" (x64)");
  67. case MsvcToolChain::ia64:
  68. return QLatin1String(" (ia64)");
  69. case MsvcToolChain::amd64:
  70. return QLatin1String(" (amd64)");
  71. }
  72. return QString();
  73. }
  74. static Abi findAbiOfMsvc(MsvcToolChain::Type type, MsvcToolChain::Platform platform, const QString &version)
  75. {
  76. Abi::Architecture arch = Abi::X86Architecture;
  77. Abi::OSFlavor flavor = Abi::UnknownFlavor;
  78. int wordWidth = 64;
  79. switch (platform)
  80. {
  81. case ProjectExplorer::Internal::MsvcToolChain::s32:
  82. wordWidth = 32;
  83. break;
  84. case ProjectExplorer::Internal::MsvcToolChain::ia64:
  85. arch = Abi::ItaniumArchitecture;
  86. break;
  87. case ProjectExplorer::Internal::MsvcToolChain::s64:
  88. case ProjectExplorer::Internal::MsvcToolChain::amd64:
  89. break;
  90. };
  91. QString msvcVersionString = version;
  92. if (type == MsvcToolChain::WindowsSDK) {
  93. if (version.startsWith(QLatin1String("7.")))
  94. msvcVersionString = QLatin1String("10.0");
  95. else if (version.startsWith(QLatin1String("6.1"))
  96. || (version.startsWith(QLatin1String("6.0")) && version != QLatin1String("6.0")))
  97. // The 6.0 SDK is shipping MSVC2005, Starting at 6.0a it is MSVC2008.
  98. msvcVersionString = QLatin1String("9.0");
  99. else
  100. msvcVersionString = QLatin1String("8.0");
  101. }
  102. if (msvcVersionString.startsWith(QLatin1String("10.")))
  103. flavor = Abi::WindowsMsvc2010Flavor;
  104. else if (msvcVersionString.startsWith(QLatin1String("9.")))
  105. flavor = Abi::WindowsMsvc2008Flavor;
  106. else
  107. flavor = Abi::WindowsMsvc2005Flavor;
  108. return Abi(arch, Abi::WindowsOS, flavor, Abi::PEFormat, wordWidth);
  109. }
  110. static QString generateDisplayName(const QString &name,
  111. MsvcToolChain::Type t,
  112. MsvcToolChain::Platform p)
  113. {
  114. if (t == MsvcToolChain::WindowsSDK) {
  115. QString sdkName = name;
  116. sdkName += platformName(p);
  117. return sdkName;
  118. }
  119. // Comes as "9.0" from the registry
  120. QString vcName = QLatin1String("Microsoft Visual C++ Compiler ");
  121. vcName += name;
  122. vcName += platformName(p);
  123. return vcName;
  124. }
  125. static QByteArray msvcCompilationFile()
  126. {
  127. static const char* macros[] = {"_ATL_VER", "_CHAR_UNSIGNED", "__CLR_VER",
  128. "__cplusplus_cli", "__COUNTER__", "__cplusplus",
  129. "_CPPLIB_VER", "_CPPRTTI", "_CPPUNWIND",
  130. "_DEBUG", "_DLL", "__FUNCDNAME__",
  131. "__FUNCSIG__", "__FUNCTION__", "_INTEGRAL_MAX_BITS",
  132. "_M_ALPHA", "_M_AAMD64", "_M_CEE", "_M_CEE_PURE",
  133. "_M_CEE_SAFE", "_M_IX86", "_M_IA64",
  134. "_M_IX86_FP", "_M_MPPC", "_M_MRX000",
  135. "_M_PPC", "_M_X64", "_MANAGED",
  136. "_MFC_VER", "_MSC_BUILD", "_MSC_EXTENSIONS",
  137. "_MSC_FULL_VER", "_MSC_VER", "__MSVC_RUNTIME_CHECKS",
  138. "_MT", "_NATIVE_WCHAR_T_DEFINED", "_OPENMP",
  139. "_VC_NODEFAULTLIB", "_WCHAR_T_DEFINED", "_WIN32",
  140. "_WIN32_WCE", "_WIN64", "_Wp64",
  141. "__DATE__", "__TIME__", "__TIMESTAMP__",
  142. 0};
  143. QByteArray file = "#define __PPOUT__(x) V##x=x\n\n";
  144. for (int i = 0; macros[i] != 0; ++i) {
  145. const QByteArray macro(macros[i]);
  146. file += "#if defined(" + macro + ")\n__PPOUT__("
  147. + macro + ")\n#endif\n";
  148. }
  149. file += "\nvoid main(){}\n\n";
  150. return file;
  151. }
  152. // Run MSVC 'cl' compiler to obtain #defines.
  153. QByteArray MsvcToolChain::msvcPredefinedMacros(const QStringList cxxflags,
  154. const Utils::Environment &env) const
  155. {
  156. QByteArray predefinedMacros = AbstractMsvcToolChain::msvcPredefinedMacros(cxxflags, env);
  157. QStringList toProcess;
  158. foreach (const QString &arg, cxxflags) {
  159. if (arg.startsWith(QLatin1String("/D"))) {
  160. QString define = arg.mid(2);
  161. int pos = define.indexOf(QLatin1Char('='));
  162. if (pos < 0) {
  163. predefinedMacros += "#define ";
  164. predefinedMacros += define.toLocal8Bit();
  165. predefinedMacros += '\n';
  166. } else {
  167. predefinedMacros += "#define ";
  168. predefinedMacros += define.left(pos).toLocal8Bit();
  169. predefinedMacros += ' ';
  170. predefinedMacros += define.mid(pos + 1).toLocal8Bit();
  171. predefinedMacros += '\n';
  172. }
  173. } else if (arg.startsWith(QLatin1String("/U"))) {
  174. predefinedMacros += "#undef ";
  175. predefinedMacros += arg.mid(2).toLocal8Bit();
  176. predefinedMacros += '\n';
  177. } else {
  178. toProcess.append(arg);
  179. }
  180. }
  181. Utils::TempFileSaver saver(QDir::tempPath() + QLatin1String("/envtestXXXXXX.cpp"));
  182. saver.write(msvcCompilationFile());
  183. if (!saver.finalize()) {
  184. qWarning("%s: %s", Q_FUNC_INFO, qPrintable(saver.errorString()));
  185. return predefinedMacros;
  186. }
  187. QProcess cpp;
  188. cpp.setEnvironment(env.toStringList());
  189. cpp.setWorkingDirectory(QDir::tempPath());
  190. QStringList arguments;
  191. const QString binary = env.searchInPath(QLatin1String("cl.exe"));
  192. if (binary.isEmpty()) {
  193. qWarning("%s: The compiler binary cl.exe could not be found in the path.", Q_FUNC_INFO);
  194. return predefinedMacros;
  195. }
  196. arguments << toProcess << QLatin1String("/EP") << QDir::toNativeSeparators(saver.fileName());
  197. cpp.start(binary, arguments);
  198. if (!cpp.waitForStarted()) {
  199. qWarning("%s: Cannot start '%s': %s", Q_FUNC_INFO, qPrintable(binary),
  200. qPrintable(cpp.errorString()));
  201. return predefinedMacros;
  202. }
  203. cpp.closeWriteChannel();
  204. if (!cpp.waitForFinished()) {
  205. Utils::SynchronousProcess::stopProcess(cpp);
  206. qWarning("%s: Timeout running '%s'.", Q_FUNC_INFO, qPrintable(binary));
  207. return predefinedMacros;
  208. }
  209. if (cpp.exitStatus() != QProcess::NormalExit) {
  210. qWarning("%s: '%s' crashed.", Q_FUNC_INFO, qPrintable(binary));
  211. return predefinedMacros;
  212. }
  213. const QList<QByteArray> output = cpp.readAllStandardOutput().split('\n');
  214. foreach (const QByteArray& line, output) {
  215. if (line.startsWith('V')) {
  216. QList<QByteArray> split = line.split('=');
  217. const QByteArray key = split.at(0).mid(1);
  218. QByteArray value = split.at(1);
  219. if (!value.isEmpty()) {
  220. value.chop(1); //remove '\n'
  221. }
  222. predefinedMacros += "#define ";
  223. predefinedMacros += key;
  224. predefinedMacros += ' ';
  225. predefinedMacros += value;
  226. predefinedMacros += '\n';
  227. }
  228. }
  229. if (debug)
  230. qDebug() << "msvcPredefinedMacros" << predefinedMacros;
  231. return predefinedMacros;
  232. }
  233. // Windows: Expand the delayed evaluation references returned by the
  234. // SDK setup scripts: "PATH=!Path!;foo". Some values might expand
  235. // to empty and should not be added
  236. static QString winExpandDelayedEnvReferences(QString in, const Utils::Environment &env)
  237. {
  238. const QChar exclamationMark = QLatin1Char('!');
  239. for (int pos = 0; pos < in.size(); ) {
  240. // Replace "!REF!" by its value in process environment
  241. pos = in.indexOf(exclamationMark, pos);
  242. if (pos == -1)
  243. break;
  244. const int nextPos = in.indexOf(exclamationMark, pos + 1);
  245. if (nextPos == -1)
  246. break;
  247. const QString var = in.mid(pos + 1, nextPos - pos - 1);
  248. const QString replacement = env.value(var.toUpper());
  249. in.replace(pos, nextPos + 1 - pos, replacement);
  250. pos += replacement.size();
  251. }
  252. return in;
  253. }
  254. Utils::Environment MsvcToolChain::readEnvironmentSetting(Utils::Environment& env) const
  255. {
  256. Utils::Environment result = env;
  257. if (!QFileInfo(m_vcvarsBat).exists())
  258. return result;
  259. QMap<QString, QString> envPairs;
  260. if (!generateEnvironmentSettings(env, m_vcvarsBat, m_varsBatArg, envPairs))
  261. return result;
  262. // Now loop through and process them
  263. QMap<QString,QString>::const_iterator envIter;
  264. for (envIter = envPairs.begin(); envIter!=envPairs.end(); ++envIter) {
  265. const QString expandedValue = winExpandDelayedEnvReferences(envIter.value(), env);
  266. if (!expandedValue.isEmpty())
  267. result.set(envIter.key(), expandedValue);
  268. }
  269. if (debug) {
  270. const QStringList newVars = result.toStringList();
  271. const QStringList oldVars = env.toStringList();
  272. QDebug nsp = qDebug().nospace();
  273. foreach (const QString &n, newVars) {
  274. if (!oldVars.contains(n))
  275. nsp << n << '\n';
  276. }
  277. }
  278. return result;
  279. }
  280. // --------------------------------------------------------------------------
  281. // MsvcToolChain
  282. // --------------------------------------------------------------------------
  283. MsvcToolChain::MsvcToolChain(const QString &name, const Abi &abi,
  284. const QString &varsBat, const QString &varsBatArg, bool autodetect) :
  285. AbstractMsvcToolChain(QLatin1String(Constants::MSVC_TOOLCHAIN_ID), autodetect, abi, varsBat),
  286. m_varsBatArg(varsBatArg)
  287. {
  288. Q_ASSERT(!name.isEmpty());
  289. setDisplayName(name);
  290. }
  291. MsvcToolChain::MsvcToolChain() :
  292. AbstractMsvcToolChain(QLatin1String(Constants::MSVC_TOOLCHAIN_ID), false)
  293. {
  294. }
  295. MsvcToolChain *MsvcToolChain::readFromMap(const QVariantMap &data)
  296. {
  297. MsvcToolChain *tc = new MsvcToolChain;
  298. if (tc->fromMap(data))
  299. return tc;
  300. delete tc;
  301. return 0;
  302. }
  303. QString MsvcToolChain::legacyId() const
  304. {
  305. const QChar colon = QLatin1Char(':');
  306. QString id = QLatin1String(Constants::MSVC_TOOLCHAIN_ID);
  307. id += colon;
  308. id += m_vcvarsBat;
  309. id += colon;
  310. id += m_varsBatArg;
  311. id += colon;
  312. id += m_debuggerCommand.toString();
  313. return id;
  314. }
  315. QString MsvcToolChain::type() const
  316. {
  317. return QLatin1String("msvc");
  318. }
  319. QString MsvcToolChain::typeDisplayName() const
  320. {
  321. return MsvcToolChainFactory::tr("MSVC");
  322. }
  323. QList<Utils::FileName> MsvcToolChain::suggestedMkspecList() const
  324. {
  325. if (m_abi.osFlavor() == Abi::WindowsMsvc2005Flavor)
  326. return QList<Utils::FileName>() << Utils::FileName::fromString(QLatin1String("win32-msvc2005"));
  327. if (m_abi.osFlavor() == Abi::WindowsMsvc2008Flavor)
  328. return QList<Utils::FileName>() << Utils::FileName::fromString(QLatin1String("win32-msvc2008"));
  329. if (m_abi.osFlavor() == Abi::WindowsMsvc2010Flavor)
  330. return QList<Utils::FileName>() << Utils::FileName::fromString(QLatin1String("win32-msvc2010"));
  331. return QList<Utils::FileName>();
  332. }
  333. QVariantMap MsvcToolChain::toMap() const
  334. {
  335. QVariantMap data = ToolChain::toMap();
  336. if (!m_debuggerCommand.isEmpty())
  337. data.insert(QLatin1String(debuggerCommandKeyC), m_debuggerCommand.toString());
  338. data.insert(QLatin1String(varsBatKeyC), m_vcvarsBat);
  339. if (!m_varsBatArg.isEmpty())
  340. data.insert(QLatin1String(varsBatArgKeyC), m_varsBatArg);
  341. data.insert(QLatin1String(supportedAbiKeyC), m_abi.toString());
  342. return data;
  343. }
  344. bool MsvcToolChain::fromMap(const QVariantMap &data)
  345. {
  346. if (!ToolChain::fromMap(data))
  347. return false;
  348. m_vcvarsBat = data.value(QLatin1String(varsBatKeyC)).toString();
  349. m_varsBatArg = data.value(QLatin1String(varsBatArgKeyC)).toString();
  350. m_debuggerCommand = Utils::FileName::fromString(data.value(QLatin1String(debuggerCommandKeyC)).toString());
  351. const QString abiString = data.value(QLatin1String(supportedAbiKeyC)).toString();
  352. m_abi = Abi(abiString);
  353. return !m_vcvarsBat.isEmpty() && m_abi.isValid();
  354. }
  355. ToolChainConfigWidget *MsvcToolChain::configurationWidget()
  356. {
  357. return new MsvcToolChainConfigWidget(this);
  358. }
  359. ToolChain *MsvcToolChain::clone() const
  360. {
  361. return new MsvcToolChain(*this);
  362. }
  363. // --------------------------------------------------------------------------
  364. // MsvcDebuggerConfigLabel
  365. // --------------------------------------------------------------------------
  366. static const char dgbToolsDownloadLink32C[] = "http://www.microsoft.com/whdc/devtools/debugging/installx86.Mspx";
  367. static const char dgbToolsDownloadLink64C[] = "http://www.microsoft.com/whdc/devtools/debugging/install64bit.Mspx";
  368. QString MsvcDebuggerConfigLabel::labelText()
  369. {
  370. #ifdef Q_OS_WIN
  371. const bool is64bit = Utils::winIs64BitSystem();
  372. #else
  373. const bool is64bit = false;
  374. #endif
  375. const QString link = is64bit ? QLatin1String(dgbToolsDownloadLink64C) : QLatin1String(dgbToolsDownloadLink32C);
  376. //: Label text for path configuration. %2 is "x-bit version".
  377. return tr(
  378. "<html><body><p>Specify the path to the "
  379. "<a href=\"%1\">Windows Console Debugger executable</a>"
  380. " (%2) here.</p>"
  381. "</body></html>").arg(link, (is64bit ? tr("64-bit version")
  382. : tr("32-bit version")));
  383. }
  384. MsvcDebuggerConfigLabel::MsvcDebuggerConfigLabel(QWidget *parent) :
  385. QLabel(labelText(), parent)
  386. {
  387. connect(this, SIGNAL(linkActivated(QString)), this, SLOT(slotLinkActivated(QString)));
  388. setTextInteractionFlags(Qt::TextBrowserInteraction);
  389. }
  390. void MsvcDebuggerConfigLabel::slotLinkActivated(const QString &link)
  391. {
  392. QDesktopServices::openUrl(QUrl(link));
  393. }
  394. // --------------------------------------------------------------------------
  395. // MsvcToolChainConfigWidget
  396. // --------------------------------------------------------------------------
  397. MsvcToolChainConfigWidget::MsvcToolChainConfigWidget(ToolChain *tc) :
  398. ToolChainConfigWidget(tc),
  399. m_varsBatDisplayLabel(new QLabel(this))
  400. {
  401. QFormLayout *formLayout = new QFormLayout(this);
  402. formLayout->addRow(new QLabel(tc->displayName()));
  403. m_varsBatDisplayLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
  404. formLayout->addRow(tr("Initialization:"), m_varsBatDisplayLabel);
  405. formLayout->addRow(new MsvcDebuggerConfigLabel);
  406. addDebuggerCommandControls(formLayout, QStringList(QLatin1String("-version")));
  407. addDebuggerAutoDetection(this, SLOT(autoDetectDebugger()));
  408. addMkspecControls(formLayout);
  409. addErrorLabel(formLayout);
  410. setFromToolChain();
  411. }
  412. void MsvcToolChainConfigWidget::apply()
  413. {
  414. MsvcToolChain *tc = static_cast<MsvcToolChain *>(toolChain());
  415. QTC_ASSERT(tc, return; );
  416. tc->setDebuggerCommand(debuggerCommand());
  417. tc->setMkspecList(mkspecList());
  418. }
  419. void MsvcToolChainConfigWidget::setFromToolChain()
  420. {
  421. MsvcToolChain *tc = static_cast<MsvcToolChain *>(toolChain());
  422. QTC_ASSERT(tc, return);
  423. QString varsBatDisplay = tc->varsBat();
  424. if (!tc->varsBatArg().isEmpty()) {
  425. varsBatDisplay += QLatin1Char(' ');
  426. varsBatDisplay += tc->varsBatArg();
  427. }
  428. m_varsBatDisplayLabel->setText(varsBatDisplay);
  429. setDebuggerCommand(tc->debuggerCommand());
  430. setMkspecList(tc->mkspecList());
  431. }
  432. bool MsvcToolChainConfigWidget::isDirty() const
  433. {
  434. MsvcToolChain *tc = static_cast<MsvcToolChain *>(toolChain());
  435. QTC_ASSERT(tc, return false);
  436. return debuggerCommand() != tc->debuggerCommand()
  437. || mkspecList() != tc->mkspecList();
  438. }
  439. void MsvcToolChainConfigWidget::autoDetectDebugger()
  440. {
  441. clearErrorMessage();
  442. MsvcToolChain *tc = static_cast<MsvcToolChain *>(toolChain());
  443. QTC_ASSERT(tc, return);
  444. ProjectExplorer::Abi abi = tc->targetAbi();
  445. const QPair<Utils::FileName, Utils::FileName> cdbExecutables = MsvcToolChain::autoDetectCdbDebugger();
  446. Utils::FileName debugger;
  447. if (abi.wordWidth() == 32) {
  448. if (cdbExecutables.first.isEmpty()) {
  449. setErrorMessage(tr("No CDB debugger detected (neither 32bit nor 64bit)."));
  450. return;
  451. }
  452. debugger = cdbExecutables.first;
  453. } else if (abi.wordWidth() == 64) {
  454. if (cdbExecutables.second.isEmpty()) {
  455. setErrorMessage(tr("No 64bit CDB debugger detected."));
  456. return;
  457. }
  458. debugger = cdbExecutables.second;
  459. }
  460. if (debugger != debuggerCommand()) {
  461. setDebuggerCommand(debugger);
  462. emitDirty();
  463. }
  464. }
  465. // --------------------------------------------------------------------------
  466. // MsvcToolChainFactory
  467. // --------------------------------------------------------------------------
  468. QString MsvcToolChainFactory::displayName() const
  469. {
  470. return tr("MSVC");
  471. }
  472. QString MsvcToolChainFactory::id() const
  473. {
  474. return QLatin1String(Constants::MSVC_TOOLCHAIN_ID);
  475. }
  476. QList<ToolChain *> MsvcToolChainFactory::autoDetect()
  477. {
  478. QList<ToolChain *> results;
  479. // 1) Installed SDKs preferred over standalone Visual studio
  480. const QSettings sdkRegistry(QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows"),
  481. QSettings::NativeFormat);
  482. const QString defaultSdkPath = sdkRegistry.value(QLatin1String("CurrentInstallFolder")).toString();
  483. if (!defaultSdkPath.isEmpty()) {
  484. foreach (const QString &sdkKey, sdkRegistry.childGroups()) {
  485. const QString name = sdkRegistry.value(sdkKey + QLatin1String("/ProductName")).toString();
  486. const QString version = sdkRegistry.value(sdkKey + QLatin1String("/ProductVersion")).toString();
  487. const QString folder = sdkRegistry.value(sdkKey + QLatin1String("/InstallationFolder")).toString();
  488. if (folder.isEmpty())
  489. continue;
  490. QDir dir(folder);
  491. if (!dir.cd(QLatin1String("bin")))
  492. continue;
  493. QFileInfo fi(dir, QLatin1String("SetEnv.cmd"));
  494. if (!fi.exists())
  495. continue;
  496. QList<ToolChain *> tmp;
  497. tmp.append(new MsvcToolChain(generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::s32),
  498. findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::s32, version),
  499. fi.absoluteFilePath(), QLatin1String("/x86"), true));
  500. // Add all platforms
  501. tmp.append(new MsvcToolChain(generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::s64),
  502. findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::s64, version),
  503. fi.absoluteFilePath(), QLatin1String("/x64"), true));
  504. tmp.append(new MsvcToolChain(generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::ia64),
  505. findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::ia64, version),
  506. fi.absoluteFilePath(), QLatin1String("/ia64"), true));
  507. // Make sure the default is front.
  508. if (folder == defaultSdkPath)
  509. results = tmp + results;
  510. else
  511. results += tmp;
  512. } // foreach
  513. }
  514. // 2) Installed MSVCs
  515. const QSettings vsRegistry(
  516. #ifdef Q_OS_WIN64
  517. QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7"),
  518. #else
  519. QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VC7"),
  520. #endif
  521. QSettings::NativeFormat);
  522. foreach (const QString &vsName, vsRegistry.allKeys()) {
  523. // Scan for version major.minor
  524. const int dotPos = vsName.indexOf(QLatin1Char('.'));
  525. if (dotPos == -1)
  526. continue;
  527. const QString path = vsRegistry.value(vsName).toString();
  528. const int version = vsName.left(dotPos).toInt();
  529. // Check existence of various install scripts
  530. const QString vcvars32bat = path + QLatin1String("bin\\vcvars32.bat");
  531. if (QFileInfo(vcvars32bat).isFile())
  532. results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::s32),
  533. findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::s32, vsName),
  534. vcvars32bat, QString(), true));
  535. if (version >= 10) {
  536. // Just one common file
  537. const QString vcvarsAllbat = path + QLatin1String("vcvarsall.bat");
  538. if (QFileInfo(vcvarsAllbat).isFile()) {
  539. results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::s32),
  540. findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::s32, vsName),
  541. vcvarsAllbat, QLatin1String("x86"), true));
  542. results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::amd64),
  543. findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::amd64, vsName),
  544. vcvarsAllbat, QLatin1String("amd64"), true));
  545. results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::s64),
  546. findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::s64, vsName),
  547. vcvarsAllbat, QLatin1String("x64"), true));
  548. results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::ia64),
  549. findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::ia64, vsName),
  550. vcvarsAllbat, QLatin1String("ia64"), true));
  551. } else {
  552. qWarning("Unable to find MSVC setup script %s in version %d", qPrintable(vcvarsAllbat), version);
  553. }
  554. } else {
  555. // Amd 64 is the preferred 64bit platform
  556. const QString vcvarsAmd64bat = path + QLatin1String("bin\\amd64\\vcvarsamd64.bat");
  557. if (QFileInfo(vcvarsAmd64bat).isFile())
  558. results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::amd64),
  559. findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::amd64, vsName),
  560. vcvarsAmd64bat, QString(), true));
  561. const QString vcvarsAmd64bat2 = path + QLatin1String("bin\\vcvarsx86_amd64.bat");
  562. if (QFileInfo(vcvarsAmd64bat2).isFile())
  563. results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::amd64),
  564. findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::amd64, vsName),
  565. vcvarsAmd64bat2, QString(), true));
  566. const QString vcvars64bat = path + QLatin1String("bin\\vcvars64.bat");
  567. if (QFileInfo(vcvars64bat).isFile())
  568. results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::s64),
  569. findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::s64, vsName),
  570. vcvars64bat, QString(), true));
  571. const QString vcvarsIA64bat = path + QLatin1String("bin\\vcvarsx86_ia64.bat");
  572. if (QFileInfo(vcvarsIA64bat).isFile())
  573. results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::ia64),
  574. findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::ia64, vsName),
  575. vcvarsIA64bat, QString(), true));
  576. }
  577. }
  578. if (!results.isEmpty()) { // Detect debugger
  579. const QPair<Utils::FileName, Utils::FileName> cdbDebugger = MsvcToolChain::autoDetectCdbDebugger();
  580. foreach (ToolChain *tc, results)
  581. static_cast<MsvcToolChain *>(tc)->setDebuggerCommand(tc->targetAbi().wordWidth() == 32 ? cdbDebugger.first : cdbDebugger.second);
  582. }
  583. return results;
  584. }
  585. // Detect CDB, return a pair of <32bit, 64bit> executables.
  586. QPair<Utils::FileName, Utils::FileName> MsvcToolChain::autoDetectCdbDebugger()
  587. {
  588. QPair<Utils::FileName, Utils::FileName> result;
  589. QList<Utils::FileName> cdbs;
  590. QStringList programDirs;
  591. programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramFiles")));
  592. programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramFiles(x86)")));
  593. programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramW6432")));
  594. foreach (const QString &dirName, programDirs) {
  595. if (dirName.isEmpty())
  596. continue;
  597. QDir dir(dirName);
  598. // Windows SDK's starting from version 8 live in
  599. // "ProgramDir\Windows Kits\<version>"
  600. const QString windowsKitsFolderName = QLatin1String("Windows Kits");
  601. if (dir.exists(windowsKitsFolderName)) {
  602. QDir windowKitsFolder = dir;
  603. if (windowKitsFolder.cd(windowsKitsFolderName)) {
  604. // Check in reverse order (latest first)
  605. const QFileInfoList kitFolders =
  606. windowKitsFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot,
  607. QDir::Time|QDir::Reversed);
  608. foreach (const QFileInfo &kitFolderFi, kitFolders) {
  609. const QString path = kitFolderFi.absoluteFilePath();
  610. const QFileInfo cdb32(path + QLatin1String("/Debuggers/x86/cdb.exe"));
  611. if (cdb32.isExecutable())
  612. cdbs.push_back(Utils::FileName::fromString(cdb32.absoluteFilePath()));
  613. const QFileInfo cdb64(path + QLatin1String("/Debuggers/x64/cdb.exe"));
  614. if (cdb64.isExecutable())
  615. cdbs.push_back(Utils::FileName::fromString(cdb64.absoluteFilePath()));
  616. } // for Kits
  617. } // can cd to "Windows Kits"
  618. } // "Windows Kits" exists
  619. // Pre Windows SDK 8: Check 'Debugging Tools for Windows'
  620. foreach (const QFileInfo &fi, dir.entryInfoList(QStringList(QLatin1String("Debugging Tools for Windows*")),
  621. QDir::Dirs | QDir::NoDotAndDotDot)) {
  622. Utils::FileName filePath(fi);
  623. filePath.appendPath(QLatin1String("cdb.exe"));
  624. if (!cdbs.contains(filePath))
  625. cdbs.append(filePath);
  626. }
  627. }
  628. foreach (const Utils::FileName &cdb, cdbs) {
  629. QList<ProjectExplorer::Abi> abis = ProjectExplorer::Abi::abisOfBinary(cdb);
  630. if (abis.isEmpty())
  631. continue;
  632. if (abis.first().wordWidth() == 32)
  633. result.first = cdb;
  634. else if (abis.first().wordWidth() == 64)
  635. result.second = cdb;
  636. }
  637. // prefer 64bit debugger, even for 32bit binaries:
  638. if (!result.second.isEmpty())
  639. result.first = result.second;
  640. return result;
  641. }
  642. bool MsvcToolChain::operator ==(const ToolChain &other) const
  643. {
  644. if (!AbstractMsvcToolChain::operator ==(other))
  645. return false;
  646. const MsvcToolChain *msvcTc = static_cast<const MsvcToolChain *>(&other);
  647. return m_varsBatArg == msvcTc->m_varsBatArg;
  648. }
  649. bool MsvcToolChainFactory::canRestore(const QVariantMap &data)
  650. {
  651. return idFromMap(data).startsWith(QLatin1String(Constants::MSVC_TOOLCHAIN_ID) + QLatin1Char(':'));
  652. }
  653. } // namespace Internal
  654. } // namespace ProjectExplorer