PageRenderTime 63ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/src/plugins/projectexplorer/gcctoolchain.cpp

https://bitbucket.org/kpozn/qtcreator
C++ | 1140 lines | 902 code | 161 blank | 77 comment | 194 complexity | a4955de7270849ec1732e15b000a9fbf 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 "gcctoolchain.h"
  33. #include "clangparser.h"
  34. #include "gcctoolchainfactories.h"
  35. #include "gccparser.h"
  36. #include "linuxiccparser.h"
  37. #include "projectexplorerconstants.h"
  38. #include "toolchainmanager.h"
  39. #include <utils/environment.h>
  40. #include <utils/synchronousprocess.h>
  41. #include <utils/qtcassert.h>
  42. #include <utils/pathchooser.h>
  43. #include <QtCore/QBuffer>
  44. #include <QtCore/QCoreApplication>
  45. #include <QtCore/QFileInfo>
  46. #include <QtCore/QProcess>
  47. #include <QtCore/QScopedPointer>
  48. #include <QtGui/QComboBox>
  49. #include <QtGui/QFormLayout>
  50. #include <QtGui/QLabel>
  51. namespace ProjectExplorer {
  52. // --------------------------------------------------------------------------
  53. // Helpers:
  54. // --------------------------------------------------------------------------
  55. static const char compilerPathKeyC[] = "ProjectExplorer.GccToolChain.Path";
  56. static const char targetAbiKeyC[] = "ProjectExplorer.GccToolChain.TargetAbi";
  57. static const char supportedAbisKeyC[] = "ProjectExplorer.GccToolChain.SupportedAbis";
  58. static const char debuggerCommandKeyC[] = "ProjectExplorer.GccToolChain.Debugger";
  59. static QByteArray runGcc(const QString &gcc, const QStringList &arguments, const QStringList &env)
  60. {
  61. if (gcc.isEmpty() || !QFileInfo(gcc).isExecutable())
  62. return QByteArray();
  63. QProcess cpp;
  64. // Force locale: This function is used only to detect settings inside the tool chain, so this is save.
  65. QStringList environment(env);
  66. environment.append(QLatin1String("LC_ALL"));
  67. environment.append(QLatin1String("C"));
  68. cpp.setEnvironment(environment);
  69. cpp.start(gcc, arguments);
  70. if (!cpp.waitForStarted()) {
  71. qWarning("%s: Cannot start '%s': %s", Q_FUNC_INFO, qPrintable(gcc),
  72. qPrintable(cpp.errorString()));
  73. return QByteArray();
  74. }
  75. cpp.closeWriteChannel();
  76. if (!cpp.waitForFinished()) {
  77. Utils::SynchronousProcess::stopProcess(cpp);
  78. qWarning("%s: Timeout running '%s'.", Q_FUNC_INFO, qPrintable(gcc));
  79. return QByteArray();
  80. }
  81. if (cpp.exitStatus() != QProcess::NormalExit) {
  82. qWarning("%s: '%s' crashed.", Q_FUNC_INFO, qPrintable(gcc));
  83. return QByteArray();
  84. }
  85. return cpp.readAllStandardOutput() + '\n' + cpp.readAllStandardError();
  86. }
  87. static QByteArray gccPredefinedMacros(const QString &gcc, const QStringList &env)
  88. {
  89. QStringList arguments;
  90. arguments << QLatin1String("-xc++")
  91. << QLatin1String("-E")
  92. << QLatin1String("-dM")
  93. << QLatin1String("-");
  94. QByteArray predefinedMacros = runGcc(gcc, arguments, env);
  95. #ifdef Q_OS_MAC
  96. // Turn off flag indicating Apple's blocks support
  97. const QByteArray blocksDefine("#define __BLOCKS__ 1");
  98. const QByteArray blocksUndefine("#undef __BLOCKS__");
  99. const int idx = predefinedMacros.indexOf(blocksDefine);
  100. if (idx != -1) {
  101. predefinedMacros.replace(idx, blocksDefine.length(), blocksUndefine);
  102. }
  103. // Define __strong and __weak (used for Apple's GC extension of C) to be empty
  104. predefinedMacros.append("#define __strong\n");
  105. predefinedMacros.append("#define __weak\n");
  106. #endif // Q_OS_MAC
  107. return predefinedMacros;
  108. }
  109. static QList<HeaderPath> gccHeaderPathes(const QString &gcc, const QStringList &env)
  110. {
  111. QList<HeaderPath> systemHeaderPaths;
  112. QStringList arguments;
  113. arguments << QLatin1String("-xc++")
  114. << QLatin1String("-E")
  115. << QLatin1String("-v")
  116. << QLatin1String("-");
  117. QByteArray line;
  118. QByteArray data = runGcc(gcc, arguments, env);
  119. QBuffer cpp(&data);
  120. cpp.open(QIODevice::ReadOnly);
  121. while (cpp.canReadLine()) {
  122. line = cpp.readLine();
  123. if (line.startsWith("#include"))
  124. break;
  125. }
  126. if (!line.isEmpty() && line.startsWith("#include")) {
  127. HeaderPath::Kind kind = HeaderPath::UserHeaderPath;
  128. while (cpp.canReadLine()) {
  129. line = cpp.readLine();
  130. if (line.startsWith("#include")) {
  131. kind = HeaderPath::GlobalHeaderPath;
  132. } else if (! line.isEmpty() && QChar(line.at(0)).isSpace()) {
  133. HeaderPath::Kind thisHeaderKind = kind;
  134. line = line.trimmed();
  135. const int index = line.indexOf(" (framework directory)");
  136. if (index != -1) {
  137. line.truncate(index);
  138. thisHeaderKind = HeaderPath::FrameworkHeaderPath;
  139. }
  140. systemHeaderPaths.append(HeaderPath(QFile::decodeName(line), thisHeaderKind));
  141. } else if (line.startsWith("End of search list.")) {
  142. break;
  143. } else {
  144. qWarning() << "ignore line:" << line;
  145. }
  146. }
  147. }
  148. return systemHeaderPaths;
  149. }
  150. static QList<ProjectExplorer::Abi> guessGccAbi(const QString &m)
  151. {
  152. QList<ProjectExplorer::Abi> abiList;
  153. QString machine = m.toLower();
  154. if (machine.isEmpty())
  155. return abiList;
  156. QStringList parts = machine.split(QRegExp("[ /-]"));
  157. ProjectExplorer::Abi::Architecture arch = ProjectExplorer::Abi::UnknownArchitecture;
  158. ProjectExplorer::Abi::OS os = ProjectExplorer::Abi::UnknownOS;
  159. ProjectExplorer::Abi::OSFlavor flavor = ProjectExplorer::Abi::UnknownFlavor;
  160. ProjectExplorer::Abi::BinaryFormat format = ProjectExplorer::Abi::UnknownFormat;
  161. int width = 0;
  162. int unknownCount = 0;
  163. foreach (const QString &p, parts) {
  164. if (p == QLatin1String("unknown") || p == QLatin1String("pc") || p == QLatin1String("none")
  165. || p == QLatin1String("gnu") || p == QLatin1String("uclibc")
  166. || p == QLatin1String("86_64") || p == QLatin1String("redhat") || p == QLatin1String("gnueabi")) {
  167. continue;
  168. } else if (p == QLatin1String("i386") || p == QLatin1String("i486") || p == QLatin1String("i586")
  169. || p == QLatin1String("i686") || p == QLatin1String("x86")) {
  170. arch = ProjectExplorer::Abi::X86Architecture;
  171. width = 32;
  172. } else if (p.startsWith(QLatin1String("arm"))) {
  173. arch = ProjectExplorer::Abi::ArmArchitecture;
  174. width = 32;
  175. } else if (p == QLatin1String("mipsel")) {
  176. arch = ProjectExplorer::Abi::MipsArchitecture;
  177. width = 32;
  178. } else if (p == QLatin1String("x86_64")) {
  179. arch = ProjectExplorer::Abi::X86Architecture;
  180. width = 64;
  181. } else if (p == QLatin1String("powerpc")) {
  182. arch = ProjectExplorer::Abi::PowerPCArchitecture;
  183. } else if (p == QLatin1String("w64")) {
  184. width = 64;
  185. } else if (p == QLatin1String("linux") || p == QLatin1String("linux6e")) {
  186. os = ProjectExplorer::Abi::LinuxOS;
  187. if (flavor == Abi::UnknownFlavor)
  188. flavor = ProjectExplorer::Abi::GenericLinuxFlavor;
  189. format = ProjectExplorer::Abi::ElfFormat;
  190. } else if (p.startsWith("freebsd")) {
  191. os = ProjectExplorer::Abi::BsdOS;
  192. if (flavor == Abi::UnknownFlavor)
  193. flavor = ProjectExplorer::Abi::FreeBsdFlavor;
  194. format = ProjectExplorer::Abi::ElfFormat;
  195. } else if (p == QLatin1String("meego")) {
  196. os = ProjectExplorer::Abi::LinuxOS;
  197. flavor = ProjectExplorer::Abi::MeegoLinuxFlavor;
  198. format = ProjectExplorer::Abi::ElfFormat;
  199. } else if (p == QLatin1String("symbianelf")) {
  200. os = ProjectExplorer::Abi::SymbianOS;
  201. flavor = ProjectExplorer::Abi::SymbianDeviceFlavor;
  202. format = ProjectExplorer::Abi::ElfFormat;
  203. width = 32;
  204. } else if (p == QLatin1String("mingw32") || p == QLatin1String("win32")) {
  205. arch = ProjectExplorer::Abi::X86Architecture;
  206. os = ProjectExplorer::Abi::WindowsOS;
  207. flavor = ProjectExplorer::Abi::WindowsMSysFlavor;
  208. format = ProjectExplorer::Abi::PEFormat;
  209. if (width == 0)
  210. width = 32;
  211. } else if (p == QLatin1String("apple")) {
  212. os = ProjectExplorer::Abi::MacOS;
  213. flavor = ProjectExplorer::Abi::GenericMacFlavor;
  214. format = ProjectExplorer::Abi::MachOFormat;
  215. } else if (p == QLatin1String("darwin10")) {
  216. width = 64;
  217. } else if (p == QLatin1String("darwin9")) {
  218. width = 32;
  219. } else if (p == QLatin1String("gnueabi")) {
  220. format = ProjectExplorer::Abi::ElfFormat;
  221. } else {
  222. ++unknownCount;
  223. }
  224. }
  225. if (unknownCount == parts.count())
  226. return abiList;
  227. if (os == Abi::MacOS && arch != Abi::ArmArchitecture) {
  228. // Apple does PPC and x86!
  229. abiList << ProjectExplorer::Abi(arch, os, flavor, format, width);
  230. abiList << ProjectExplorer::Abi(arch, os, flavor, format, width == 64 ? 32 : 64);
  231. abiList << ProjectExplorer::Abi(arch == Abi::X86Architecture ? Abi::PowerPCArchitecture : Abi::X86Architecture, os, flavor, format, width);
  232. abiList << ProjectExplorer::Abi(arch == Abi::X86Architecture ? Abi::PowerPCArchitecture : Abi::X86Architecture, os, flavor, format, width == 64 ? 32 : 64);
  233. } else if (width == 64) {
  234. abiList << ProjectExplorer::Abi(arch, os, flavor, format, width);
  235. abiList << ProjectExplorer::Abi(arch, os, flavor, format, 32);
  236. } else {
  237. abiList << ProjectExplorer::Abi(arch, os, flavor, format, width);
  238. }
  239. return abiList;
  240. }
  241. static QList<ProjectExplorer::Abi> guessGccAbi(const QString &path, const QStringList &env)
  242. {
  243. QStringList arguments(QLatin1String("-dumpmachine"));
  244. QString machine = QString::fromLocal8Bit(runGcc(path, arguments, env)).trimmed();
  245. return guessGccAbi(machine);
  246. }
  247. static QString gccVersion(const QString &path, const QStringList &env)
  248. {
  249. QStringList arguments(QLatin1String("-dumpversion"));
  250. return QString::fromLocal8Bit(runGcc(path, arguments, env)).trimmed();
  251. }
  252. // --------------------------------------------------------------------------
  253. // GccToolChain
  254. // --------------------------------------------------------------------------
  255. GccToolChain::GccToolChain(bool autodetect) :
  256. ToolChain(QLatin1String(Constants::GCC_TOOLCHAIN_ID), autodetect)
  257. { }
  258. GccToolChain::GccToolChain(const QString &id, bool autodetect) :
  259. ToolChain(id, autodetect)
  260. { }
  261. GccToolChain::GccToolChain(const GccToolChain &tc) :
  262. ToolChain(tc),
  263. m_compilerPath(tc.compilerPath()),
  264. m_debuggerCommand(tc.debuggerCommand()),
  265. m_targetAbi(tc.m_targetAbi)
  266. {
  267. setCompilerPath(tc.m_compilerPath);
  268. }
  269. QString GccToolChain::defaultDisplayName() const
  270. {
  271. if (!m_targetAbi.isValid())
  272. return typeName();
  273. return QString::fromLatin1("%1 (%2 %3)").arg(typeName(),
  274. ProjectExplorer::Abi::toString(m_targetAbi.architecture()),
  275. ProjectExplorer::Abi::toString(m_targetAbi.wordWidth()));
  276. }
  277. void GccToolChain::updateId()
  278. {
  279. QString i = id();
  280. i = i.left(i.indexOf(QLatin1Char(':')));
  281. setId(QString::fromLatin1("%1:%2.%3.%4")
  282. .arg(i).arg(m_compilerPath)
  283. .arg(m_targetAbi.toString()).arg(m_debuggerCommand));
  284. }
  285. QString GccToolChain::typeName() const
  286. {
  287. return Internal::GccToolChainFactory::tr("GCC");
  288. }
  289. Abi GccToolChain::targetAbi() const
  290. {
  291. return m_targetAbi;
  292. }
  293. QString GccToolChain::version() const
  294. {
  295. if (m_version.isEmpty())
  296. m_version = detectVersion();
  297. return m_version;
  298. }
  299. void GccToolChain::setTargetAbi(const Abi &abi)
  300. {
  301. if (abi == m_targetAbi)
  302. return;
  303. updateSupportedAbis();
  304. m_targetAbi = abi;
  305. toolChainUpdated();
  306. }
  307. QList<Abi> GccToolChain::supportedAbis() const
  308. {
  309. updateSupportedAbis();
  310. return m_supportedAbis;
  311. }
  312. bool GccToolChain::isValid() const
  313. {
  314. return !m_compilerPath.isNull();
  315. }
  316. QByteArray GccToolChain::predefinedMacros() const
  317. {
  318. if (m_predefinedMacros.isEmpty()) {
  319. // Using a clean environment breaks ccache/distcc/etc.
  320. Utils::Environment env = Utils::Environment::systemEnvironment();
  321. addToEnvironment(env);
  322. m_predefinedMacros = gccPredefinedMacros(m_compilerPath, env.toStringList());
  323. }
  324. return m_predefinedMacros;
  325. }
  326. QList<HeaderPath> GccToolChain::systemHeaderPaths() const
  327. {
  328. if (m_headerPathes.isEmpty()) {
  329. // Using a clean environment breaks ccache/distcc/etc.
  330. Utils::Environment env = Utils::Environment::systemEnvironment();
  331. addToEnvironment(env);
  332. m_headerPathes = gccHeaderPathes(m_compilerPath, env.toStringList());
  333. }
  334. return m_headerPathes;
  335. }
  336. void GccToolChain::addToEnvironment(Utils::Environment &env) const
  337. {
  338. if (!m_compilerPath.isEmpty())
  339. env.prependOrSetPath(QFileInfo(m_compilerPath).absolutePath());
  340. env.set(QLatin1String("LANG"), QLatin1String("C"));
  341. }
  342. void GccToolChain::setDebuggerCommand(const QString &d)
  343. {
  344. if (m_debuggerCommand == d)
  345. return;
  346. m_debuggerCommand = d;
  347. updateId();
  348. toolChainUpdated();
  349. }
  350. QString GccToolChain::debuggerCommand() const
  351. {
  352. return m_debuggerCommand;
  353. }
  354. QString GccToolChain::mkspec() const
  355. {
  356. Abi abi = targetAbi();
  357. if (abi.os() == Abi::MacOS) {
  358. QString v = version();
  359. // prefer versioned g++ on mac. This is required to enable building for older Mac OS versions
  360. if (v.startsWith(QLatin1String("4.0")))
  361. return QLatin1String("macx-g++40");
  362. if (v.startsWith(QLatin1String("4.2")))
  363. return QLatin1String("macx-g++42");
  364. return QLatin1String("macx-g++");
  365. }
  366. QList<Abi> gccAbiList = Abi::abisOfBinary(m_compilerPath);
  367. Abi gccAbi;
  368. if (!gccAbiList.isEmpty())
  369. gccAbi = gccAbiList.first();
  370. if (!gccAbi.isNull()
  371. && (gccAbi.architecture() != abi.architecture()
  372. || gccAbi.os() != abi.os()
  373. || gccAbi.osFlavor() != abi.osFlavor())) {
  374. // Note: This can fail:-(
  375. return QString(); // this is a cross-compiler, leave the mkspec alone!
  376. }
  377. if (abi.os() == Abi::LinuxOS) {
  378. if (abi.osFlavor() != Abi::GenericLinuxFlavor)
  379. return QString(); // most likely not a desktop, so leave the mkspec alone.
  380. if (abi.wordWidth() == gccAbi.wordWidth())
  381. return QLatin1String("linux-g++"); // no need to explicitly set the word width
  382. return QLatin1String("linux-g++-") + QString::number(m_targetAbi.wordWidth());
  383. }
  384. if (abi.os() == Abi::BsdOS && abi.osFlavor() == Abi::FreeBsdFlavor)
  385. return QLatin1String("freebsd-g++");
  386. return QString();
  387. }
  388. QString GccToolChain::makeCommand() const
  389. {
  390. return QLatin1String("make");
  391. }
  392. IOutputParser *GccToolChain::outputParser() const
  393. {
  394. return new GccParser;
  395. }
  396. void GccToolChain::setCompilerPath(const QString &path)
  397. {
  398. if (path == m_compilerPath)
  399. return;
  400. bool resetDisplayName = displayName() == defaultDisplayName();
  401. m_compilerPath = path;
  402. m_supportedAbis.clear();
  403. Abi currentAbi = m_targetAbi;
  404. m_targetAbi = Abi();
  405. if (!m_compilerPath.isEmpty()) {
  406. updateSupportedAbis();
  407. if (!m_supportedAbis.isEmpty()) {
  408. if (m_supportedAbis.contains(currentAbi))
  409. m_targetAbi = currentAbi;
  410. else
  411. m_targetAbi = m_supportedAbis.at(0);
  412. }
  413. if (resetDisplayName)
  414. setDisplayName(defaultDisplayName());
  415. }
  416. updateId(); // Will trigger toolChainUpdated()!
  417. }
  418. QString GccToolChain::compilerPath() const
  419. {
  420. return m_compilerPath;
  421. }
  422. ToolChain *GccToolChain::clone() const
  423. {
  424. return new GccToolChain(*this);
  425. }
  426. QVariantMap GccToolChain::toMap() const
  427. {
  428. QVariantMap data = ToolChain::toMap();
  429. data.insert(QLatin1String(compilerPathKeyC), m_compilerPath);
  430. data.insert(QLatin1String(targetAbiKeyC), m_targetAbi.toString());
  431. QStringList abiList;
  432. foreach (const ProjectExplorer::Abi &a, m_supportedAbis)
  433. abiList.append(a.toString());
  434. data.insert(QLatin1String(supportedAbisKeyC), abiList);
  435. data.insert(QLatin1String(debuggerCommandKeyC), m_debuggerCommand);
  436. return data;
  437. }
  438. bool GccToolChain::fromMap(const QVariantMap &data)
  439. {
  440. if (!ToolChain::fromMap(data))
  441. return false;
  442. m_compilerPath = data.value(QLatin1String(compilerPathKeyC)).toString();
  443. m_targetAbi = Abi(data.value(QLatin1String(targetAbiKeyC)).toString());
  444. QStringList abiList = data.value(QLatin1String(supportedAbisKeyC)).toStringList();
  445. m_supportedAbis.clear();
  446. foreach (const QString &a, abiList) {
  447. ProjectExplorer::Abi abi(a);
  448. if (!abi.isValid())
  449. continue;
  450. m_supportedAbis.append(abi);
  451. }
  452. m_debuggerCommand = data.value(QLatin1String(debuggerCommandKeyC)).toString();
  453. updateId();
  454. return true;
  455. }
  456. bool GccToolChain::operator ==(const ToolChain &other) const
  457. {
  458. if (!ToolChain::operator ==(other))
  459. return false;
  460. const GccToolChain *gccTc = static_cast<const GccToolChain *>(&other);
  461. return m_compilerPath == gccTc->m_compilerPath && m_targetAbi == gccTc->m_targetAbi
  462. && m_debuggerCommand == gccTc->m_debuggerCommand;
  463. }
  464. ToolChainConfigWidget *GccToolChain::configurationWidget()
  465. {
  466. return new Internal::GccToolChainConfigWidget(this);
  467. }
  468. void GccToolChain::updateSupportedAbis() const
  469. {
  470. if (m_supportedAbis.isEmpty())
  471. m_supportedAbis = detectSupportedAbis();
  472. }
  473. QList<Abi> GccToolChain::detectSupportedAbis() const
  474. {
  475. Utils::Environment env = Utils::Environment::systemEnvironment();
  476. addToEnvironment(env);
  477. return guessGccAbi(m_compilerPath, env.toStringList());
  478. }
  479. QString GccToolChain::detectVersion() const
  480. {
  481. Utils::Environment env = Utils::Environment::systemEnvironment();
  482. addToEnvironment(env);
  483. return gccVersion(m_compilerPath, env.toStringList());
  484. }
  485. // --------------------------------------------------------------------------
  486. // GccToolChainFactory
  487. // --------------------------------------------------------------------------
  488. QString Internal::GccToolChainFactory::displayName() const
  489. {
  490. return tr("GCC");
  491. }
  492. QString Internal::GccToolChainFactory::id() const
  493. {
  494. return QLatin1String(Constants::GCC_TOOLCHAIN_ID);
  495. }
  496. bool Internal::GccToolChainFactory::canCreate()
  497. {
  498. return true;
  499. }
  500. ToolChain *Internal::GccToolChainFactory::create()
  501. {
  502. return createToolChain(false);
  503. }
  504. QList<ToolChain *> Internal::GccToolChainFactory::autoDetect()
  505. {
  506. QStringList debuggers;
  507. #ifdef Q_OS_MAC
  508. // Fixme Prefer lldb once it is implemented: debuggers.push_back(QLatin1String("lldb"));
  509. #endif
  510. debuggers.push_back(QLatin1String("gdb"));
  511. return autoDetectToolchains(QLatin1String("g++"), debuggers, Abi::hostAbi());
  512. }
  513. // Used by the ToolChainManager to restore user-generated tool chains
  514. bool Internal::GccToolChainFactory::canRestore(const QVariantMap &data)
  515. {
  516. return idFromMap(data).startsWith(QLatin1String(Constants::GCC_TOOLCHAIN_ID) + QLatin1Char(':'));
  517. }
  518. ToolChain *Internal::GccToolChainFactory::restore(const QVariantMap &data)
  519. {
  520. GccToolChain *tc = new GccToolChain(false);
  521. if (tc->fromMap(data))
  522. return tc;
  523. delete tc;
  524. return 0;
  525. }
  526. GccToolChain *Internal::GccToolChainFactory::createToolChain(bool autoDetect)
  527. {
  528. return new GccToolChain(autoDetect);
  529. }
  530. QList<ToolChain *> Internal::GccToolChainFactory::autoDetectToolchains(const QString &compiler,
  531. const QStringList &debuggers,
  532. const Abi &requiredAbi)
  533. {
  534. QList<ToolChain *> result;
  535. const Utils::Environment systemEnvironment = Utils::Environment::systemEnvironment();
  536. const QString compilerPath = systemEnvironment.searchInPath(compiler);
  537. if (compilerPath.isEmpty())
  538. return result;
  539. QList<Abi> abiList = guessGccAbi(compilerPath, systemEnvironment.toStringList());
  540. if (!abiList.contains(requiredAbi)) {
  541. if (requiredAbi.wordWidth() != 64
  542. || !abiList.contains(Abi(requiredAbi.architecture(), requiredAbi.os(), requiredAbi.osFlavor(),
  543. requiredAbi.binaryFormat(), 32)))
  544. return result;
  545. }
  546. QString debuggerPath = ToolChainManager::instance()->defaultDebugger(requiredAbi); // Find the first debugger
  547. if (debuggerPath.isEmpty()) {
  548. foreach (const QString &debugger, debuggers) {
  549. debuggerPath = systemEnvironment.searchInPath(debugger);
  550. if (!debuggerPath.isEmpty())
  551. break;
  552. }
  553. }
  554. foreach (const Abi &abi, abiList) {
  555. QScopedPointer<GccToolChain> tc(createToolChain(true));
  556. if (tc.isNull())
  557. return result;
  558. tc->setCompilerPath(compilerPath);
  559. tc->setDebuggerCommand(debuggerPath);
  560. tc->setTargetAbi(abi);
  561. tc->setDisplayName(tc->defaultDisplayName()); // reset displayname
  562. result.append(tc.take());
  563. }
  564. return result;
  565. }
  566. // --------------------------------------------------------------------------
  567. // GccToolChainConfigWidget
  568. // --------------------------------------------------------------------------
  569. Internal::GccToolChainConfigWidget::GccToolChainConfigWidget(GccToolChain *tc) :
  570. ToolChainConfigWidget(tc),
  571. m_compilerPath(new Utils::PathChooser),
  572. m_abiWidget(new AbiWidget),
  573. m_isReadOnly(false)
  574. {
  575. Q_ASSERT(tc);
  576. QFormLayout *layout = new QFormLayout(this);
  577. const QStringList gnuVersionArgs = QStringList(QLatin1String("--version"));
  578. m_compilerPath->setExpectedKind(Utils::PathChooser::ExistingCommand);
  579. m_compilerPath->setCommandVersionArguments(gnuVersionArgs);
  580. layout->addRow(tr("&Compiler path:"), m_compilerPath);
  581. layout->addRow(tr("&ABI:"), m_abiWidget);
  582. m_abiWidget->setEnabled(false);
  583. addDebuggerCommandControls(layout, gnuVersionArgs);
  584. addErrorLabel(layout);
  585. setFromToolchain();
  586. connect(m_compilerPath, SIGNAL(changed(QString)), this, SLOT(handlePathChange()));
  587. connect(m_abiWidget, SIGNAL(abiChanged()), this, SLOT(handleAbiChange()));
  588. }
  589. void Internal::GccToolChainConfigWidget::apply()
  590. {
  591. if (toolChain()->isAutoDetected())
  592. return;
  593. GccToolChain *tc = static_cast<GccToolChain *>(toolChain());
  594. Q_ASSERT(tc);
  595. QString displayName = tc->displayName();
  596. QString path = m_compilerPath->path();
  597. if (path.isEmpty())
  598. path = m_compilerPath->rawPath();
  599. tc->setCompilerPath(path);
  600. tc->setTargetAbi(m_abiWidget->currentAbi());
  601. tc->setDisplayName(displayName); // reset display name
  602. tc->setDebuggerCommand(debuggerCommand());
  603. m_autoDebuggerCommand = QLatin1String("<manually set>");
  604. }
  605. void Internal::GccToolChainConfigWidget::setFromToolchain()
  606. {
  607. // subwidgets are not yet connected!
  608. bool blocked = blockSignals(true);
  609. GccToolChain *tc = static_cast<GccToolChain *>(toolChain());
  610. m_compilerPath->setPath(tc->compilerPath());
  611. m_abiWidget->setAbis(tc->supportedAbis(), tc->targetAbi());
  612. if (!m_isReadOnly && !m_compilerPath->path().isEmpty())
  613. m_abiWidget->setEnabled(true);
  614. setDebuggerCommand(tc->debuggerCommand());
  615. blockSignals(blocked);
  616. }
  617. bool Internal::GccToolChainConfigWidget::isDirty() const
  618. {
  619. GccToolChain *tc = static_cast<GccToolChain *>(toolChain());
  620. Q_ASSERT(tc);
  621. return m_compilerPath->path() != tc->compilerPath()
  622. || m_abiWidget->currentAbi() != tc->targetAbi();
  623. }
  624. void Internal::GccToolChainConfigWidget::makeReadOnly()
  625. {
  626. m_compilerPath->setEnabled(false);
  627. m_abiWidget->setEnabled(false);
  628. m_isReadOnly = true;
  629. ToolChainConfigWidget::makeReadOnly();
  630. }
  631. void Internal::GccToolChainConfigWidget::handlePathChange()
  632. {
  633. QString path = m_compilerPath->path();
  634. QList<Abi> abiList;
  635. bool haveCompiler = false;
  636. if (!path.isEmpty()) {
  637. QFileInfo fi(path);
  638. haveCompiler = fi.isExecutable() && fi.isFile();
  639. }
  640. if (haveCompiler)
  641. abiList = guessGccAbi(path, Utils::Environment::systemEnvironment().toStringList());
  642. m_abiWidget->setEnabled(haveCompiler);
  643. Abi currentAbi = m_abiWidget->currentAbi();
  644. m_abiWidget->setAbis(abiList, abiList.contains(currentAbi) ? currentAbi : Abi());
  645. handleAbiChange();
  646. }
  647. void Internal::GccToolChainConfigWidget::handleAbiChange()
  648. {
  649. if (m_autoDebuggerCommand == debuggerCommand()) {
  650. ProjectExplorer::Abi abi = m_abiWidget->currentAbi();
  651. m_autoDebuggerCommand = ToolChainManager::instance()->defaultDebugger(abi);
  652. setDebuggerCommand(m_autoDebuggerCommand);
  653. }
  654. emit dirty(toolChain());
  655. }
  656. // --------------------------------------------------------------------------
  657. // ClangToolChain
  658. // --------------------------------------------------------------------------
  659. ClangToolChain::ClangToolChain(bool autodetect) :
  660. GccToolChain(QLatin1String(Constants::CLANG_TOOLCHAIN_ID), autodetect)
  661. { }
  662. QString ClangToolChain::typeName() const
  663. {
  664. return Internal::ClangToolChainFactory::tr("Clang");
  665. }
  666. QString ClangToolChain::makeCommand() const
  667. {
  668. #if defined(Q_OS_WIN)
  669. return QLatin1String("mingw32-make.exe");
  670. #else
  671. return QLatin1String("make");
  672. #endif
  673. }
  674. QString ClangToolChain::mkspec() const
  675. {
  676. Abi abi = targetAbi();
  677. if (abi.os() == Abi::MacOS)
  678. return QLatin1String("unsupported/macx-clang");
  679. else if (abi.os() == Abi::LinuxOS)
  680. return QLatin1String("unsupported/linux-clang");
  681. return QString(); // Note: Not supported by Qt yet, so default to the mkspec the Qt was build with
  682. }
  683. IOutputParser *ClangToolChain::outputParser() const
  684. {
  685. return new ClangParser;
  686. }
  687. ToolChain *ClangToolChain::clone() const
  688. {
  689. return new ClangToolChain(*this);
  690. }
  691. // --------------------------------------------------------------------------
  692. // ClangToolChainFactory
  693. // --------------------------------------------------------------------------
  694. QString Internal::ClangToolChainFactory::displayName() const
  695. {
  696. return tr("Clang");
  697. }
  698. QString Internal::ClangToolChainFactory::id() const
  699. {
  700. return QLatin1String(Constants::CLANG_TOOLCHAIN_ID);
  701. }
  702. QList<ToolChain *> Internal::ClangToolChainFactory::autoDetect()
  703. {
  704. Abi ha = Abi::hostAbi();
  705. return autoDetectToolchains(QLatin1String("clang++"), QStringList(), ha);
  706. }
  707. bool Internal::ClangToolChainFactory::canCreate()
  708. {
  709. return true;
  710. }
  711. ToolChain *Internal::ClangToolChainFactory::create()
  712. {
  713. return createToolChain(false);
  714. }
  715. bool Internal::ClangToolChainFactory::canRestore(const QVariantMap &data)
  716. {
  717. return idFromMap(data).startsWith(QLatin1String(Constants::CLANG_TOOLCHAIN_ID) + QLatin1Char(':'));
  718. }
  719. ToolChain *Internal::ClangToolChainFactory::restore(const QVariantMap &data)
  720. {
  721. ClangToolChain *tc = new ClangToolChain(false);
  722. if (tc->fromMap(data))
  723. return tc;
  724. delete tc;
  725. return 0;
  726. }
  727. GccToolChain *Internal::ClangToolChainFactory::createToolChain(bool autoDetect)
  728. {
  729. return new ClangToolChain(autoDetect);
  730. }
  731. // --------------------------------------------------------------------------
  732. // MingwToolChain
  733. // --------------------------------------------------------------------------
  734. MingwToolChain::MingwToolChain(bool autodetect) :
  735. GccToolChain(QLatin1String(Constants::MINGW_TOOLCHAIN_ID), autodetect)
  736. { }
  737. QString MingwToolChain::typeName() const
  738. {
  739. return Internal::MingwToolChainFactory::tr("MinGW");
  740. }
  741. QString MingwToolChain::mkspec() const
  742. {
  743. return QLatin1String("win32-g++");
  744. }
  745. QString MingwToolChain::makeCommand() const
  746. {
  747. return QLatin1String("mingw32-make.exe");
  748. }
  749. ToolChain *MingwToolChain::clone() const
  750. {
  751. return new MingwToolChain(*this);
  752. }
  753. // --------------------------------------------------------------------------
  754. // MingwToolChainFactory
  755. // --------------------------------------------------------------------------
  756. QString Internal::MingwToolChainFactory::displayName() const
  757. {
  758. return tr("MinGW");
  759. }
  760. QString Internal::MingwToolChainFactory::id() const
  761. {
  762. return QLatin1String(Constants::MINGW_TOOLCHAIN_ID);
  763. }
  764. QList<ToolChain *> Internal::MingwToolChainFactory::autoDetect()
  765. {
  766. // Compatibility to pre-2.2:
  767. // All Mingw toolchains that exist so far are either installed by the SDK itself (in
  768. // which case they most likely have debuggers set up) or were created when updating
  769. // from a previous Qt version. Add debugger in that case.
  770. foreach (ToolChain *tc, ToolChainManager::instance()->toolChains()) {
  771. if (tc->debuggerCommand().isEmpty() && tc->id().startsWith(QLatin1String(Constants::MINGW_TOOLCHAIN_ID)))
  772. static_cast<MingwToolChain *>(tc)
  773. ->setDebuggerCommand(ToolChainManager::instance()->defaultDebugger(tc->targetAbi()));
  774. }
  775. Abi ha = Abi::hostAbi();
  776. return autoDetectToolchains(QLatin1String("g++"), QStringList(),
  777. Abi(ha.architecture(), Abi::WindowsOS, Abi::WindowsMSysFlavor, Abi::PEFormat, ha.wordWidth()));
  778. }
  779. bool Internal::MingwToolChainFactory::canCreate()
  780. {
  781. return true;
  782. }
  783. ToolChain *Internal::MingwToolChainFactory::create()
  784. {
  785. return createToolChain(false);
  786. }
  787. bool Internal::MingwToolChainFactory::canRestore(const QVariantMap &data)
  788. {
  789. return idFromMap(data).startsWith(QLatin1String(Constants::MINGW_TOOLCHAIN_ID) + QLatin1Char(':'));
  790. }
  791. ToolChain *Internal::MingwToolChainFactory::restore(const QVariantMap &data)
  792. {
  793. MingwToolChain *tc = new MingwToolChain(false);
  794. if (tc->fromMap(data))
  795. return tc;
  796. delete tc;
  797. return 0;
  798. }
  799. GccToolChain *Internal::MingwToolChainFactory::createToolChain(bool autoDetect)
  800. {
  801. return new MingwToolChain(autoDetect);
  802. }
  803. // --------------------------------------------------------------------------
  804. // LinuxIccToolChain
  805. // --------------------------------------------------------------------------
  806. LinuxIccToolChain::LinuxIccToolChain(bool autodetect) :
  807. GccToolChain(QLatin1String(Constants::LINUXICC_TOOLCHAIN_ID), autodetect)
  808. { }
  809. QString LinuxIccToolChain::typeName() const
  810. {
  811. return Internal::LinuxIccToolChainFactory::tr("Linux ICC");
  812. }
  813. IOutputParser *LinuxIccToolChain::outputParser() const
  814. {
  815. return new LinuxIccParser;
  816. }
  817. QString LinuxIccToolChain::mkspec() const
  818. {
  819. return QLatin1String("linux-icc-") + QString::number(targetAbi().wordWidth());
  820. }
  821. ToolChain *LinuxIccToolChain::clone() const
  822. {
  823. return new LinuxIccToolChain(*this);
  824. }
  825. // --------------------------------------------------------------------------
  826. // LinuxIccToolChainFactory
  827. // --------------------------------------------------------------------------
  828. QString Internal::LinuxIccToolChainFactory::displayName() const
  829. {
  830. return tr("Linux ICC");
  831. }
  832. QString Internal::LinuxIccToolChainFactory::id() const
  833. {
  834. return QLatin1String(Constants::LINUXICC_TOOLCHAIN_ID);
  835. }
  836. QList<ToolChain *> Internal::LinuxIccToolChainFactory::autoDetect()
  837. {
  838. return autoDetectToolchains(QLatin1String("icpc"),
  839. QStringList(QLatin1String("gdb")),
  840. Abi::hostAbi());
  841. }
  842. ToolChain *Internal::LinuxIccToolChainFactory::create()
  843. {
  844. return createToolChain(false);
  845. }
  846. bool Internal::LinuxIccToolChainFactory::canRestore(const QVariantMap &data)
  847. {
  848. return idFromMap(data).startsWith(QLatin1String(Constants::LINUXICC_TOOLCHAIN_ID) + QLatin1Char(':'));
  849. }
  850. ToolChain *Internal::LinuxIccToolChainFactory::restore(const QVariantMap &data)
  851. {
  852. LinuxIccToolChain *tc = new LinuxIccToolChain(false);
  853. if (tc->fromMap(data))
  854. return tc;
  855. delete tc;
  856. return 0;
  857. }
  858. GccToolChain *Internal::LinuxIccToolChainFactory::createToolChain(bool autoDetect)
  859. {
  860. return new LinuxIccToolChain(autoDetect);
  861. }
  862. } // namespace ProjectExplorer
  863. // Unit tests:
  864. #ifdef WITH_TESTS
  865. # include "projectexplorer.h"
  866. # include <QTest>
  867. # include <QtCore/QUrl>
  868. namespace ProjectExplorer {
  869. void ProjectExplorerPlugin::testGccAbiGuessing_data()
  870. {
  871. QTest::addColumn<QString>("input");
  872. QTest::addColumn<QStringList>("abiList");
  873. QTest::newRow("invalid input")
  874. << QString::fromLatin1("Some text")
  875. << (QStringList());
  876. QTest::newRow("empty input")
  877. << QString::fromLatin1("")
  878. << (QStringList());
  879. QTest::newRow("broken input")
  880. << QString::fromLatin1("arm-none-foo-gnueabi")
  881. << (QStringList() << QLatin1String("arm-unknown-unknown-unknown-32bit"));
  882. QTest::newRow("totally broken input")
  883. << QString::fromLatin1("foo-bar-foo")
  884. << (QStringList());
  885. QTest::newRow("Maemo 1")
  886. << QString::fromLatin1("arm-none-linux-gnueabi")
  887. << (QStringList() << QLatin1String("arm-linux-generic-elf-32bit"));
  888. QTest::newRow("Linux 1")
  889. << QString::fromLatin1("i686-linux-gnu")
  890. << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit"));
  891. QTest::newRow("Linux 2")
  892. << QString::fromLatin1("i486-linux-gnu")
  893. << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit"));
  894. QTest::newRow("Linux 3")
  895. << QString::fromLatin1("x86_64-linux-gnu")
  896. << (QStringList() << QLatin1String("x86-linux-generic-elf-64bit")
  897. << QLatin1String("x86-linux-generic-elf-32bit"));
  898. QTest::newRow("Linux 4")
  899. << QString::fromLatin1("mipsel-linux-uclibc")
  900. << (QStringList() << QLatin1String("mips-linux-generic-elf-32bit"));
  901. QTest::newRow("Linux 5") // from QTCREATORBUG-4690
  902. << QString::fromLatin1("x86_64-redhat-linux6E")
  903. << (QStringList() << QLatin1String("x86-linux-generic-elf-64bit")
  904. << QLatin1String("x86-linux-generic-elf-32bit"));
  905. QTest::newRow("Linux 6") // from QTCREATORBUG-4690
  906. << QString::fromLatin1("x86_64-redhat-linux")
  907. << (QStringList() << QLatin1String("x86-linux-generic-elf-64bit")
  908. << QLatin1String("x86-linux-generic-elf-32bit"));
  909. QTest::newRow("Linux 7") // Meego
  910. << QString::fromLatin1("armv5tel-meego-linux-gnueabi")
  911. << (QStringList() << QLatin1String("arm-linux-meego-elf-32bit"));
  912. QTest::newRow("Linux 8")
  913. << QString::fromLatin1("armv5tl-montavista-linux-gnueabi")
  914. << (QStringList() << QLatin1String("arm-linux-generic-elf-32bit"));
  915. QTest::newRow("Linux 9")
  916. << QString::fromLatin1("arm-angstrom-linux-gnueabi")
  917. << (QStringList() << QLatin1String("arm-linux-generic-elf-32bit"));
  918. QTest::newRow("Mingw 1")
  919. << QString::fromLatin1("i686-w64-mingw32")
  920. << (QStringList() << QLatin1String("x86-windows-msys-pe-64bit")
  921. << QLatin1String("x86-windows-msys-pe-32bit"));
  922. QTest::newRow("Mingw 2")
  923. << QString::fromLatin1("mingw32")
  924. << (QStringList() << QLatin1String("x86-windows-msys-pe-32bit"));
  925. QTest::newRow("Clang 1: windows")
  926. << QString::fromLatin1("x86_64-pc-win32")
  927. << (QStringList() << QLatin1String("x86-windows-msys-pe-64bit")
  928. << QLatin1String("x86-windows-msys-pe-32bit"));
  929. QTest::newRow("Clang 1: linux")
  930. << QString::fromLatin1("x86_64-unknown-linux-gnu")
  931. << (QStringList() << QLatin1String("x86-linux-generic-elf-64bit")
  932. << QLatin1String("x86-linux-generic-elf-32bit"));
  933. QTest::newRow("Mac 1")
  934. << QString::fromLatin1("i686-apple-darwin10")
  935. << (QStringList() << QLatin1String("x86-macos-generic-mach_o-64bit")
  936. << QLatin1String("x86-macos-generic-mach_o-32bit")
  937. << QLatin1String("ppc-macos-generic-mach_o-64bit")
  938. << QLatin1String("ppc-macos-generic-mach_o-32bit"));
  939. QTest::newRow("Mac 2")
  940. << QString::fromLatin1("powerpc-apple-darwin10")
  941. << (QStringList() << QLatin1String("ppc-macos-generic-mach_o-64bit")
  942. << QLatin1String("ppc-macos-generic-mach_o-32bit")
  943. << QLatin1String("x86-macos-generic-mach_o-64bit")
  944. << QLatin1String("x86-macos-generic-mach_o-32bit"));
  945. QTest::newRow("Mac 3")
  946. << QString::fromLatin1("i686-apple-darwin9")
  947. << (QStringList() << QLatin1String("x86-macos-generic-mach_o-32bit")
  948. << QLatin1String("x86-macos-generic-mach_o-64bit")
  949. << QLatin1String("ppc-macos-generic-mach_o-32bit")
  950. << QLatin1String("ppc-macos-generic-mach_o-64bit"));
  951. QTest::newRow("Mac IOS")
  952. << QString::fromLatin1("arm-apple-darwin9")
  953. << (QStringList() << QLatin1String("arm-macos-generic-mach_o-32bit"));
  954. QTest::newRow("Intel 1")
  955. << QString::fromLatin1("86_64 x86_64 GNU/Linux")
  956. << (QStringList() << QLatin1String("x86-linux-generic-elf-64bit")
  957. << QLatin1String("x86-linux-generic-elf-32bit"));
  958. QTest::newRow("Symbian 1")
  959. << QString::fromLatin1("arm-none-symbianelf")
  960. << (QStringList() << QLatin1String("arm-symbian-device-elf-32bit"));
  961. QTest::newRow("FreeBSD 1")
  962. << QString::fromLatin1("i386-portbld-freebsd9.0")
  963. << (QStringList() << QLatin1String("x86-bsd-freebsd-elf-32bit"));
  964. QTest::newRow("FreeBSD 2")
  965. << QString::fromLatin1("i386-undermydesk-freebsd")
  966. << (QStringList() << QLatin1String("x86-bsd-freebsd-elf-32bit"));
  967. }
  968. void ProjectExplorerPlugin::testGccAbiGuessing()
  969. {
  970. QFETCH(QString, input);
  971. QFETCH(QStringList, abiList);
  972. QList<ProjectExplorer::Abi> al = guessGccAbi(input);
  973. QCOMPARE(al.count(), abiList.count());
  974. for (int i = 0; i < al.count(); ++i) {
  975. QCOMPARE(al.at(i).toString(), abiList.at(i));
  976. }
  977. }
  978. } // namespace ProjectExplorer
  979. #endif