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

/src/plugins/projectexplorer/gcctoolchain.cpp

https://github.com/CNOT/julia-studio
C++ | 1178 lines | 936 code | 169 blank | 73 comment | 277 complexity | 75116909f8cc8563d24e07f2dc480c98 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
  4. ** Contact: http://www.qt-project.org/legal
  5. **
  6. ** This file is part of Qt Creator.
  7. **
  8. ** Commercial License Usage
  9. ** Licensees holding valid commercial Qt licenses may use this file in
  10. ** accordance with the commercial license agreement provided with the
  11. ** Software or, alternatively, in accordance with the terms contained in
  12. ** a written agreement between you and Digia. For licensing terms and
  13. ** conditions see http://qt.digia.com/licensing. For further information
  14. ** use the contact form at http://qt.digia.com/contact-us.
  15. **
  16. ** GNU Lesser General Public License Usage
  17. ** Alternatively, this file may be used under the terms of the GNU Lesser
  18. ** General Public License version 2.1 as published by the Free Software
  19. ** Foundation and appearing in the file LICENSE.LGPL included in the
  20. ** packaging of this file. Please review the following information to
  21. ** ensure the GNU Lesser General Public License version 2.1 requirements
  22. ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  23. **
  24. ** In addition, as a special exception, Digia gives you certain additional
  25. ** rights. These rights are described in the Digia Qt LGPL Exception
  26. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  27. **
  28. ****************************************************************************/
  29. #include "gcctoolchain.h"
  30. #include "clangparser.h"
  31. #include "gcctoolchainfactories.h"
  32. #include "gccparser.h"
  33. #include "linuxiccparser.h"
  34. #include "projectexplorerconstants.h"
  35. #include "toolchainmanager.h"
  36. #include <utils/detailswidget.h>
  37. #include <utils/environment.h>
  38. #include <utils/hostosinfo.h>
  39. #include <utils/synchronousprocess.h>
  40. #include <utils/qtcassert.h>
  41. #include <utils/pathchooser.h>
  42. #include <QBuffer>
  43. #include <QCoreApplication>
  44. #include <QFileInfo>
  45. #include <QProcess>
  46. #include <QScopedPointer>
  47. #include <QComboBox>
  48. #include <QFormLayout>
  49. #include <QLabel>
  50. using namespace Utils;
  51. namespace ProjectExplorer {
  52. // --------------------------------------------------------------------------
  53. // Helpers:
  54. // --------------------------------------------------------------------------
  55. static const char compilerCommandKeyC[] = "ProjectExplorer.GccToolChain.Path";
  56. static const char targetAbiKeyC[] = "ProjectExplorer.GccToolChain.TargetAbi";
  57. static const char supportedAbisKeyC[] = "ProjectExplorer.GccToolChain.SupportedAbis";
  58. static const char LEGACY_MAEMO_ID[] = "Qt4ProjectManager.ToolChain.Maemo:";
  59. static QByteArray runGcc(const FileName &gcc, const QStringList &arguments, const QStringList &env)
  60. {
  61. if (gcc.isEmpty() || !gcc.toFileInfo().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=C"));
  67. cpp.setEnvironment(environment);
  68. cpp.start(gcc.toString(), arguments);
  69. if (!cpp.waitForStarted()) {
  70. qWarning("%s: Cannot start '%s': %s", Q_FUNC_INFO, qPrintable(gcc.toUserOutput()),
  71. qPrintable(cpp.errorString()));
  72. return QByteArray();
  73. }
  74. cpp.closeWriteChannel();
  75. if (!cpp.waitForFinished()) {
  76. SynchronousProcess::stopProcess(cpp);
  77. qWarning("%s: Timeout running '%s'.", Q_FUNC_INFO, qPrintable(gcc.toUserOutput()));
  78. return QByteArray();
  79. }
  80. if (cpp.exitStatus() != QProcess::NormalExit) {
  81. qWarning("%s: '%s' crashed.", Q_FUNC_INFO, qPrintable(gcc.toUserOutput()));
  82. return QByteArray();
  83. }
  84. return cpp.readAllStandardOutput() + '\n' + cpp.readAllStandardError();
  85. }
  86. static QByteArray gccPredefinedMacros(const FileName &gcc, const QStringList &args, const QStringList &env)
  87. {
  88. QStringList arguments;
  89. arguments << QLatin1String("-xc++")
  90. << QLatin1String("-E")
  91. << QLatin1String("-dM");
  92. foreach (const QString &a, args) {
  93. if (a == QLatin1String("-m128bit-long-double") || a == QLatin1String("-m32")
  94. || a == QLatin1String("-m3dnow") || a == QLatin1String("-m3dnowa")
  95. || a == QLatin1String("-m64") || a == QLatin1String("-m96bit-long-double")
  96. || a == QLatin1String("-mabm") || a == QLatin1String("-maes")
  97. || a.startsWith(QLatin1String("-march=")) || a == QLatin1String("-mavx")
  98. || a.startsWith(QLatin1String("-masm=")) || a == QLatin1String("-mcx16")
  99. || a == QLatin1String("-mfma") || a == QLatin1String("-mfma4")
  100. || a == QLatin1String("-mlwp") || a == QLatin1String("-mpclmul")
  101. || a == QLatin1String("-mpopcnt") || a == QLatin1String("-msse")
  102. || a == QLatin1String("-msse2") || a == QLatin1String("-msse2avx")
  103. || a == QLatin1String("-msse3") || a == QLatin1String("-msse4")
  104. || a == QLatin1String("-msse4.1") || a == QLatin1String("-msse4.2")
  105. || a == QLatin1String("-msse4a") || a == QLatin1String("-mssse3")
  106. || a.startsWith(QLatin1String("-mtune=")) || a == QLatin1String("-mxop")
  107. || a == QLatin1String("-Os") || a == QLatin1String("-O0") || a == QLatin1String("-O1")
  108. || a == QLatin1String("-O2") || a == QLatin1String("-O3")
  109. || a == QLatin1String("-ffinite-math-only") || a == QLatin1String("-fshort-double")
  110. || a == QLatin1String("-fshort-wchar") || a == QLatin1String("-fsignaling-nans")
  111. || a.startsWith(QLatin1String("-std=")) || a.startsWith(QLatin1String("-specs="))
  112. || a == QLatin1String("-ansi")
  113. || a.startsWith(QLatin1String("-D")) || a.startsWith(QLatin1String("-U"))
  114. || a == QLatin1String("-undef"))
  115. arguments << a;
  116. }
  117. arguments << QLatin1String("-");
  118. QByteArray predefinedMacros = runGcc(gcc, arguments, env);
  119. if (Utils::HostOsInfo::isMacHost()) {
  120. // Turn off flag indicating Apple's blocks support
  121. const QByteArray blocksDefine("#define __BLOCKS__ 1");
  122. const QByteArray blocksUndefine("#undef __BLOCKS__");
  123. const int idx = predefinedMacros.indexOf(blocksDefine);
  124. if (idx != -1) {
  125. predefinedMacros.replace(idx, blocksDefine.length(), blocksUndefine);
  126. }
  127. // Define __strong and __weak (used for Apple's GC extension of C) to be empty
  128. predefinedMacros.append("#define __strong\n");
  129. predefinedMacros.append("#define __weak\n");
  130. }
  131. return predefinedMacros;
  132. }
  133. QList<HeaderPath> GccToolChain::gccHeaderPaths(const FileName &gcc, const QStringList &env, const FileName &sysrootPath)
  134. {
  135. QList<HeaderPath> systemHeaderPaths;
  136. QStringList arguments;
  137. if (!sysrootPath.isEmpty())
  138. arguments.append(QString::fromLatin1("--sysroot=%1").arg(sysrootPath.toString()));
  139. arguments << QLatin1String("-xc++")
  140. << QLatin1String("-E")
  141. << QLatin1String("-v")
  142. << QLatin1String("-");
  143. QByteArray line;
  144. QByteArray data = runGcc(gcc, arguments, env);
  145. QBuffer cpp(&data);
  146. cpp.open(QIODevice::ReadOnly);
  147. while (cpp.canReadLine()) {
  148. line = cpp.readLine();
  149. if (line.startsWith("#include"))
  150. break;
  151. }
  152. if (!line.isEmpty() && line.startsWith("#include")) {
  153. HeaderPath::Kind kind = HeaderPath::UserHeaderPath;
  154. while (cpp.canReadLine()) {
  155. line = cpp.readLine();
  156. if (line.startsWith("#include")) {
  157. kind = HeaderPath::GlobalHeaderPath;
  158. } else if (! line.isEmpty() && QChar(QLatin1Char(line.at(0))).isSpace()) {
  159. HeaderPath::Kind thisHeaderKind = kind;
  160. line = line.trimmed();
  161. const int index = line.indexOf(" (framework directory)");
  162. if (index != -1) {
  163. line.truncate(index);
  164. thisHeaderKind = HeaderPath::FrameworkHeaderPath;
  165. }
  166. systemHeaderPaths.append(HeaderPath(QFile::decodeName(line), thisHeaderKind));
  167. } else if (line.startsWith("End of search list.")) {
  168. break;
  169. } else {
  170. qWarning("%s: Ignoring line: %s", __FUNCTION__, line.constData());
  171. }
  172. }
  173. }
  174. return systemHeaderPaths;
  175. }
  176. static QList<Abi> guessGccAbi(const QString &m)
  177. {
  178. QList<Abi> abiList;
  179. QString machine = m.toLower();
  180. if (machine.isEmpty())
  181. return abiList;
  182. QStringList parts = machine.split(QRegExp(QLatin1String("[ /-]")));
  183. Abi::Architecture arch = Abi::UnknownArchitecture;
  184. Abi::OS os = Abi::UnknownOS;
  185. Abi::OSFlavor flavor = Abi::UnknownFlavor;
  186. Abi::BinaryFormat format = Abi::UnknownFormat;
  187. int width = 0;
  188. int unknownCount = 0;
  189. foreach (const QString &p, parts) {
  190. if (p == QLatin1String("unknown") || p == QLatin1String("pc") || p == QLatin1String("none")
  191. || p == QLatin1String("gnu") || p == QLatin1String("uclibc")
  192. || p == QLatin1String("86_64") || p == QLatin1String("redhat") || p == QLatin1String("gnueabi")) {
  193. continue;
  194. } else if (p == QLatin1String("i386") || p == QLatin1String("i486") || p == QLatin1String("i586")
  195. || p == QLatin1String("i686") || p == QLatin1String("x86")) {
  196. arch = Abi::X86Architecture;
  197. width = 32;
  198. } else if (p.startsWith(QLatin1String("arm"))) {
  199. arch = Abi::ArmArchitecture;
  200. width = 32;
  201. } else if (p == QLatin1String("mipsel")) {
  202. arch = Abi::MipsArchitecture;
  203. width = 32;
  204. } else if (p == QLatin1String("x86_64") || p == QLatin1String("amd64")) {
  205. arch = Abi::X86Architecture;
  206. width = 64;
  207. } else if (p == QLatin1String("powerpc")) {
  208. arch = Abi::PowerPCArchitecture;
  209. } else if (p == QLatin1String("w64")) {
  210. width = 64;
  211. } else if (p == QLatin1String("linux") || p == QLatin1String("linux6e")) {
  212. os = Abi::LinuxOS;
  213. if (flavor == Abi::UnknownFlavor)
  214. flavor = Abi::GenericLinuxFlavor;
  215. format = Abi::ElfFormat;
  216. } else if (p.startsWith(QLatin1String("freebsd"))) {
  217. os = Abi::BsdOS;
  218. if (flavor == Abi::UnknownFlavor)
  219. flavor = Abi::FreeBsdFlavor;
  220. format = Abi::ElfFormat;
  221. } else if (p == QLatin1String("mingw32") || p == QLatin1String("win32") || p == QLatin1String("mingw32msvc")) {
  222. arch = Abi::X86Architecture;
  223. os = Abi::WindowsOS;
  224. flavor = Abi::WindowsMSysFlavor;
  225. format = Abi::PEFormat;
  226. if (width == 0)
  227. width = 32;
  228. } else if (p == QLatin1String("apple")) {
  229. os = Abi::MacOS;
  230. flavor = Abi::GenericMacFlavor;
  231. format = Abi::MachOFormat;
  232. } else if (p == QLatin1String("darwin10")) {
  233. width = 64;
  234. } else if (p == QLatin1String("darwin9")) {
  235. width = 32;
  236. } else if (p == QLatin1String("gnueabi")) {
  237. format = Abi::ElfFormat;
  238. } else {
  239. ++unknownCount;
  240. }
  241. }
  242. if (unknownCount == parts.count())
  243. return abiList;
  244. if (os == Abi::MacOS && arch != Abi::ArmArchitecture) {
  245. // Apple does PPC and x86!
  246. abiList << Abi(arch, os, flavor, format, width);
  247. abiList << Abi(arch, os, flavor, format, width == 64 ? 32 : 64);
  248. abiList << Abi(arch == Abi::X86Architecture ? Abi::PowerPCArchitecture : Abi::X86Architecture, os, flavor, format, width);
  249. abiList << Abi(arch == Abi::X86Architecture ? Abi::PowerPCArchitecture : Abi::X86Architecture, os, flavor, format, width == 64 ? 32 : 64);
  250. } else if (width == 64) {
  251. abiList << Abi(arch, os, flavor, format, width);
  252. abiList << Abi(arch, os, flavor, format, 32);
  253. } else {
  254. abiList << Abi(arch, os, flavor, format, width);
  255. }
  256. return abiList;
  257. }
  258. static QList<Abi> guessGccAbi(const FileName &path, const QStringList &env)
  259. {
  260. if (path.isEmpty())
  261. return QList<Abi>();
  262. QStringList arguments(QLatin1String("-dumpmachine"));
  263. QString machine = QString::fromLocal8Bit(runGcc(path, arguments, env)).trimmed();
  264. return guessGccAbi(machine);
  265. }
  266. static QString gccVersion(const FileName &path, const QStringList &env)
  267. {
  268. QStringList arguments(QLatin1String("-dumpversion"));
  269. return QString::fromLocal8Bit(runGcc(path, arguments, env)).trimmed();
  270. }
  271. // --------------------------------------------------------------------------
  272. // GccToolChain
  273. // --------------------------------------------------------------------------
  274. GccToolChain::GccToolChain(bool autodetect) :
  275. ToolChain(QLatin1String(Constants::GCC_TOOLCHAIN_ID), autodetect)
  276. { }
  277. GccToolChain::GccToolChain(const QString &id, bool autodetect) :
  278. ToolChain(id, autodetect)
  279. { }
  280. GccToolChain::GccToolChain(const GccToolChain &tc) :
  281. ToolChain(tc),
  282. m_predefinedMacros(tc.predefinedMacros(QStringList())),
  283. m_compilerCommand(tc.compilerCommand()),
  284. m_targetAbi(tc.m_targetAbi),
  285. m_supportedAbis(tc.m_supportedAbis),
  286. m_headerPaths(tc.m_headerPaths),
  287. m_version(tc.m_version)
  288. { }
  289. QString GccToolChain::defaultDisplayName() const
  290. {
  291. if (!m_targetAbi.isValid())
  292. return typeDisplayName();
  293. return QString::fromLatin1("%1 (%2 %3)").arg(typeDisplayName(),
  294. Abi::toString(m_targetAbi.architecture()),
  295. Abi::toString(m_targetAbi.wordWidth()));
  296. }
  297. QString GccToolChain::type() const
  298. {
  299. return QLatin1String("gcc");
  300. }
  301. QString GccToolChain::typeDisplayName() const
  302. {
  303. return Internal::GccToolChainFactory::tr("GCC");
  304. }
  305. Abi GccToolChain::targetAbi() const
  306. {
  307. return m_targetAbi;
  308. }
  309. QString GccToolChain::version() const
  310. {
  311. if (m_version.isEmpty())
  312. m_version = detectVersion();
  313. return m_version;
  314. }
  315. void GccToolChain::setTargetAbi(const Abi &abi)
  316. {
  317. if (abi == m_targetAbi)
  318. return;
  319. m_targetAbi = abi;
  320. toolChainUpdated();
  321. }
  322. QList<Abi> GccToolChain::supportedAbis() const
  323. {
  324. return m_supportedAbis;
  325. }
  326. bool GccToolChain::isValid() const
  327. {
  328. return !m_compilerCommand.isNull();
  329. }
  330. QByteArray GccToolChain::predefinedMacros(const QStringList &cxxflags) const
  331. {
  332. if (m_predefinedMacros.isEmpty()) {
  333. // Using a clean environment breaks ccache/distcc/etc.
  334. Environment env = Environment::systemEnvironment();
  335. addToEnvironment(env);
  336. m_predefinedMacros = gccPredefinedMacros(m_compilerCommand, cxxflags, env.toStringList());
  337. }
  338. return m_predefinedMacros;
  339. }
  340. ToolChain::CompilerFlags GccToolChain::compilerFlags(const QStringList &cxxflags) const
  341. {
  342. if (cxxflags.contains("-std=c++0x") || cxxflags.contains("-std=gnu++0x") ||
  343. cxxflags.contains("-std=c++11") || cxxflags.contains("-std=gnu++11"))
  344. return STD_CXX11;
  345. return NO_FLAGS;
  346. }
  347. QList<HeaderPath> GccToolChain::systemHeaderPaths(const Utils::FileName &sysRoot) const
  348. {
  349. if (m_headerPaths.isEmpty()) {
  350. // Using a clean environment breaks ccache/distcc/etc.
  351. Environment env = Environment::systemEnvironment();
  352. addToEnvironment(env);
  353. m_headerPaths = gccHeaderPaths(m_compilerCommand, env.toStringList(), sysRoot);
  354. }
  355. return m_headerPaths;
  356. }
  357. void GccToolChain::addToEnvironment(Environment &env) const
  358. {
  359. if (!m_compilerCommand.isEmpty()) {
  360. FileName path = m_compilerCommand.parentDir();
  361. env.prependOrSetPath(path.toString());
  362. }
  363. }
  364. QList<FileName> GccToolChain::suggestedMkspecList() const
  365. {
  366. Abi abi = targetAbi();
  367. Abi host = Abi::hostAbi();
  368. // Cross compile: Leave the mkspec alone!
  369. if (abi.architecture() != host.architecture()
  370. || abi.os() != host.os()
  371. || abi.osFlavor() != host.osFlavor()) // Note: This can fail:-(
  372. return QList<FileName>();
  373. if (abi.os() == Abi::MacOS) {
  374. QString v = version();
  375. // prefer versioned g++ on mac. This is required to enable building for older Mac OS versions
  376. if (v.startsWith(QLatin1String("4.0")) && m_compilerCommand.endsWith(QLatin1String("-4.0")))
  377. return QList<FileName>() << FileName::fromString(QLatin1String("macx-g++40"));
  378. if (v.startsWith(QLatin1String("4.2")) && m_compilerCommand.endsWith(QLatin1String("-4.2")))
  379. return QList<FileName>() << FileName::fromString(QLatin1String("macx-g++42"));
  380. return QList<FileName>() << FileName::fromString(QLatin1String("macx-g++"));
  381. }
  382. if (abi.os() == Abi::LinuxOS) {
  383. if (abi.osFlavor() != Abi::GenericLinuxFlavor)
  384. return QList<FileName>(); // most likely not a desktop, so leave the mkspec alone.
  385. if (abi.wordWidth() == host.wordWidth()) {
  386. // no need to explicitly set the word width, but provide that mkspec anyway to make sure
  387. // that the correct compiler is picked if a mkspec with a wordwidth is given.
  388. return QList<FileName>() << FileName::fromString(QLatin1String("linux-g++"))
  389. << FileName::fromString(QLatin1String("linux-g++-") + QString::number(m_targetAbi.wordWidth()));
  390. }
  391. return QList<FileName>() << FileName::fromString(QLatin1String("linux-g++-") + QString::number(m_targetAbi.wordWidth()));
  392. }
  393. if (abi.os() == Abi::BsdOS && abi.osFlavor() == Abi::FreeBsdFlavor)
  394. return QList<FileName>() << FileName::fromString(QLatin1String("freebsd-g++"));
  395. return QList<FileName>();
  396. }
  397. QString GccToolChain::makeCommand(const Utils::Environment &environment) const
  398. {
  399. QString make = QLatin1String("make");
  400. QString tmp = environment.searchInPath(make);
  401. return tmp.isEmpty() ? make : tmp;
  402. }
  403. IOutputParser *GccToolChain::outputParser() const
  404. {
  405. return new GccParser;
  406. }
  407. void GccToolChain::setCompilerCommand(const FileName &path)
  408. {
  409. if (path == m_compilerCommand)
  410. return;
  411. bool resetDisplayName = displayName() == defaultDisplayName();
  412. m_compilerCommand = path;
  413. Abi currentAbi = m_targetAbi;
  414. m_supportedAbis = detectSupportedAbis();
  415. m_targetAbi = Abi();
  416. if (!m_supportedAbis.isEmpty()) {
  417. if (m_supportedAbis.contains(currentAbi))
  418. m_targetAbi = currentAbi;
  419. else
  420. m_targetAbi = m_supportedAbis.at(0);
  421. }
  422. if (resetDisplayName)
  423. setDisplayName(defaultDisplayName()); // calls toolChainUpdated()!
  424. else
  425. toolChainUpdated();
  426. }
  427. FileName GccToolChain::compilerCommand() const
  428. {
  429. return m_compilerCommand;
  430. }
  431. ToolChain *GccToolChain::clone() const
  432. {
  433. return new GccToolChain(*this);
  434. }
  435. QVariantMap GccToolChain::toMap() const
  436. {
  437. QVariantMap data = ToolChain::toMap();
  438. data.insert(QLatin1String(compilerCommandKeyC), m_compilerCommand.toString());
  439. data.insert(QLatin1String(targetAbiKeyC), m_targetAbi.toString());
  440. QStringList abiList;
  441. foreach (const Abi &a, m_supportedAbis)
  442. abiList.append(a.toString());
  443. data.insert(QLatin1String(supportedAbisKeyC), abiList);
  444. return data;
  445. }
  446. bool GccToolChain::fromMap(const QVariantMap &data)
  447. {
  448. if (!ToolChain::fromMap(data))
  449. return false;
  450. m_compilerCommand = FileName::fromString(data.value(QLatin1String(compilerCommandKeyC)).toString());
  451. m_targetAbi = Abi(data.value(QLatin1String(targetAbiKeyC)).toString());
  452. QStringList abiList = data.value(QLatin1String(supportedAbisKeyC)).toStringList();
  453. m_supportedAbis.clear();
  454. foreach (const QString &a, abiList) {
  455. Abi abi(a);
  456. if (!abi.isValid())
  457. continue;
  458. m_supportedAbis.append(abi);
  459. }
  460. return true;
  461. }
  462. bool GccToolChain::operator ==(const ToolChain &other) const
  463. {
  464. if (!ToolChain::operator ==(other))
  465. return false;
  466. const GccToolChain *gccTc = static_cast<const GccToolChain *>(&other);
  467. return m_compilerCommand == gccTc->m_compilerCommand && m_targetAbi == gccTc->m_targetAbi;
  468. }
  469. ToolChainConfigWidget *GccToolChain::configurationWidget()
  470. {
  471. return new Internal::GccToolChainConfigWidget(this);
  472. }
  473. void GccToolChain::updateSupportedAbis() const
  474. {
  475. if (m_supportedAbis.isEmpty())
  476. m_supportedAbis = detectSupportedAbis();
  477. }
  478. QList<Abi> GccToolChain::detectSupportedAbis() const
  479. {
  480. Environment env = Environment::systemEnvironment();
  481. addToEnvironment(env);
  482. return guessGccAbi(m_compilerCommand, env.toStringList());
  483. }
  484. QString GccToolChain::detectVersion() const
  485. {
  486. Environment env = Environment::systemEnvironment();
  487. addToEnvironment(env);
  488. return gccVersion(m_compilerCommand, env.toStringList());
  489. }
  490. // --------------------------------------------------------------------------
  491. // GccToolChainFactory
  492. // --------------------------------------------------------------------------
  493. QString Internal::GccToolChainFactory::displayName() const
  494. {
  495. return tr("GCC");
  496. }
  497. QString Internal::GccToolChainFactory::id() const
  498. {
  499. return QLatin1String(Constants::GCC_TOOLCHAIN_ID);
  500. }
  501. bool Internal::GccToolChainFactory::canCreate()
  502. {
  503. return true;
  504. }
  505. ToolChain *Internal::GccToolChainFactory::create()
  506. {
  507. return createToolChain(false);
  508. }
  509. QList<ToolChain *> Internal::GccToolChainFactory::autoDetect()
  510. {
  511. QList<ToolChain *> tcs;
  512. if (Utils::HostOsInfo::isMacHost()) {
  513. // Old mac compilers needed to support macx-gccXY mkspecs:
  514. tcs.append(autoDetectToolchains(QLatin1String("g++-4.0"), Abi::hostAbi()));
  515. tcs.append(autoDetectToolchains(QLatin1String("g++-4.2"), Abi::hostAbi()));
  516. }
  517. tcs.append(autoDetectToolchains(QLatin1String("g++"), Abi::hostAbi()));
  518. return tcs;
  519. }
  520. // Used by the ToolChainManager to restore user-generated tool chains
  521. bool Internal::GccToolChainFactory::canRestore(const QVariantMap &data)
  522. {
  523. const QString id = idFromMap(data);
  524. return id.startsWith(QLatin1String(Constants::GCC_TOOLCHAIN_ID) + QLatin1Char(':'))
  525. || id.startsWith(QLatin1String(LEGACY_MAEMO_ID));
  526. }
  527. ToolChain *Internal::GccToolChainFactory::restore(const QVariantMap &data)
  528. {
  529. GccToolChain *tc = new GccToolChain(false);
  530. // Updating from 2.5:
  531. QVariantMap updated = data;
  532. QString id = idFromMap(updated);
  533. if (id.startsWith(LEGACY_MAEMO_ID)) {
  534. id = QString::fromLatin1(Constants::GCC_TOOLCHAIN_ID).append(id.mid(id.indexOf(QLatin1Char(':'))));
  535. idToMap(updated, id);
  536. autoDetectionToMap(updated, false);
  537. }
  538. if (tc->fromMap(updated))
  539. return tc;
  540. delete tc;
  541. return 0;
  542. }
  543. GccToolChain *Internal::GccToolChainFactory::createToolChain(bool autoDetect)
  544. {
  545. return new GccToolChain(autoDetect);
  546. }
  547. QList<ToolChain *> Internal::GccToolChainFactory::autoDetectToolchains(const QString &compiler,
  548. const Abi &requiredAbi)
  549. {
  550. QList<ToolChain *> result;
  551. const Environment systemEnvironment = Environment::systemEnvironment();
  552. const FileName compilerPath = FileName::fromString(systemEnvironment.searchInPath(compiler));
  553. if (compilerPath.isEmpty())
  554. return result;
  555. QList<Abi> abiList = guessGccAbi(compilerPath, systemEnvironment.toStringList());
  556. if (!abiList.contains(requiredAbi)) {
  557. if (requiredAbi.wordWidth() != 64
  558. || !abiList.contains(Abi(requiredAbi.architecture(), requiredAbi.os(), requiredAbi.osFlavor(),
  559. requiredAbi.binaryFormat(), 32)))
  560. return result;
  561. }
  562. foreach (const Abi &abi, abiList) {
  563. QScopedPointer<GccToolChain> tc(createToolChain(true));
  564. if (tc.isNull())
  565. return result;
  566. tc->setCompilerCommand(compilerPath);
  567. tc->setTargetAbi(abi);
  568. tc->setDisplayName(tc->defaultDisplayName()); // reset displayname
  569. result.append(tc.take());
  570. }
  571. return result;
  572. }
  573. // --------------------------------------------------------------------------
  574. // GccToolChainConfigWidget
  575. // --------------------------------------------------------------------------
  576. Internal::GccToolChainConfigWidget::GccToolChainConfigWidget(GccToolChain *tc) :
  577. ToolChainConfigWidget(tc),
  578. m_compilerCommand(new PathChooser),
  579. m_abiWidget(new AbiWidget),
  580. m_isReadOnly(false)
  581. {
  582. Q_ASSERT(tc);
  583. const QStringList gnuVersionArgs = QStringList(QLatin1String("--version"));
  584. m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand);
  585. m_compilerCommand->setCommandVersionArguments(gnuVersionArgs);
  586. m_mainLayout->addRow(tr("&Compiler path:"), m_compilerCommand);
  587. m_mainLayout->addRow(tr("&ABI:"), m_abiWidget);
  588. m_abiWidget->setEnabled(false);
  589. addErrorLabel();
  590. setFromToolchain();
  591. connect(m_compilerCommand, SIGNAL(changed(QString)), this, SLOT(handleCompilerCommandChange()));
  592. connect(m_abiWidget, SIGNAL(abiChanged()), this, SIGNAL(dirty()));
  593. }
  594. void Internal::GccToolChainConfigWidget::applyImpl()
  595. {
  596. if (toolChain()->isAutoDetected())
  597. return;
  598. GccToolChain *tc = static_cast<GccToolChain *>(toolChain());
  599. Q_ASSERT(tc);
  600. QString displayName = tc->displayName();
  601. tc->setCompilerCommand(m_compilerCommand->fileName());
  602. tc->setTargetAbi(m_abiWidget->currentAbi());
  603. tc->setDisplayName(displayName); // reset display name
  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_compilerCommand->setFileName(tc->compilerCommand());
  611. m_abiWidget->setAbis(tc->supportedAbis(), tc->targetAbi());
  612. if (!m_isReadOnly && !m_compilerCommand->path().isEmpty())
  613. m_abiWidget->setEnabled(true);
  614. blockSignals(blocked);
  615. }
  616. bool Internal::GccToolChainConfigWidget::isDirtyImpl() const
  617. {
  618. GccToolChain *tc = static_cast<GccToolChain *>(toolChain());
  619. Q_ASSERT(tc);
  620. return m_compilerCommand->fileName() != tc->compilerCommand()
  621. || m_abiWidget->currentAbi() != tc->targetAbi();
  622. }
  623. void Internal::GccToolChainConfigWidget::makeReadOnlyImpl()
  624. {
  625. m_compilerCommand->setEnabled(false);
  626. m_abiWidget->setEnabled(false);
  627. m_isReadOnly = true;
  628. }
  629. void Internal::GccToolChainConfigWidget::handleCompilerCommandChange()
  630. {
  631. FileName path = m_compilerCommand->fileName();
  632. QList<Abi> abiList;
  633. bool haveCompiler = false;
  634. if (!path.isEmpty()) {
  635. QFileInfo fi(path.toFileInfo());
  636. haveCompiler = fi.isExecutable() && fi.isFile();
  637. }
  638. if (haveCompiler)
  639. abiList = guessGccAbi(path, Environment::systemEnvironment().toStringList());
  640. m_abiWidget->setEnabled(haveCompiler);
  641. Abi currentAbi = m_abiWidget->currentAbi();
  642. m_abiWidget->setAbis(abiList, abiList.contains(currentAbi) ? currentAbi : Abi());
  643. emit dirty();
  644. }
  645. // --------------------------------------------------------------------------
  646. // ClangToolChain
  647. // --------------------------------------------------------------------------
  648. ClangToolChain::ClangToolChain(bool autodetect) :
  649. GccToolChain(QLatin1String(Constants::CLANG_TOOLCHAIN_ID), autodetect)
  650. { }
  651. QString ClangToolChain::type() const
  652. {
  653. return QLatin1String("clang");
  654. }
  655. QString ClangToolChain::typeDisplayName() const
  656. {
  657. return Internal::ClangToolChainFactory::tr("Clang");
  658. }
  659. QString ClangToolChain::makeCommand(const Utils::Environment &environment) const
  660. {
  661. QStringList makes;
  662. if (Utils::HostOsInfo::isWindowsHost()) {
  663. makes << QLatin1String("mingw32-make.exe");
  664. makes << QLatin1String("make.exe");
  665. } else {
  666. makes << QLatin1String("make");
  667. }
  668. QString tmp;
  669. foreach (const QString &make, makes) {
  670. tmp = environment.searchInPath(make);
  671. if (!tmp.isEmpty())
  672. return tmp;
  673. }
  674. return makes.first();
  675. }
  676. QList<FileName> ClangToolChain::suggestedMkspecList() const
  677. {
  678. Abi abi = targetAbi();
  679. if (abi.os() == Abi::MacOS)
  680. return QList<FileName>()
  681. << FileName::fromString(QLatin1String("macx-clang"))
  682. << FileName::fromString(QLatin1String("unsupported/macx-clang"));
  683. else if (abi.os() == Abi::LinuxOS)
  684. return QList<FileName>()
  685. << FileName::fromString(QLatin1String("linux-clang"))
  686. << FileName::fromString(QLatin1String("unsupported/linux-clang"));
  687. return QList<FileName>(); // Note: Not supported by Qt yet, so default to the mkspec the Qt was build with
  688. }
  689. IOutputParser *ClangToolChain::outputParser() const
  690. {
  691. return new ClangParser;
  692. }
  693. ToolChain *ClangToolChain::clone() const
  694. {
  695. return new ClangToolChain(*this);
  696. }
  697. // --------------------------------------------------------------------------
  698. // ClangToolChainFactory
  699. // --------------------------------------------------------------------------
  700. QString Internal::ClangToolChainFactory::displayName() const
  701. {
  702. return tr("Clang");
  703. }
  704. QString Internal::ClangToolChainFactory::id() const
  705. {
  706. return QLatin1String(Constants::CLANG_TOOLCHAIN_ID);
  707. }
  708. QList<ToolChain *> Internal::ClangToolChainFactory::autoDetect()
  709. {
  710. Abi ha = Abi::hostAbi();
  711. return autoDetectToolchains(QLatin1String("clang++"), ha);
  712. }
  713. bool Internal::ClangToolChainFactory::canCreate()
  714. {
  715. return true;
  716. }
  717. ToolChain *Internal::ClangToolChainFactory::create()
  718. {
  719. return createToolChain(false);
  720. }
  721. bool Internal::ClangToolChainFactory::canRestore(const QVariantMap &data)
  722. {
  723. return idFromMap(data).startsWith(QLatin1String(Constants::CLANG_TOOLCHAIN_ID) + QLatin1Char(':'));
  724. }
  725. ToolChain *Internal::ClangToolChainFactory::restore(const QVariantMap &data)
  726. {
  727. ClangToolChain *tc = new ClangToolChain(false);
  728. if (tc->fromMap(data))
  729. return tc;
  730. delete tc;
  731. return 0;
  732. }
  733. GccToolChain *Internal::ClangToolChainFactory::createToolChain(bool autoDetect)
  734. {
  735. return new ClangToolChain(autoDetect);
  736. }
  737. // --------------------------------------------------------------------------
  738. // MingwToolChain
  739. // --------------------------------------------------------------------------
  740. MingwToolChain::MingwToolChain(bool autodetect) :
  741. GccToolChain(QLatin1String(Constants::MINGW_TOOLCHAIN_ID), autodetect)
  742. { }
  743. QString MingwToolChain::type() const
  744. {
  745. return QLatin1String("mingw");
  746. }
  747. QString MingwToolChain::typeDisplayName() const
  748. {
  749. return Internal::MingwToolChainFactory::tr("MinGW");
  750. }
  751. QList<FileName> MingwToolChain::suggestedMkspecList() const
  752. {
  753. if (Utils::HostOsInfo::isWindowsHost())
  754. return QList<FileName>() << FileName::fromString(QLatin1String("win32-g++"));
  755. if (Utils::HostOsInfo::isLinuxHost()) {
  756. if (version().startsWith("4.6."))
  757. return QList<FileName>()
  758. << FileName::fromString(QLatin1String("win32-g++-4.6-cross"))
  759. << FileName::fromString(QLatin1String("unsupported/win32-g++-4.6-cross"));
  760. else
  761. return QList<FileName>()
  762. << FileName::fromString(QLatin1String("win32-g++-cross"))
  763. << FileName::fromString(QLatin1String("unsupported/win32-g++-cross"));
  764. }
  765. return QList<FileName>();
  766. }
  767. QString MingwToolChain::makeCommand(const Utils::Environment &environment) const
  768. {
  769. QStringList makes;
  770. if (Utils::HostOsInfo::isWindowsHost()) {
  771. makes << QLatin1String("mingw32-make.exe");
  772. makes << QLatin1String("make.exe");
  773. } else {
  774. makes << QLatin1String("make");
  775. }
  776. QString tmp;
  777. foreach (const QString &make, makes) {
  778. tmp = environment.searchInPath(make);
  779. if (!tmp.isEmpty())
  780. return tmp;
  781. }
  782. return makes.first();
  783. }
  784. ToolChain *MingwToolChain::clone() const
  785. {
  786. return new MingwToolChain(*this);
  787. }
  788. // --------------------------------------------------------------------------
  789. // MingwToolChainFactory
  790. // --------------------------------------------------------------------------
  791. QString Internal::MingwToolChainFactory::displayName() const
  792. {
  793. return tr("MinGW");
  794. }
  795. QString Internal::MingwToolChainFactory::id() const
  796. {
  797. return QLatin1String(Constants::MINGW_TOOLCHAIN_ID);
  798. }
  799. QList<ToolChain *> Internal::MingwToolChainFactory::autoDetect()
  800. {
  801. Abi ha = Abi::hostAbi();
  802. return autoDetectToolchains(QLatin1String("g++"),
  803. Abi(ha.architecture(), Abi::WindowsOS, Abi::WindowsMSysFlavor, Abi::PEFormat, ha.wordWidth()));
  804. }
  805. bool Internal::MingwToolChainFactory::canCreate()
  806. {
  807. return true;
  808. }
  809. ToolChain *Internal::MingwToolChainFactory::create()
  810. {
  811. return createToolChain(false);
  812. }
  813. bool Internal::MingwToolChainFactory::canRestore(const QVariantMap &data)
  814. {
  815. return idFromMap(data).startsWith(QLatin1String(Constants::MINGW_TOOLCHAIN_ID) + QLatin1Char(':'));
  816. }
  817. ToolChain *Internal::MingwToolChainFactory::restore(const QVariantMap &data)
  818. {
  819. MingwToolChain *tc = new MingwToolChain(false);
  820. if (tc->fromMap(data))
  821. return tc;
  822. delete tc;
  823. return 0;
  824. }
  825. GccToolChain *Internal::MingwToolChainFactory::createToolChain(bool autoDetect)
  826. {
  827. return new MingwToolChain(autoDetect);
  828. }
  829. // --------------------------------------------------------------------------
  830. // LinuxIccToolChain
  831. // --------------------------------------------------------------------------
  832. LinuxIccToolChain::LinuxIccToolChain(bool autodetect) :
  833. GccToolChain(QLatin1String(Constants::LINUXICC_TOOLCHAIN_ID), autodetect)
  834. { }
  835. QString LinuxIccToolChain::type() const
  836. {
  837. return QLatin1String("icc");
  838. }
  839. QString LinuxIccToolChain::typeDisplayName() const
  840. {
  841. return Internal::LinuxIccToolChainFactory::tr("Linux ICC");
  842. }
  843. IOutputParser *LinuxIccToolChain::outputParser() const
  844. {
  845. return new LinuxIccParser;
  846. }
  847. QList<FileName> LinuxIccToolChain::suggestedMkspecList() const
  848. {
  849. return QList<FileName>()
  850. << FileName::fromString(QLatin1String("linux-icc-") + QString::number(targetAbi().wordWidth()));
  851. }
  852. ToolChain *LinuxIccToolChain::clone() const
  853. {
  854. return new LinuxIccToolChain(*this);
  855. }
  856. // --------------------------------------------------------------------------
  857. // LinuxIccToolChainFactory
  858. // --------------------------------------------------------------------------
  859. QString Internal::LinuxIccToolChainFactory::displayName() const
  860. {
  861. return tr("Linux ICC");
  862. }
  863. QString Internal::LinuxIccToolChainFactory::id() const
  864. {
  865. return QLatin1String(Constants::LINUXICC_TOOLCHAIN_ID);
  866. }
  867. QList<ToolChain *> Internal::LinuxIccToolChainFactory::autoDetect()
  868. {
  869. return autoDetectToolchains(QLatin1String("icpc"), Abi::hostAbi());
  870. }
  871. ToolChain *Internal::LinuxIccToolChainFactory::create()
  872. {
  873. return createToolChain(false);
  874. }
  875. bool Internal::LinuxIccToolChainFactory::canRestore(const QVariantMap &data)
  876. {
  877. return idFromMap(data).startsWith(QLatin1String(Constants::LINUXICC_TOOLCHAIN_ID) + QLatin1Char(':'));
  878. }
  879. ToolChain *Internal::LinuxIccToolChainFactory::restore(const QVariantMap &data)
  880. {
  881. LinuxIccToolChain *tc = new LinuxIccToolChain(false);
  882. if (tc->fromMap(data))
  883. return tc;
  884. delete tc;
  885. return 0;
  886. }
  887. GccToolChain *Internal::LinuxIccToolChainFactory::createToolChain(bool autoDetect)
  888. {
  889. return new LinuxIccToolChain(autoDetect);
  890. }
  891. } // namespace ProjectExplorer
  892. // Unit tests:
  893. #ifdef WITH_TESTS
  894. # include "projectexplorer.h"
  895. # include <QTest>
  896. # include <QUrl>
  897. namespace ProjectExplorer {
  898. void ProjectExplorerPlugin::testGccAbiGuessing_data()
  899. {
  900. QTest::addColumn<QString>("input");
  901. QTest::addColumn<QStringList>("abiList");
  902. QTest::newRow("invalid input")
  903. << QString::fromLatin1("Some text")
  904. << (QStringList());
  905. QTest::newRow("empty input")
  906. << QString::fromLatin1("")
  907. << (QStringList());
  908. QTest::newRow("broken input")
  909. << QString::fromLatin1("arm-none-foo-gnueabi")
  910. << (QStringList() << QLatin1String("arm-unknown-unknown-unknown-32bit"));
  911. QTest::newRow("totally broken input")
  912. << QString::fromLatin1("foo-bar-foo")
  913. << (QStringList());
  914. QTest::newRow("Maemo 1")
  915. << QString::fromLatin1("arm-none-linux-gnueabi")
  916. << (QStringList() << QLatin1String("arm-linux-generic-elf-32bit"));
  917. QTest::newRow("Linux 1")
  918. << QString::fromLatin1("i686-linux-gnu")
  919. << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit"));
  920. QTest::newRow("Linux 2")
  921. << QString::fromLatin1("i486-linux-gnu")
  922. << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit"));
  923. QTest::newRow("Linux 3")
  924. << QString::fromLatin1("x86_64-linux-gnu")
  925. << (QStringList() << QLatin1String("x86-linux-generic-elf-64bit")
  926. << QLatin1String("x86-linux-generic-elf-32bit"));
  927. QTest::newRow("Linux 4")
  928. << QString::fromLatin1("mipsel-linux-uclibc")
  929. << (QStringList() << QLatin1String("mips-linux-generic-elf-32bit"));
  930. QTest::newRow("Linux 5") // from QTCREATORBUG-4690
  931. << QString::fromLatin1("x86_64-redhat-linux6E")
  932. << (QStringList() << QLatin1String("x86-linux-generic-elf-64bit")
  933. << QLatin1String("x86-linux-generic-elf-32bit"));
  934. QTest::newRow("Linux 6") // from QTCREATORBUG-4690
  935. << QString::fromLatin1("x86_64-redhat-linux")
  936. << (QStringList() << QLatin1String("x86-linux-generic-elf-64bit")
  937. << QLatin1String("x86-linux-generic-elf-32bit"));
  938. QTest::newRow("Linux 7")
  939. << QString::fromLatin1("armv5tl-montavista-linux-gnueabi")
  940. << (QStringList() << QLatin1String("arm-linux-generic-elf-32bit"));
  941. QTest::newRow("Linux 8")
  942. << QString::fromLatin1("arm-angstrom-linux-gnueabi")
  943. << (QStringList() << QLatin1String("arm-linux-generic-elf-32bit"));
  944. QTest::newRow("Mingw 1")
  945. << QString::fromLatin1("i686-w64-mingw32")
  946. << (QStringList() << QLatin1String("x86-windows-msys-pe-64bit")
  947. << QLatin1String("x86-windows-msys-pe-32bit"));
  948. QTest::newRow("Mingw 2")
  949. << QString::fromLatin1("mingw32")
  950. << (QStringList() << QLatin1String("x86-windows-msys-pe-32bit"));
  951. QTest::newRow("Cross Mingw 1")
  952. << QString::fromLatin1("amd64-mingw32msvc")
  953. << (QStringList() << QLatin1String("x86-windows-msys-pe-64bit")
  954. << QLatin1String("x86-windows-msys-pe-32bit"));
  955. QTest::newRow("Cross Mingw 2")
  956. << QString::fromLatin1("i586-mingw32msvc")
  957. << (QStringList() << QLatin1String("x86-windows-msys-pe-32bit"));
  958. QTest::newRow("Clang 1: windows")
  959. << QString::fromLatin1("x86_64-pc-win32")
  960. << (QStringList() << QLatin1String("x86-windows-msys-pe-64bit")
  961. << QLatin1String("x86-windows-msys-pe-32bit"));
  962. QTest::newRow("Clang 1: linux")
  963. << QString::fromLatin1("x86_64-unknown-linux-gnu")
  964. << (QStringList() << QLatin1String("x86-linux-generic-elf-64bit")
  965. << QLatin1String("x86-linux-generic-elf-32bit"));
  966. QTest::newRow("Mac 1")
  967. << QString::fromLatin1("i686-apple-darwin10")
  968. << (QStringList() << QLatin1String("x86-macos-generic-mach_o-64bit")
  969. << QLatin1String("x86-macos-generic-mach_o-32bit")
  970. << QLatin1String("ppc-macos-generic-mach_o-64bit")
  971. << QLatin1String("ppc-macos-generic-mach_o-32bit"));
  972. QTest::newRow("Mac 2")
  973. << QString::fromLatin1("powerpc-apple-darwin10")
  974. << (QStringList() << QLatin1String("ppc-macos-generic-mach_o-64bit")
  975. << QLatin1String("ppc-macos-generic-mach_o-32bit")
  976. << QLatin1String("x86-macos-generic-mach_o-64bit")
  977. << QLatin1String("x86-macos-generic-mach_o-32bit"));
  978. QTest::newRow("Mac 3")
  979. << QString::fromLatin1("i686-apple-darwin9")
  980. << (QStringList() << QLatin1String("x86-macos-generic-mach_o-32bit")
  981. << QLatin1String("x86-macos-generic-mach_o-64bit")
  982. << QLatin1String("ppc-macos-generic-mach_o-32bit")
  983. << QLatin1String("ppc-macos-generic-mach_o-64bit"));
  984. QTest::newRow("Mac IOS")
  985. << QString::fromLatin1("arm-apple-darwin9")
  986. << (QStringList() << QLatin1String("arm-macos-generic-mach_o-32bit"));
  987. QTest::newRow("Intel 1")
  988. << QString::fromLatin1("86_64 x86_64 GNU/Linux")
  989. << (QStringList() << QLatin1String("x86-linux-generic-elf-64bit")
  990. << QLatin1String("x86-linux-generic-elf-32bit"));
  991. QTest::newRow("FreeBSD 1")
  992. << QString::fromLatin1("i386-portbld-freebsd9.0")
  993. << (QStringList() << QLatin1String("x86-bsd-freebsd-elf-32bit"));
  994. QTest::newRow("FreeBSD 2")
  995. << QString::fromLatin1("i386-undermydesk-freebsd")
  996. << (QStringList() << QLatin1String("x86-bsd-freebsd-elf-32bit"));
  997. }
  998. void ProjectExplorerPlugin::testGccAbiGuessing()
  999. {
  1000. QFETCH(QString, input);
  1001. QFETCH(QStringList, abiList);
  1002. QList<Abi> al = guessGccAbi(input);
  1003. QCOMPARE(al.count(), abiList.count());
  1004. for (int i = 0; i < al.count(); ++i) {
  1005. QCOMPARE(al.at(i).toString(), abiList.at(i));
  1006. }
  1007. }
  1008. } // namespace ProjectExplorer
  1009. #endif