PageRenderTime 80ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/src/plugins/projectexplorer/msvctoolchain.cpp

https://bitbucket.org/kpozn/qtcreator
C++ | 813 lines | 699 code | 52 blank | 62 comment | 72 complexity | 215a5b6216c5a836b85d6bb2b5458d28 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-3.0
  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 (info@qt.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 info@qt.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/qtcprocess.h>
  40. #include <utils/qtcassert.h>
  41. #include <utils/synchronousprocess.h>
  42. #include <utils/winutils.h>
  43. #include <QtCore/QCoreApplication>
  44. #include <QtCore/QDir>
  45. #include <QtCore/QFileInfo>
  46. #include <QtCore/QSettings>
  47. #include <QtCore/QUrl>
  48. #include <QtCore/QTemporaryFile>
  49. #include <QtGui/QLabel>
  50. #include <QtGui/QFormLayout>
  51. #include <QtGui/QDesktopServices>
  52. #define KEY_ROOT "ProjectExplorer.MsvcToolChain."
  53. static const char debuggerCommandKeyC[] = KEY_ROOT"Debugger";
  54. static const char varsBatKeyC[] = KEY_ROOT"VarsBat";
  55. static const char varsBatArgKeyC[] = KEY_ROOT"VarsBatArg";
  56. static const char supportedAbiKeyC[] = KEY_ROOT"SupportedAbi";
  57. enum { debug = 0 };
  58. namespace ProjectExplorer {
  59. namespace Internal {
  60. // --------------------------------------------------------------------------
  61. // Helpers:
  62. // --------------------------------------------------------------------------
  63. static QString platformName(MsvcToolChain::Platform t)
  64. {
  65. switch (t) {
  66. case MsvcToolChain::s32:
  67. return QLatin1String(" (x86)");
  68. case MsvcToolChain::s64:
  69. return QLatin1String(" (x64)");
  70. case MsvcToolChain::ia64:
  71. return QLatin1String(" (ia64)");
  72. case MsvcToolChain::amd64:
  73. return QLatin1String(" (amd64)");
  74. }
  75. return QString();
  76. }
  77. static Abi findAbiOfMsvc(MsvcToolChain::Type type, MsvcToolChain::Platform platform, const QString &version)
  78. {
  79. Abi::Architecture arch = Abi::X86Architecture;
  80. Abi::OSFlavor flavor = Abi::UnknownFlavor;
  81. int wordWidth = 64;
  82. switch (platform)
  83. {
  84. case ProjectExplorer::Internal::MsvcToolChain::s32:
  85. wordWidth = 32;
  86. break;
  87. case ProjectExplorer::Internal::MsvcToolChain::ia64:
  88. arch = Abi::ItaniumArchitecture;
  89. break;
  90. case ProjectExplorer::Internal::MsvcToolChain::s64:
  91. case ProjectExplorer::Internal::MsvcToolChain::amd64:
  92. break;
  93. };
  94. QString msvcVersionString = version;
  95. if (type == MsvcToolChain::WindowsSDK) {
  96. if (version.startsWith(QLatin1String("7.")))
  97. msvcVersionString = QLatin1String("10.0");
  98. else if (version.startsWith(QLatin1String("6.1"))
  99. || (version.startsWith(QLatin1String("6.0")) && version != QLatin1String("6.0")))
  100. // The 6.0 SDK is shipping MSVC2005, Starting at 6.0a it is MSVC2008.
  101. msvcVersionString = QLatin1String("9.0");
  102. else
  103. msvcVersionString = QLatin1String("8.0");
  104. }
  105. if (msvcVersionString.startsWith(QLatin1String("10.")))
  106. flavor = Abi::WindowsMsvc2010Flavor;
  107. else if (msvcVersionString.startsWith(QLatin1String("9.")))
  108. flavor = Abi::WindowsMsvc2008Flavor;
  109. else
  110. flavor = Abi::WindowsMsvc2005Flavor;
  111. return Abi(arch, Abi::WindowsOS, flavor, Abi::PEFormat, wordWidth);
  112. }
  113. static QString generateDisplayName(const QString &name,
  114. MsvcToolChain::Type t,
  115. MsvcToolChain::Platform p)
  116. {
  117. if (t == MsvcToolChain::WindowsSDK) {
  118. QString sdkName = name;
  119. sdkName += platformName(p);
  120. return sdkName;
  121. }
  122. // Comes as "9.0" from the registry
  123. QString vcName = QLatin1String("Microsoft Visual C++ Compiler ");
  124. vcName += name;
  125. vcName += platformName(p);
  126. return vcName;
  127. }
  128. static QByteArray msvcCompilationFile()
  129. {
  130. static const char* macros[] = {"_ATL_VER", "_CHAR_UNSIGNED", "__CLR_VER",
  131. "__cplusplus_cli", "__COUNTER__", "__cplusplus",
  132. "_CPPLIB_VER", "_CPPRTTI", "_CPPUNWIND",
  133. "_DEBUG", "_DLL", "__FUNCDNAME__",
  134. "__FUNCSIG__","__FUNCTION__","_INTEGRAL_MAX_BITS",
  135. "_M_ALPHA","_M_CEE","_M_CEE_PURE",
  136. "_M_CEE_SAFE","_M_IX86","_M_IA64",
  137. "_M_IX86_FP","_M_MPPC","_M_MRX000",
  138. "_M_PPC","_M_X64","_MANAGED",
  139. "_MFC_VER","_MSC_BUILD", /* "_MSC_EXTENSIONS", */
  140. "_MSC_FULL_VER","_MSC_VER","__MSVC_RUNTIME_CHECKS",
  141. "_MT", "_NATIVE_WCHAR_T_DEFINED", "_OPENMP",
  142. "_VC_NODEFAULTLIB", "_WCHAR_T_DEFINED", "_WIN32",
  143. "_WIN32_WCE", "_WIN64", "_Wp64", "__DATE__",
  144. "__DATE__", "__TIME__", "__TIMESTAMP__",
  145. 0};
  146. QByteArray file = "#define __PPOUT__(x) V##x=x\n\n";
  147. for (int i = 0; macros[i] != 0; ++i) {
  148. const QByteArray macro(macros[i]);
  149. file += "#if defined(" + macro + ")\n__PPOUT__("
  150. + macro + ")\n#endif\n";
  151. }
  152. file += "\nvoid main(){}\n\n";
  153. return file;
  154. }
  155. // Run MSVC 'cl' compiler to obtain #defines.
  156. static QByteArray msvcPredefinedMacros(const Utils::Environment &env)
  157. {
  158. QByteArray predefinedMacros = "#define __MSVCRT__\n"
  159. "#define __w64\n"
  160. "#define __int64 long long\n"
  161. "#define __int32 long\n"
  162. "#define __int16 short\n"
  163. "#define __int8 char\n"
  164. "#define __ptr32\n"
  165. "#define __ptr64\n";
  166. Utils::TempFileSaver saver(QDir::tempPath()+"/envtestXXXXXX.cpp");
  167. saver.write(msvcCompilationFile());
  168. if (!saver.finalize()) {
  169. qWarning("%s: %s", Q_FUNC_INFO, qPrintable(saver.errorString()));
  170. return predefinedMacros;
  171. }
  172. QProcess cpp;
  173. cpp.setEnvironment(env.toStringList());
  174. cpp.setWorkingDirectory(QDir::tempPath());
  175. QStringList arguments;
  176. const QString binary = env.searchInPath(QLatin1String("cl.exe"));
  177. if (binary.isEmpty()) {
  178. qWarning("%s: The compiler binary cl.exe could not be found in the path.", Q_FUNC_INFO);
  179. return predefinedMacros;
  180. }
  181. arguments << QLatin1String("/EP") << QDir::toNativeSeparators(saver.fileName());
  182. cpp.start(binary, arguments);
  183. if (!cpp.waitForStarted()) {
  184. qWarning("%s: Cannot start '%s': %s", Q_FUNC_INFO, qPrintable(binary),
  185. qPrintable(cpp.errorString()));
  186. return predefinedMacros;
  187. }
  188. cpp.closeWriteChannel();
  189. if (!cpp.waitForFinished()) {
  190. Utils::SynchronousProcess::stopProcess(cpp);
  191. qWarning("%s: Timeout running '%s'.", Q_FUNC_INFO, qPrintable(binary));
  192. return predefinedMacros;
  193. }
  194. if (cpp.exitStatus() != QProcess::NormalExit) {
  195. qWarning("%s: '%s' crashed.", Q_FUNC_INFO, qPrintable(binary));
  196. return predefinedMacros;
  197. }
  198. const QList<QByteArray> output = cpp.readAllStandardOutput().split('\n');
  199. foreach (const QByteArray& line, output) {
  200. if (line.startsWith('V')) {
  201. QList<QByteArray> split = line.split('=');
  202. const QByteArray key = split.at(0).mid(1);
  203. QByteArray value = split.at(1);
  204. if (!value.isEmpty()) {
  205. value.chop(1); //remove '\n'
  206. }
  207. predefinedMacros += "#define ";
  208. predefinedMacros += key;
  209. predefinedMacros += ' ';
  210. predefinedMacros += value;
  211. predefinedMacros += '\n';
  212. }
  213. }
  214. if (debug)
  215. qDebug() << "msvcPredefinedMacros" << predefinedMacros;
  216. return predefinedMacros;
  217. }
  218. // Windows: Expand the delayed evaluation references returned by the
  219. // SDK setup scripts: "PATH=!Path!;foo". Some values might expand
  220. // to empty and should not be added
  221. static QString winExpandDelayedEnvReferences(QString in, const Utils::Environment &env)
  222. {
  223. const QChar exclamationMark = QLatin1Char('!');
  224. for (int pos = 0; pos < in.size(); ) {
  225. // Replace "!REF!" by its value in process environment
  226. pos = in.indexOf(exclamationMark, pos);
  227. if (pos == -1)
  228. break;
  229. const int nextPos = in.indexOf(exclamationMark, pos + 1);
  230. if (nextPos == -1)
  231. break;
  232. const QString var = in.mid(pos + 1, nextPos - pos - 1);
  233. const QString replacement = env.value(var.toUpper());
  234. in.replace(pos, nextPos + 1 - pos, replacement);
  235. pos += replacement.size();
  236. }
  237. return in;
  238. }
  239. static Utils::Environment msvcReadEnvironmentSetting(const QString &varsBat,
  240. const QString &args,
  241. Utils::Environment env)
  242. {
  243. // Run the setup script and extract the variables
  244. Utils::Environment result = env;
  245. if (!QFileInfo(varsBat).exists())
  246. return result;
  247. const QString tempOutputFileName = QDir::tempPath() + QLatin1String("\\qtcreator-msvc-environment.txt");
  248. Utils::TempFileSaver saver(QDir::tempPath() + "\\XXXXXX.bat");
  249. QByteArray call = "call ";
  250. call += Utils::QtcProcess::quoteArg(varsBat).toLocal8Bit();
  251. if (!args.isEmpty()) {
  252. call += ' ';
  253. call += args.toLocal8Bit();
  254. }
  255. call += "\r\n";
  256. saver.write(call);
  257. const QByteArray redirect = "set > " + Utils::QtcProcess::quoteArg(
  258. QDir::toNativeSeparators(tempOutputFileName)).toLocal8Bit() + "\r\n";
  259. saver.write(redirect);
  260. if (!saver.finalize()) {
  261. qWarning("%s: %s", Q_FUNC_INFO, qPrintable(saver.errorString()));
  262. return result;
  263. }
  264. Utils::QtcProcess run;
  265. // As of WinSDK 7.1, there is logic preventing the path from being set
  266. // correctly if "ORIGINALPATH" is already set. That can cause problems
  267. // if Creator is launched within a session set up by setenv.cmd.
  268. env.unset(QLatin1String("ORIGINALPATH"));
  269. run.setEnvironment(env);
  270. const QString cmdPath = QString::fromLocal8Bit(qgetenv("COMSPEC"));
  271. // Windows SDK setup scripts require command line switches for environment expansion.
  272. QString cmdArguments = QLatin1String(" /E:ON /V:ON /c \"");
  273. cmdArguments += QDir::toNativeSeparators(saver.fileName());
  274. cmdArguments += QLatin1Char('"');
  275. run.setCommand(cmdPath, cmdArguments);
  276. if (debug)
  277. qDebug() << "msvcReadEnvironmentSetting: " << call << cmdPath << cmdArguments
  278. << " Env: " << env.size();
  279. run.start();
  280. if (!run.waitForStarted()) {
  281. qWarning("%s: Unable to run '%s': %s", Q_FUNC_INFO, qPrintable(varsBat),
  282. qPrintable(run.errorString()));
  283. return result;
  284. }
  285. if (!run.waitForFinished()) {
  286. qWarning("%s: Timeout running '%s'", Q_FUNC_INFO, qPrintable(varsBat));
  287. Utils::SynchronousProcess::stopProcess(run);
  288. return result;
  289. }
  290. QFile varsFile(tempOutputFileName);
  291. if (!varsFile.open(QIODevice::ReadOnly|QIODevice::Text))
  292. return result;
  293. QRegExp regexp(QLatin1String("(\\w*)=(.*)"));
  294. while (!varsFile.atEnd()) {
  295. const QString line = QString::fromLocal8Bit(varsFile.readLine()).trimmed();
  296. if (regexp.exactMatch(line)) {
  297. const QString varName = regexp.cap(1);
  298. const QString expandedValue = winExpandDelayedEnvReferences(regexp.cap(2), env);
  299. if (!expandedValue.isEmpty())
  300. result.set(varName, expandedValue);
  301. }
  302. }
  303. varsFile.close();
  304. varsFile.remove();
  305. if (debug) {
  306. const QStringList newVars = result.toStringList();
  307. const QStringList oldVars = env.toStringList();
  308. QDebug nsp = qDebug().nospace();
  309. foreach (const QString &n, newVars) {
  310. if (!oldVars.contains(n))
  311. nsp << n << '\n';
  312. }
  313. }
  314. return result;
  315. }
  316. // --------------------------------------------------------------------------
  317. // MsvcToolChain
  318. // --------------------------------------------------------------------------
  319. MsvcToolChain::MsvcToolChain(const QString &name, const Abi &abi,
  320. const QString &varsBat, const QString &varsBatArg, bool autodetect) :
  321. ToolChain(QLatin1String(Constants::MSVC_TOOLCHAIN_ID), autodetect),
  322. m_varsBat(varsBat),
  323. m_varsBatArg(varsBatArg),
  324. m_lastEnvironment(Utils::Environment::systemEnvironment()),
  325. m_abi(abi)
  326. {
  327. Q_ASSERT(!name.isEmpty());
  328. Q_ASSERT(!m_varsBat.isEmpty());
  329. Q_ASSERT(QFileInfo(m_varsBat).exists());
  330. Q_ASSERT(abi.os() == Abi::WindowsOS);
  331. Q_ASSERT(abi.binaryFormat() == Abi::PEFormat);
  332. Q_ASSERT(abi.osFlavor() != Abi::WindowsMSysFlavor);
  333. updateId();
  334. setDisplayName(name);
  335. }
  336. MsvcToolChain::MsvcToolChain() :
  337. ToolChain(QLatin1String(Constants::MSVC_TOOLCHAIN_ID), false),
  338. m_lastEnvironment(Utils::Environment::systemEnvironment())
  339. {
  340. }
  341. MsvcToolChain *MsvcToolChain::readFromMap(const QVariantMap &data)
  342. {
  343. MsvcToolChain *tc = new MsvcToolChain;
  344. if (tc->fromMap(data))
  345. return tc;
  346. delete tc;
  347. return 0;
  348. }
  349. void MsvcToolChain::updateId()
  350. {
  351. const QChar colon = QLatin1Char(':');
  352. QString id = QLatin1String(Constants::MSVC_TOOLCHAIN_ID);
  353. id += colon;
  354. id += m_varsBat;
  355. id += colon;
  356. id += m_varsBatArg;
  357. id += colon;
  358. id += m_debuggerCommand;
  359. setId(id);
  360. }
  361. QString MsvcToolChain::typeName() const
  362. {
  363. return MsvcToolChainFactory::tr("MSVC");
  364. }
  365. Abi MsvcToolChain::targetAbi() const
  366. {
  367. return m_abi;
  368. }
  369. bool MsvcToolChain::isValid() const
  370. {
  371. return !m_varsBat.isEmpty();
  372. }
  373. QByteArray MsvcToolChain::predefinedMacros() const
  374. {
  375. if (m_predefinedMacros.isEmpty()) {
  376. Utils::Environment env(m_lastEnvironment);
  377. addToEnvironment(env);
  378. m_predefinedMacros = msvcPredefinedMacros(env);
  379. }
  380. return m_predefinedMacros;
  381. }
  382. QList<HeaderPath> MsvcToolChain::systemHeaderPaths() const
  383. {
  384. if (m_headerPaths.isEmpty()) {
  385. Utils::Environment env(m_lastEnvironment);
  386. addToEnvironment(env);
  387. foreach (const QString &path, env.value("INCLUDE").split(QLatin1Char(';')))
  388. m_headerPaths.append(HeaderPath(path, HeaderPath::GlobalHeaderPath));
  389. }
  390. return m_headerPaths;
  391. }
  392. void MsvcToolChain::addToEnvironment(Utils::Environment &env) const
  393. {
  394. // We cache the full environment (incoming + modifications by setup script).
  395. if (!m_resultEnvironment.size() || env != m_lastEnvironment) {
  396. if (debug)
  397. qDebug() << "addToEnvironment: " << displayName();
  398. m_lastEnvironment = env;
  399. m_resultEnvironment = msvcReadEnvironmentSetting(m_varsBat, m_varsBatArg, env);
  400. }
  401. env = m_resultEnvironment;
  402. }
  403. QString MsvcToolChain::mkspec() const
  404. {
  405. if (m_abi.osFlavor() == Abi::WindowsMsvc2005Flavor)
  406. return QLatin1String("win32-msvc2005");
  407. if (m_abi.osFlavor() == Abi::WindowsMsvc2008Flavor)
  408. return QLatin1String("win32-msvc2008");
  409. if (m_abi.osFlavor() == Abi::WindowsMsvc2010Flavor)
  410. return QLatin1String("win32-msvc2010");
  411. return QString();
  412. }
  413. QString MsvcToolChain::makeCommand() const
  414. {
  415. if (ProjectExplorerPlugin::instance()->projectExplorerSettings().useJom) {
  416. // We want jom! Try to find it.
  417. const QString jom = QLatin1String("jom.exe");
  418. const QFileInfo installedJom = QFileInfo(QCoreApplication::applicationDirPath()
  419. + QLatin1Char('/') + jom);
  420. if (installedJom.isFile() && installedJom.isExecutable()) {
  421. return installedJom.absoluteFilePath();
  422. } else {
  423. return jom;
  424. }
  425. }
  426. return QLatin1String("nmake.exe");
  427. }
  428. void MsvcToolChain::setDebuggerCommand(const QString &d)
  429. {
  430. if (m_debuggerCommand == d)
  431. return;
  432. m_debuggerCommand = d;
  433. updateId();
  434. toolChainUpdated();
  435. }
  436. QString MsvcToolChain::debuggerCommand() const
  437. {
  438. return m_debuggerCommand;
  439. }
  440. QVariantMap MsvcToolChain::toMap() const
  441. {
  442. QVariantMap data = ToolChain::toMap();
  443. if (!m_debuggerCommand.isEmpty())
  444. data.insert(QLatin1String(debuggerCommandKeyC), m_debuggerCommand);
  445. data.insert(QLatin1String(varsBatKeyC), m_varsBat);
  446. if (!m_varsBatArg.isEmpty())
  447. data.insert(QLatin1String(varsBatArgKeyC), m_varsBatArg);
  448. data.insert(QLatin1String(supportedAbiKeyC), m_abi.toString());
  449. return data;
  450. }
  451. bool MsvcToolChain::fromMap(const QVariantMap &data)
  452. {
  453. if (!ToolChain::fromMap(data))
  454. return false;
  455. m_varsBat = data.value(QLatin1String(varsBatKeyC)).toString();
  456. m_varsBatArg = data.value(QLatin1String(varsBatArgKeyC)).toString();
  457. m_debuggerCommand = data.value(QLatin1String(debuggerCommandKeyC)).toString();
  458. const QString abiString = data.value(QLatin1String(supportedAbiKeyC)).toString();
  459. m_abi = Abi(abiString);
  460. updateId();
  461. return !m_varsBat.isEmpty() && m_abi.isValid();
  462. }
  463. IOutputParser *MsvcToolChain::outputParser() const
  464. {
  465. return new MsvcParser;
  466. }
  467. ToolChainConfigWidget *MsvcToolChain::configurationWidget()
  468. {
  469. return new MsvcToolChainConfigWidget(this);
  470. }
  471. bool MsvcToolChain::canClone() const
  472. {
  473. return true;
  474. }
  475. ToolChain *MsvcToolChain::clone() const
  476. {
  477. return new MsvcToolChain(*this);
  478. }
  479. // --------------------------------------------------------------------------
  480. // MsvcDebuggerConfigLabel
  481. // --------------------------------------------------------------------------
  482. static const char dgbToolsDownloadLink32C[] = "http://www.microsoft.com/whdc/devtools/debugging/installx86.Mspx";
  483. static const char dgbToolsDownloadLink64C[] = "http://www.microsoft.com/whdc/devtools/debugging/install64bit.Mspx";
  484. QString MsvcDebuggerConfigLabel::labelText()
  485. {
  486. #ifdef Q_OS_WIN
  487. const bool is64bit = Utils::winIs64BitSystem();
  488. #else
  489. const bool is64bit = false;
  490. #endif
  491. const QString link = is64bit ? QLatin1String(dgbToolsDownloadLink64C) : QLatin1String(dgbToolsDownloadLink32C);
  492. //: Label text for path configuration. %2 is "x-bit version".
  493. return tr(
  494. "<html><body><p>Specify the path to the "
  495. "<a href=\"%1\">Windows Console Debugger executable</a>"
  496. " (%2) here.</p>"
  497. "</body></html>").arg(link, (is64bit ? tr("64-bit version")
  498. : tr("32-bit version")));
  499. }
  500. MsvcDebuggerConfigLabel::MsvcDebuggerConfigLabel(QWidget *parent) :
  501. QLabel(labelText(), parent)
  502. {
  503. connect(this, SIGNAL(linkActivated(QString)), this, SLOT(slotLinkActivated(QString)));
  504. setTextInteractionFlags(Qt::TextBrowserInteraction);
  505. }
  506. void MsvcDebuggerConfigLabel::slotLinkActivated(const QString &link)
  507. {
  508. QDesktopServices::openUrl(QUrl(link));
  509. }
  510. // --------------------------------------------------------------------------
  511. // MsvcToolChainConfigWidget
  512. // --------------------------------------------------------------------------
  513. MsvcToolChainConfigWidget::MsvcToolChainConfigWidget(ToolChain *tc) :
  514. ToolChainConfigWidget(tc),
  515. m_varsBatDisplayLabel(new QLabel(this))
  516. {
  517. QFormLayout *formLayout = new QFormLayout(this);
  518. formLayout->addRow(new QLabel(tc->displayName()));
  519. m_varsBatDisplayLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
  520. formLayout->addRow(tr("Initialization:"), m_varsBatDisplayLabel);
  521. formLayout->addRow(new MsvcDebuggerConfigLabel);
  522. addDebuggerCommandControls(formLayout, QStringList(QLatin1String("-version")));
  523. addDebuggerAutoDetection(this, SLOT(autoDetectDebugger()));
  524. addErrorLabel(formLayout);
  525. setFromToolChain();
  526. }
  527. void MsvcToolChainConfigWidget::apply()
  528. {
  529. MsvcToolChain *tc = static_cast<MsvcToolChain *>(toolChain());
  530. QTC_ASSERT(tc, return; );
  531. tc->setDebuggerCommand(debuggerCommand());
  532. }
  533. void MsvcToolChainConfigWidget::setFromToolChain()
  534. {
  535. MsvcToolChain *tc = static_cast<MsvcToolChain *>(toolChain());
  536. QTC_ASSERT(tc, return);
  537. QString varsBatDisplay = tc->varsBat();
  538. if (!tc->varsBatArg().isEmpty()) {
  539. varsBatDisplay += QLatin1Char(' ');
  540. varsBatDisplay += tc->varsBatArg();
  541. }
  542. m_varsBatDisplayLabel->setText(varsBatDisplay);
  543. setDebuggerCommand(tc->debuggerCommand());
  544. }
  545. bool MsvcToolChainConfigWidget::isDirty() const
  546. {
  547. MsvcToolChain *tc = static_cast<MsvcToolChain *>(toolChain());
  548. QTC_ASSERT(tc, return false);
  549. return debuggerCommand() != tc->debuggerCommand();
  550. }
  551. void MsvcToolChainConfigWidget::autoDetectDebugger()
  552. {
  553. clearErrorMessage();
  554. MsvcToolChain *tc = static_cast<MsvcToolChain *>(toolChain());
  555. QTC_ASSERT(tc, return);
  556. ProjectExplorer::Abi abi = tc->targetAbi();
  557. const QPair<QString, QString> cdbExecutables = MsvcToolChain::autoDetectCdbDebugger();
  558. QString debugger;
  559. if (abi.wordWidth() == 32) {
  560. if (cdbExecutables.first.isEmpty()) {
  561. setErrorMessage(tr("No CDB debugger detected (neither 32bit nor 64bit)."));
  562. return;
  563. }
  564. debugger = cdbExecutables.first;
  565. } else if (abi.wordWidth() == 64) {
  566. if (cdbExecutables.second.isEmpty()) {
  567. setErrorMessage(tr("No 64bit CDB debugger detected."));
  568. return;
  569. }
  570. debugger = cdbExecutables.second;
  571. }
  572. if (debugger != debuggerCommand()) {
  573. setDebuggerCommand(debugger);
  574. emitDirty();
  575. }
  576. }
  577. // --------------------------------------------------------------------------
  578. // MsvcToolChainFactory
  579. // --------------------------------------------------------------------------
  580. QString MsvcToolChainFactory::displayName() const
  581. {
  582. return tr("MSVC");
  583. }
  584. QString MsvcToolChainFactory::id() const
  585. {
  586. return QLatin1String(Constants::MSVC_TOOLCHAIN_ID);
  587. }
  588. QList<ToolChain *> MsvcToolChainFactory::autoDetect()
  589. {
  590. QList<ToolChain *> results;
  591. #ifdef Q_OS_WIN
  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())
  602. continue;
  603. const QString sdkVcVarsBat = folder + QLatin1String("bin\\SetEnv.cmd");
  604. if (!QFileInfo(sdkVcVarsBat).exists())
  605. continue;
  606. QList<ToolChain *> tmp;
  607. tmp.append(new MsvcToolChain(generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::s32),
  608. findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::s32, version),
  609. sdkVcVarsBat, QLatin1String("/x86"), true));
  610. // Add all platforms
  611. tmp.append(new MsvcToolChain(generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::s64),
  612. findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::s64, version),
  613. sdkVcVarsBat, QLatin1String("/x64"), true));
  614. tmp.append(new MsvcToolChain(generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::ia64),
  615. findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::ia64, version),
  616. sdkVcVarsBat, QLatin1String("/ia64"), true));
  617. // Make sure the default is front.
  618. if (folder == defaultSdkPath)
  619. results = tmp + results;
  620. else
  621. results += tmp;
  622. } // foreach
  623. }
  624. // 2) Installed MSVCs
  625. const QSettings vsRegistry(
  626. #ifdef Q_OS_WIN64
  627. QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7"),
  628. #else
  629. QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VC7"),
  630. #endif
  631. QSettings::NativeFormat);
  632. foreach (const QString &vsName, vsRegistry.allKeys()) {
  633. // Scan for version major.minor
  634. const int dotPos = vsName.indexOf(QLatin1Char('.'));
  635. if (dotPos == -1)
  636. continue;
  637. const QString path = vsRegistry.value(vsName).toString();
  638. const int version = vsName.left(dotPos).toInt();
  639. // Check existence of various install scripts
  640. const QString vcvars32bat = path + QLatin1String("bin\\vcvars32.bat");
  641. if (QFileInfo(vcvars32bat).isFile())
  642. results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::s32),
  643. findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::s32, vsName),
  644. vcvars32bat, QString(), true));
  645. if (version >= 10) {
  646. // Just one common file
  647. const QString vcvarsAllbat = path + QLatin1String("vcvarsall.bat");
  648. if (QFileInfo(vcvarsAllbat).isFile()) {
  649. results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::s32),
  650. findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::s32, vsName),
  651. vcvarsAllbat, QLatin1String("x86"), true));
  652. results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::amd64),
  653. findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::amd64, vsName),
  654. vcvarsAllbat, QLatin1String("amd64"), true));
  655. results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::s64),
  656. findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::s64, vsName),
  657. vcvarsAllbat, QLatin1String("x64"), true));
  658. results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::ia64),
  659. findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::ia64, vsName),
  660. vcvarsAllbat, QLatin1String("ia64"), true));
  661. } else {
  662. qWarning("Unable to find MSVC setup script %s in version %d", qPrintable(vcvarsAllbat), version);
  663. }
  664. } else {
  665. // Amd 64 is the preferred 64bit platform
  666. const QString vcvarsAmd64bat = path + QLatin1String("bin\\amd64\\vcvarsamd64.bat");
  667. if (QFileInfo(vcvarsAmd64bat).isFile())
  668. results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::amd64),
  669. findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::amd64, vsName),
  670. vcvarsAmd64bat, QString(), true));
  671. const QString vcvarsAmd64bat2 = path + QLatin1String("bin\\vcvarsx86_amd64.bat");
  672. if (QFileInfo(vcvarsAmd64bat2).isFile())
  673. results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::amd64),
  674. findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::amd64, vsName),
  675. vcvarsAmd64bat2, QString(), true));
  676. const QString vcvars64bat = path + QLatin1String("bin\\vcvars64.bat");
  677. if (QFileInfo(vcvars64bat).isFile())
  678. results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::s64),
  679. findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::s64, vsName),
  680. vcvars64bat, QString(), true));
  681. const QString vcvarsIA64bat = path + QLatin1String("bin\\vcvarsx86_ia64.bat");
  682. if (QFileInfo(vcvarsIA64bat).isFile())
  683. results.append(new MsvcToolChain(generateDisplayName(vsName, MsvcToolChain::VS, MsvcToolChain::ia64),
  684. findAbiOfMsvc(MsvcToolChain::VS, MsvcToolChain::ia64, vsName),
  685. vcvarsIA64bat, QString(), true));
  686. }
  687. }
  688. #endif
  689. if (!results.isEmpty()) { // Detect debugger
  690. const QPair<QString, QString> cdbDebugger = MsvcToolChain::autoDetectCdbDebugger();
  691. foreach (ToolChain *tc, results)
  692. static_cast<MsvcToolChain *>(tc)->setDebuggerCommand(tc->targetAbi().wordWidth() == 32 ? cdbDebugger.first : cdbDebugger.second);
  693. }
  694. return results;
  695. }
  696. QPair<QString, QString> MsvcToolChain::autoDetectCdbDebugger()
  697. {
  698. QPair<QString, QString> result;
  699. QStringList cdbs;
  700. QStringList programDirs;
  701. programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramFiles")));
  702. programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramFiles(x86)")));
  703. programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramW6432")));
  704. foreach (const QString &dirName, programDirs) {
  705. if (dirName.isEmpty())
  706. continue;
  707. QDir dir(dirName);
  708. foreach (const QFileInfo &fi, dir.entryInfoList(QStringList(QLatin1String("Debugging Tools for Windows*")),
  709. QDir::Dirs | QDir::NoDotAndDotDot)) {
  710. const QString filePath = fi.absoluteFilePath() + QLatin1String("/cdb.exe");
  711. if (!cdbs.contains(filePath))
  712. cdbs.append(fi.absoluteFilePath() + QLatin1String("/cdb.exe"));
  713. }
  714. }
  715. foreach (const QString &cdb, cdbs) {
  716. QList<ProjectExplorer::Abi> abis = ProjectExplorer::Abi::abisOfBinary(cdb);
  717. if (abis.isEmpty())
  718. continue;
  719. if (abis.first().wordWidth() == 32)
  720. result.first = cdb;
  721. else if (abis.first().wordWidth() == 64)
  722. result.second = cdb;
  723. }
  724. // prefer 64bit debugger, even for 32bit binaries:
  725. if (!result.second.isEmpty())
  726. result.first = result.second;
  727. return result;
  728. }
  729. bool MsvcToolChainFactory::canRestore(const QVariantMap &data)
  730. {
  731. return idFromMap(data).startsWith(QLatin1String(Constants::MSVC_TOOLCHAIN_ID) + QLatin1Char(':'));
  732. }
  733. } // namespace Internal
  734. } // namespace ProjectExplorer