2013-01-09 21:40:34 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2013-01-09 21:40:34 +02:00
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator.
|
|
|
|
|
**
|
|
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:57:40 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2013-01-09 21:40:34 +02:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2013-01-09 21:40:34 +02:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "customtoolchain.h"
|
2013-03-12 12:13:07 +01:00
|
|
|
#include "abiwidget.h"
|
2013-01-09 21:40:34 +02:00
|
|
|
#include "gccparser.h"
|
2013-08-05 21:21:49 +03:00
|
|
|
#include "clangparser.h"
|
|
|
|
|
#include "linuxiccparser.h"
|
|
|
|
|
#include "msvcparser.h"
|
2013-08-05 21:30:41 +03:00
|
|
|
#include "customparser.h"
|
|
|
|
|
#include "customparserconfigdialog.h"
|
2013-01-09 21:40:34 +02:00
|
|
|
#include "projectexplorerconstants.h"
|
|
|
|
|
#include "toolchainmanager.h"
|
|
|
|
|
|
2014-07-07 19:02:26 +02:00
|
|
|
#include <utils/algorithm.h>
|
2013-01-09 21:40:34 +02:00
|
|
|
#include <utils/detailswidget.h>
|
|
|
|
|
#include <utils/environment.h>
|
|
|
|
|
#include <utils/pathchooser.h>
|
2013-08-05 21:21:49 +03:00
|
|
|
#include <utils/qtcassert.h>
|
2013-01-09 21:40:34 +02:00
|
|
|
|
|
|
|
|
#include <QFormLayout>
|
|
|
|
|
#include <QPlainTextEdit>
|
|
|
|
|
#include <QLineEdit>
|
2013-08-05 21:30:41 +03:00
|
|
|
#include <QHBoxLayout>
|
2013-08-05 21:21:49 +03:00
|
|
|
#include <QComboBox>
|
2013-08-05 21:30:41 +03:00
|
|
|
#include <QPushButton>
|
2013-01-09 21:40:34 +02:00
|
|
|
|
|
|
|
|
using namespace Utils;
|
|
|
|
|
|
|
|
|
|
namespace ProjectExplorer {
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// Helpers:
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
static const char compilerCommandKeyC[] = "ProjectExplorer.CustomToolChain.CompilerPath";
|
|
|
|
|
static const char makeCommandKeyC[] = "ProjectExplorer.CustomToolChain.MakePath";
|
|
|
|
|
static const char targetAbiKeyC[] = "ProjectExplorer.CustomToolChain.TargetAbi";
|
|
|
|
|
static const char predefinedMacrosKeyC[] = "ProjectExplorer.CustomToolChain.PredefinedMacros";
|
|
|
|
|
static const char headerPathsKeyC[] = "ProjectExplorer.CustomToolChain.HeaderPaths";
|
|
|
|
|
static const char cxx11FlagsKeyC[] = "ProjectExplorer.CustomToolChain.Cxx11Flags";
|
|
|
|
|
static const char mkspecsKeyC[] = "ProjectExplorer.CustomToolChain.Mkspecs";
|
2013-08-05 21:21:49 +03:00
|
|
|
static const char outputParserKeyC[] = "ProjectExplorer.CustomToolChain.OutputParser";
|
2013-08-05 21:30:41 +03:00
|
|
|
static const char errorPatternKeyC[] = "ProjectExplorer.CustomToolChain.ErrorPattern";
|
2015-12-16 21:04:45 +01:00
|
|
|
static const char errorLineNumberCapKeyC[] = "ProjectExplorer.CustomToolChain.ErrorLineNumberCap";
|
|
|
|
|
static const char errorFileNameCapKeyC[] = "ProjectExplorer.CustomToolChain.ErrorFileNameCap";
|
|
|
|
|
static const char errorMessageCapKeyC[] = "ProjectExplorer.CustomToolChain.ErrorMessageCap";
|
|
|
|
|
static const char errorChannelKeyC[] = "ProjectExplorer.CustomToolChain.ErrorChannel";
|
|
|
|
|
static const char errorExampleKeyC[] = "ProjectExplorer.CustomToolChain.ErrorExample";
|
|
|
|
|
static const char warningPatternKeyC[] = "ProjectExplorer.CustomToolChain.WarningPattern";
|
|
|
|
|
static const char warningLineNumberCapKeyC[] = "ProjectExplorer.CustomToolChain.WarningLineNumberCap";
|
|
|
|
|
static const char warningFileNameCapKeyC[] = "ProjectExplorer.CustomToolChain.WarningFileNameCap";
|
|
|
|
|
static const char warningMessageCapKeyC[] = "ProjectExplorer.CustomToolChain.WarningMessageCap";
|
|
|
|
|
static const char warningChannelKeyC[] = "ProjectExplorer.CustomToolChain.WarningChannel";
|
|
|
|
|
static const char warningExampleKeyC[] = "ProjectExplorer.CustomToolChain.WarningExample";
|
|
|
|
|
|
2013-01-09 21:40:34 +02:00
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// CustomToolChain
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
|
2013-09-03 10:58:59 +02:00
|
|
|
CustomToolChain::CustomToolChain(Detection d) :
|
2015-07-07 15:37:50 +02:00
|
|
|
ToolChain(Constants::CUSTOM_TOOLCHAIN_TYPEID, d),
|
2013-08-05 21:21:49 +03:00
|
|
|
m_outputParser(Gcc)
|
2016-07-12 15:08:53 +02:00
|
|
|
{ }
|
|
|
|
|
|
2016-12-16 00:43:14 +01:00
|
|
|
CustomToolChain::CustomToolChain(Core::Id language, Detection d) : CustomToolChain(d)
|
2016-07-12 12:20:06 +02:00
|
|
|
{
|
2016-12-16 00:43:14 +01:00
|
|
|
setLanguage(language);
|
2016-07-12 12:20:06 +02:00
|
|
|
}
|
2013-01-09 21:40:34 +02:00
|
|
|
|
2016-07-12 15:08:53 +02:00
|
|
|
|
2013-01-09 21:40:34 +02:00
|
|
|
QString CustomToolChain::typeDisplayName() const
|
|
|
|
|
{
|
|
|
|
|
return Internal::CustomToolChainFactory::tr("Custom");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Abi CustomToolChain::targetAbi() const
|
|
|
|
|
{
|
|
|
|
|
return m_targetAbi;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CustomToolChain::setTargetAbi(const Abi &abi)
|
|
|
|
|
{
|
|
|
|
|
if (abi == m_targetAbi)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_targetAbi = abi;
|
|
|
|
|
toolChainUpdated();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CustomToolChain::isValid() const
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-06 16:59:53 +01:00
|
|
|
ToolChain::PredefinedMacrosRunner CustomToolChain::createPredefinedMacrosRunner() const
|
2013-01-09 21:40:34 +02:00
|
|
|
{
|
2017-02-06 16:59:53 +01:00
|
|
|
const QStringList theMacros = m_predefinedMacros;
|
|
|
|
|
|
|
|
|
|
// This runner must be thread-safe!
|
|
|
|
|
return [theMacros](const QStringList &cxxflags){
|
|
|
|
|
QByteArray result;
|
|
|
|
|
QStringList macros = theMacros;
|
|
|
|
|
foreach (const QString &cxxFlag, cxxflags) {
|
|
|
|
|
if (cxxFlag.startsWith(QLatin1String("-D"))) {
|
|
|
|
|
macros << cxxFlag.mid(2).trimmed();
|
|
|
|
|
} else if (cxxFlag.startsWith(QLatin1String("-U"))) {
|
|
|
|
|
const QString &removedName = cxxFlag.mid(2).trimmed();
|
|
|
|
|
for (int i = macros.size() - 1; i >= 0; --i) {
|
|
|
|
|
const QString &m = macros.at(i);
|
|
|
|
|
if (m.left(m.indexOf(QLatin1Char('='))) == removedName)
|
|
|
|
|
macros.removeAt(i);
|
|
|
|
|
}
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
2017-02-06 16:59:53 +01:00
|
|
|
foreach (const QString &str, macros) {
|
|
|
|
|
QByteArray ba = str.toUtf8();
|
|
|
|
|
int equals = ba.indexOf('=');
|
|
|
|
|
if (equals == -1) {
|
|
|
|
|
result += "#define " + ba.trimmed() + '\n';
|
|
|
|
|
} else {
|
|
|
|
|
result += "#define " + ba.left(equals).trimmed() + ' '
|
|
|
|
|
+ ba.mid(equals + 1).trimmed() + '\n';
|
|
|
|
|
}
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
2017-02-06 16:59:53 +01:00
|
|
|
return result;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QByteArray CustomToolChain::predefinedMacros(const QStringList &cxxflags) const
|
|
|
|
|
{
|
|
|
|
|
return createPredefinedMacrosRunner()(cxxflags);
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ToolChain::CompilerFlags CustomToolChain::compilerFlags(const QStringList &cxxflags) const
|
|
|
|
|
{
|
|
|
|
|
foreach (const QString &cxx11Flag, m_cxx11Flags)
|
|
|
|
|
if (cxxflags.contains(cxx11Flag))
|
2013-04-28 13:11:48 +04:00
|
|
|
return StandardCxx11;
|
|
|
|
|
return NoFlags;
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
|
|
|
|
|
2016-01-18 11:56:54 +01:00
|
|
|
WarningFlags CustomToolChain::warningFlags(const QStringList &cxxflags) const
|
2013-03-03 21:53:38 +04:00
|
|
|
{
|
|
|
|
|
Q_UNUSED(cxxflags);
|
2016-01-18 11:56:54 +01:00
|
|
|
return WarningFlags::Default;
|
2013-03-03 21:53:38 +04:00
|
|
|
}
|
|
|
|
|
|
2013-01-09 21:40:34 +02:00
|
|
|
const QStringList &CustomToolChain::rawPredefinedMacros() const
|
|
|
|
|
{
|
|
|
|
|
return m_predefinedMacros;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CustomToolChain::setPredefinedMacros(const QStringList &list)
|
|
|
|
|
{
|
2016-07-06 14:13:25 +02:00
|
|
|
if (m_predefinedMacros == list)
|
|
|
|
|
return;
|
2013-01-09 21:40:34 +02:00
|
|
|
m_predefinedMacros = list;
|
2016-07-06 14:13:25 +02:00
|
|
|
toolChainUpdated();
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
|
|
|
|
|
2017-02-06 16:59:53 +01:00
|
|
|
ToolChain::SystemHeaderPathsRunner CustomToolChain::createSystemHeaderPathsRunner() const
|
2013-01-09 21:40:34 +02:00
|
|
|
{
|
2017-02-06 16:59:53 +01:00
|
|
|
const QList<HeaderPath> systemHeaderPaths = m_systemHeaderPaths;
|
|
|
|
|
|
|
|
|
|
// This runner must be thread-safe!
|
|
|
|
|
return [systemHeaderPaths](const QStringList &cxxFlags, const QString &) {
|
|
|
|
|
QList<HeaderPath> flagHeaderPaths;
|
|
|
|
|
foreach (const QString &cxxFlag, cxxFlags) {
|
|
|
|
|
if (cxxFlag.startsWith(QLatin1String("-I")))
|
|
|
|
|
flagHeaderPaths << HeaderPath(cxxFlag.mid(2).trimmed(), HeaderPath::GlobalHeaderPath);
|
|
|
|
|
}
|
2013-01-09 21:40:34 +02:00
|
|
|
|
2017-02-06 16:59:53 +01:00
|
|
|
return systemHeaderPaths + flagHeaderPaths;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<HeaderPath> CustomToolChain::systemHeaderPaths(const QStringList &cxxFlags,
|
|
|
|
|
const FileName &fileName) const
|
|
|
|
|
{
|
|
|
|
|
return createSystemHeaderPathsRunner()(cxxFlags, fileName.toString());
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CustomToolChain::addToEnvironment(Environment &env) const
|
|
|
|
|
{
|
|
|
|
|
if (!m_compilerCommand.isEmpty()) {
|
|
|
|
|
FileName path = m_compilerCommand.parentDir();
|
|
|
|
|
env.prependOrSetPath(path.toString());
|
|
|
|
|
FileName makePath = m_makeCommand.parentDir();
|
|
|
|
|
if (makePath != path)
|
|
|
|
|
env.prependOrSetPath(makePath.toString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-03 14:01:25 +01:00
|
|
|
FileNameList CustomToolChain::suggestedMkspecList() const
|
2013-01-09 21:40:34 +02:00
|
|
|
{
|
|
|
|
|
return m_mkspecs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IOutputParser *CustomToolChain::outputParser() const
|
|
|
|
|
{
|
2013-08-05 21:21:49 +03:00
|
|
|
switch (m_outputParser) {
|
|
|
|
|
case Gcc: return new GccParser;
|
|
|
|
|
case Clang: return new ClangParser;
|
|
|
|
|
case LinuxIcc: return new LinuxIccParser;
|
2013-09-02 17:10:01 +02:00
|
|
|
#if defined(Q_OS_WIN)
|
2013-08-05 21:21:49 +03:00
|
|
|
case Msvc: return new MsvcParser;
|
2013-08-06 15:11:25 +02:00
|
|
|
#endif
|
2013-08-05 21:30:41 +03:00
|
|
|
case Custom: return new CustomParser(m_customParserSettings);
|
2016-04-13 15:52:14 +02:00
|
|
|
default: return nullptr;
|
2013-08-05 21:21:49 +03:00
|
|
|
}
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList CustomToolChain::headerPathsList() const
|
|
|
|
|
{
|
2014-07-07 19:02:26 +02:00
|
|
|
return Utils::transform(m_systemHeaderPaths, &HeaderPath::path);
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CustomToolChain::setHeaderPaths(const QStringList &list)
|
|
|
|
|
{
|
2016-07-06 14:13:25 +02:00
|
|
|
QList<HeaderPath> tmp = Utils::transform(list, [](const QString &headerPath) {
|
2014-07-07 19:02:26 +02:00
|
|
|
return HeaderPath(headerPath.trimmed(), HeaderPath::GlobalHeaderPath);
|
|
|
|
|
});
|
2016-07-06 14:13:25 +02:00
|
|
|
|
|
|
|
|
if (m_systemHeaderPaths == tmp)
|
|
|
|
|
return;
|
|
|
|
|
m_systemHeaderPaths = tmp;
|
|
|
|
|
toolChainUpdated();
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CustomToolChain::setCompilerCommand(const FileName &path)
|
|
|
|
|
{
|
|
|
|
|
if (path == m_compilerCommand)
|
|
|
|
|
return;
|
|
|
|
|
m_compilerCommand = path;
|
|
|
|
|
toolChainUpdated();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FileName CustomToolChain::compilerCommand() const
|
|
|
|
|
{
|
|
|
|
|
return m_compilerCommand;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CustomToolChain::setMakeCommand(const FileName &path)
|
|
|
|
|
{
|
|
|
|
|
if (path == m_makeCommand)
|
|
|
|
|
return;
|
|
|
|
|
m_makeCommand = path;
|
|
|
|
|
toolChainUpdated();
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-03 23:59:04 +02:00
|
|
|
QString CustomToolChain::makeCommand(const Environment &) const
|
2013-01-09 21:40:34 +02:00
|
|
|
{
|
|
|
|
|
return m_makeCommand.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CustomToolChain::setCxx11Flags(const QStringList &flags)
|
|
|
|
|
{
|
|
|
|
|
if (flags == m_cxx11Flags)
|
|
|
|
|
return;
|
|
|
|
|
m_cxx11Flags = flags;
|
|
|
|
|
toolChainUpdated();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QStringList &CustomToolChain::cxx11Flags() const
|
|
|
|
|
{
|
|
|
|
|
return m_cxx11Flags;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CustomToolChain::setMkspecs(const QString &specs)
|
|
|
|
|
{
|
2016-07-06 14:13:25 +02:00
|
|
|
Utils::FileNameList tmp
|
|
|
|
|
= Utils::transform(specs.split(QLatin1Char(',')),
|
|
|
|
|
[](QString fn) { return FileName::fromString(fn); });
|
|
|
|
|
|
|
|
|
|
if (tmp == m_mkspecs)
|
|
|
|
|
return;
|
|
|
|
|
m_mkspecs = tmp;
|
|
|
|
|
toolChainUpdated();
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString CustomToolChain::mkspecs() const
|
|
|
|
|
{
|
|
|
|
|
QString list;
|
|
|
|
|
foreach (const FileName &spec, m_mkspecs)
|
|
|
|
|
list.append(spec.toString() + QLatin1Char(','));
|
|
|
|
|
list.chop(1);
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ToolChain *CustomToolChain::clone() const
|
|
|
|
|
{
|
|
|
|
|
return new CustomToolChain(*this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariantMap CustomToolChain::toMap() const
|
|
|
|
|
{
|
|
|
|
|
QVariantMap data = ToolChain::toMap();
|
|
|
|
|
data.insert(QLatin1String(compilerCommandKeyC), m_compilerCommand.toString());
|
|
|
|
|
data.insert(QLatin1String(makeCommandKeyC), m_makeCommand.toString());
|
|
|
|
|
data.insert(QLatin1String(targetAbiKeyC), m_targetAbi.toString());
|
|
|
|
|
data.insert(QLatin1String(predefinedMacrosKeyC), m_predefinedMacros);
|
|
|
|
|
data.insert(QLatin1String(headerPathsKeyC), headerPathsList());
|
|
|
|
|
data.insert(QLatin1String(cxx11FlagsKeyC), m_cxx11Flags);
|
|
|
|
|
data.insert(QLatin1String(mkspecsKeyC), mkspecs());
|
2013-08-05 21:21:49 +03:00
|
|
|
data.insert(QLatin1String(outputParserKeyC), m_outputParser);
|
2015-12-16 21:04:45 +01:00
|
|
|
data.insert(QLatin1String(errorPatternKeyC), m_customParserSettings.error.pattern());
|
|
|
|
|
data.insert(QLatin1String(errorFileNameCapKeyC), m_customParserSettings.error.fileNameCap());
|
|
|
|
|
data.insert(QLatin1String(errorLineNumberCapKeyC), m_customParserSettings.error.lineNumberCap());
|
|
|
|
|
data.insert(QLatin1String(errorMessageCapKeyC), m_customParserSettings.error.messageCap());
|
|
|
|
|
data.insert(QLatin1String(errorChannelKeyC), m_customParserSettings.error.channel());
|
|
|
|
|
data.insert(QLatin1String(errorExampleKeyC), m_customParserSettings.error.example());
|
|
|
|
|
data.insert(QLatin1String(warningPatternKeyC), m_customParserSettings.warning.pattern());
|
|
|
|
|
data.insert(QLatin1String(warningFileNameCapKeyC), m_customParserSettings.warning.fileNameCap());
|
|
|
|
|
data.insert(QLatin1String(warningLineNumberCapKeyC), m_customParserSettings.warning.lineNumberCap());
|
|
|
|
|
data.insert(QLatin1String(warningMessageCapKeyC), m_customParserSettings.warning.messageCap());
|
|
|
|
|
data.insert(QLatin1String(warningChannelKeyC), m_customParserSettings.warning.channel());
|
|
|
|
|
data.insert(QLatin1String(warningExampleKeyC), m_customParserSettings.warning.example());
|
2013-01-09 21:40:34 +02:00
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CustomToolChain::fromMap(const QVariantMap &data)
|
|
|
|
|
{
|
|
|
|
|
if (!ToolChain::fromMap(data))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
m_compilerCommand = FileName::fromString(data.value(QLatin1String(compilerCommandKeyC)).toString());
|
|
|
|
|
m_makeCommand = FileName::fromString(data.value(QLatin1String(makeCommandKeyC)).toString());
|
|
|
|
|
m_targetAbi = Abi(data.value(QLatin1String(targetAbiKeyC)).toString());
|
|
|
|
|
m_predefinedMacros = data.value(QLatin1String(predefinedMacrosKeyC)).toStringList();
|
|
|
|
|
setHeaderPaths(data.value(QLatin1String(headerPathsKeyC)).toStringList());
|
|
|
|
|
m_cxx11Flags = data.value(QLatin1String(cxx11FlagsKeyC)).toStringList();
|
|
|
|
|
setMkspecs(data.value(QLatin1String(mkspecsKeyC)).toString());
|
2013-08-05 21:21:49 +03:00
|
|
|
m_outputParser = (OutputParser)data.value(QLatin1String(outputParserKeyC)).toInt();
|
2015-12-16 21:04:45 +01:00
|
|
|
m_customParserSettings.error.setPattern(data.value(QLatin1String(errorPatternKeyC)).toString());
|
|
|
|
|
m_customParserSettings.error.setFileNameCap(data.value(QLatin1String(errorFileNameCapKeyC)).toInt());
|
|
|
|
|
m_customParserSettings.error.setLineNumberCap(data.value(QLatin1String(errorLineNumberCapKeyC)).toInt());
|
|
|
|
|
m_customParserSettings.error.setMessageCap(data.value(QLatin1String(errorMessageCapKeyC)).toInt());
|
|
|
|
|
m_customParserSettings.error.setChannel(
|
|
|
|
|
static_cast<CustomParserExpression::CustomParserChannel>(data.value(QLatin1String(errorChannelKeyC)).toInt()));
|
|
|
|
|
m_customParserSettings.error.setExample(data.value(QLatin1String(errorExampleKeyC)).toString());
|
|
|
|
|
m_customParserSettings.warning.setPattern(data.value(QLatin1String(warningPatternKeyC)).toString());
|
|
|
|
|
m_customParserSettings.warning.setFileNameCap(data.value(QLatin1String(warningFileNameCapKeyC)).toInt());
|
|
|
|
|
m_customParserSettings.warning.setLineNumberCap(data.value(QLatin1String(warningLineNumberCapKeyC)).toInt());
|
|
|
|
|
m_customParserSettings.warning.setMessageCap(data.value(QLatin1String(warningMessageCapKeyC)).toInt());
|
|
|
|
|
m_customParserSettings.warning.setChannel(
|
|
|
|
|
static_cast<CustomParserExpression::CustomParserChannel>(data.value(QLatin1String(warningChannelKeyC)).toInt()));
|
|
|
|
|
m_customParserSettings.warning.setExample(data.value(QLatin1String(warningExampleKeyC)).toString());
|
|
|
|
|
|
2013-08-05 21:21:49 +03:00
|
|
|
QTC_ASSERT(m_outputParser >= Gcc && m_outputParser < OutputParserCount, return false);
|
2013-01-09 21:40:34 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CustomToolChain::operator ==(const ToolChain &other) const
|
|
|
|
|
{
|
|
|
|
|
if (!ToolChain::operator ==(other))
|
|
|
|
|
return false;
|
|
|
|
|
|
2016-04-13 15:52:14 +02:00
|
|
|
auto customTc = static_cast<const CustomToolChain *>(&other);
|
2013-01-09 21:40:34 +02:00
|
|
|
return m_compilerCommand == customTc->m_compilerCommand
|
|
|
|
|
&& m_makeCommand == customTc->m_makeCommand
|
|
|
|
|
&& m_targetAbi == customTc->m_targetAbi
|
|
|
|
|
&& m_predefinedMacros == customTc->m_predefinedMacros
|
|
|
|
|
&& m_systemHeaderPaths == customTc->m_systemHeaderPaths;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-05 21:21:49 +03:00
|
|
|
CustomToolChain::OutputParser CustomToolChain::outputParserType() const
|
|
|
|
|
{
|
|
|
|
|
return m_outputParser;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CustomToolChain::setOutputParserType(CustomToolChain::OutputParser parser)
|
|
|
|
|
{
|
2016-07-06 14:13:25 +02:00
|
|
|
if (m_outputParser == parser)
|
|
|
|
|
return;
|
2013-08-05 21:21:49 +03:00
|
|
|
m_outputParser = parser;
|
2016-07-06 14:13:25 +02:00
|
|
|
toolChainUpdated();
|
2013-08-05 21:21:49 +03:00
|
|
|
}
|
|
|
|
|
|
2013-08-05 21:30:41 +03:00
|
|
|
CustomParserSettings CustomToolChain::customParserSettings() const
|
|
|
|
|
{
|
|
|
|
|
return m_customParserSettings;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CustomToolChain::setCustomParserSettings(const CustomParserSettings &settings)
|
|
|
|
|
{
|
2016-07-06 14:13:25 +02:00
|
|
|
if (m_customParserSettings == settings)
|
|
|
|
|
return;
|
2013-08-05 21:30:41 +03:00
|
|
|
m_customParserSettings = settings;
|
2016-07-06 14:13:25 +02:00
|
|
|
toolChainUpdated();
|
2013-08-05 21:30:41 +03:00
|
|
|
}
|
|
|
|
|
|
2013-08-05 21:21:49 +03:00
|
|
|
QString CustomToolChain::parserName(CustomToolChain::OutputParser parser)
|
|
|
|
|
{
|
|
|
|
|
switch (parser) {
|
|
|
|
|
case Gcc: return tr("GCC");
|
|
|
|
|
case Clang: return tr("Clang");
|
|
|
|
|
case LinuxIcc: return tr("ICC");
|
2013-08-06 15:11:25 +02:00
|
|
|
#if defined(Q_OS_WIN)
|
2013-08-05 21:21:49 +03:00
|
|
|
case Msvc: return tr("MSVC");
|
2013-08-06 15:11:25 +02:00
|
|
|
#endif
|
2013-08-05 21:30:41 +03:00
|
|
|
case Custom: return tr("Custom");
|
2013-08-05 21:21:49 +03:00
|
|
|
default: return QString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-09 21:40:34 +02:00
|
|
|
ToolChainConfigWidget *CustomToolChain::configurationWidget()
|
|
|
|
|
{
|
|
|
|
|
return new Internal::CustomToolChainConfigWidget(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// CustomToolChainFactory
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
|
2013-08-09 17:49:30 +02:00
|
|
|
CustomToolChainFactory::CustomToolChainFactory()
|
2013-01-09 21:40:34 +02:00
|
|
|
{
|
2013-08-09 17:49:30 +02:00
|
|
|
setDisplayName(tr("Custom"));
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
|
|
|
|
|
2016-12-16 00:43:14 +01:00
|
|
|
QSet<Core::Id> CustomToolChainFactory::supportedLanguages() const
|
2016-07-12 11:33:17 +02:00
|
|
|
{
|
2016-12-16 00:43:14 +01:00
|
|
|
return ToolChainManager::allLanguages();
|
2016-07-12 11:33:17 +02:00
|
|
|
}
|
|
|
|
|
|
2013-01-09 21:40:34 +02:00
|
|
|
bool CustomToolChainFactory::canCreate()
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-16 00:43:14 +01:00
|
|
|
ToolChain *CustomToolChainFactory::create(Core::Id language)
|
2013-01-09 21:40:34 +02:00
|
|
|
{
|
2016-12-16 00:43:14 +01:00
|
|
|
return new CustomToolChain(language, ToolChain::ManualDetection);
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Used by the ToolChainManager to restore user-generated tool chains
|
|
|
|
|
bool CustomToolChainFactory::canRestore(const QVariantMap &data)
|
|
|
|
|
{
|
2015-07-07 15:37:50 +02:00
|
|
|
return typeIdFromMap(data) == Constants::CUSTOM_TOOLCHAIN_TYPEID;
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ToolChain *CustomToolChainFactory::restore(const QVariantMap &data)
|
|
|
|
|
{
|
2016-04-13 15:52:14 +02:00
|
|
|
auto tc = new CustomToolChain(ToolChain::ManualDetection);
|
2013-01-09 21:40:34 +02:00
|
|
|
if (tc->fromMap(data))
|
|
|
|
|
return tc;
|
|
|
|
|
|
|
|
|
|
delete tc;
|
2016-04-13 15:52:14 +02:00
|
|
|
return nullptr;
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// Helper for ConfigWidget
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
class TextEditDetailsWidget : public DetailsWidget
|
|
|
|
|
{
|
2013-01-22 15:49:20 +01:00
|
|
|
Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::Internal::TextEditDetailsWidget)
|
2013-01-09 21:40:34 +02:00
|
|
|
public:
|
|
|
|
|
TextEditDetailsWidget(QPlainTextEdit *textEdit)
|
|
|
|
|
{
|
|
|
|
|
setWidget(textEdit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline QPlainTextEdit *textEditWidget() const
|
|
|
|
|
{
|
|
|
|
|
return static_cast<QPlainTextEdit *>(widget());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline QStringList entries() const
|
|
|
|
|
{
|
|
|
|
|
return textEditWidget()->toPlainText().split(QLatin1Char('\n'), QString::SkipEmptyParts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// not accurate, counts empty lines (except last)
|
|
|
|
|
int entryCount() const
|
|
|
|
|
{
|
|
|
|
|
int count = textEditWidget()->blockCount();
|
|
|
|
|
QString text = textEditWidget()->toPlainText();
|
|
|
|
|
if (text.isEmpty() || text.endsWith(QLatin1Char('\n')))
|
|
|
|
|
--count;
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void updateSummaryText()
|
|
|
|
|
{
|
|
|
|
|
int count = entryCount();
|
2013-02-13 12:38:06 +01:00
|
|
|
setSummaryText(count ? tr("%n entries", "", count) : tr("Empty"));
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// CustomToolChainConfigWidget
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
CustomToolChainConfigWidget::CustomToolChainConfigWidget(CustomToolChain *tc) :
|
|
|
|
|
ToolChainConfigWidget(tc),
|
|
|
|
|
m_compilerCommand(new PathChooser),
|
|
|
|
|
m_makeCommand(new PathChooser),
|
|
|
|
|
m_abiWidget(new AbiWidget),
|
|
|
|
|
m_predefinedMacros(new QPlainTextEdit),
|
|
|
|
|
m_headerPaths(new QPlainTextEdit),
|
|
|
|
|
m_predefinedDetails(new TextEditDetailsWidget(m_predefinedMacros)),
|
|
|
|
|
m_headerDetails(new TextEditDetailsWidget(m_headerPaths)),
|
|
|
|
|
m_cxx11Flags(new QLineEdit),
|
2013-08-05 21:21:49 +03:00
|
|
|
m_mkspecs(new QLineEdit),
|
2013-08-05 21:30:41 +03:00
|
|
|
m_errorParserComboBox(new QComboBox),
|
|
|
|
|
m_customParserSettingsButton(new QPushButton(tr("Custom Parser Settings...")))
|
2013-01-09 21:40:34 +02:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(tc);
|
|
|
|
|
|
2013-08-05 21:21:49 +03:00
|
|
|
for (int i = 0; i < CustomToolChain::OutputParserCount; ++i)
|
|
|
|
|
m_errorParserComboBox->addItem(CustomToolChain::parserName((CustomToolChain::OutputParser)i));
|
|
|
|
|
|
2016-04-13 15:52:14 +02:00
|
|
|
auto parserLayoutWidget = new QWidget;
|
|
|
|
|
auto parserLayout = new QHBoxLayout(parserLayoutWidget);
|
2013-08-05 21:30:41 +03:00
|
|
|
parserLayout->setContentsMargins(0, 0, 0, 0);
|
2013-01-09 21:40:34 +02:00
|
|
|
m_predefinedMacros->setTabChangesFocus(true);
|
2014-03-13 09:55:53 +01:00
|
|
|
m_predefinedMacros->setToolTip(tr("Each line defines a macro. Format is MACRO[=VALUE]."));
|
2013-01-09 21:40:34 +02:00
|
|
|
m_headerPaths->setTabChangesFocus(true);
|
2013-02-12 16:55:00 +01:00
|
|
|
m_headerPaths->setToolTip(tr("Each line adds a global header lookup path."));
|
|
|
|
|
m_cxx11Flags->setToolTip(tr("Comma-separated list of flags that turn on C++11 support."));
|
|
|
|
|
m_mkspecs->setToolTip(tr("Comma-separated list of mkspecs."));
|
2013-01-09 21:40:34 +02:00
|
|
|
m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand);
|
2013-11-25 14:35:35 +01:00
|
|
|
m_compilerCommand->setHistoryCompleter(QLatin1String("PE.ToolChainCommand.History"));
|
2013-01-09 21:40:34 +02:00
|
|
|
m_makeCommand->setExpectedKind(PathChooser::ExistingCommand);
|
2013-11-25 14:35:35 +01:00
|
|
|
m_makeCommand->setHistoryCompleter(QLatin1String("PE.MakeCommand.History"));
|
2013-01-09 21:40:34 +02:00
|
|
|
m_mainLayout->addRow(tr("&Compiler path:"), m_compilerCommand);
|
|
|
|
|
m_mainLayout->addRow(tr("&Make path:"), m_makeCommand);
|
|
|
|
|
m_mainLayout->addRow(tr("&ABI:"), m_abiWidget);
|
|
|
|
|
m_mainLayout->addRow(tr("&Predefined macros:"), m_predefinedDetails);
|
|
|
|
|
m_mainLayout->addRow(tr("&Header paths:"), m_headerDetails);
|
|
|
|
|
m_mainLayout->addRow(tr("C++11 &flags:"), m_cxx11Flags);
|
|
|
|
|
m_mainLayout->addRow(tr("&Qt mkspecs:"), m_mkspecs);
|
2013-08-05 21:30:41 +03:00
|
|
|
parserLayout->addWidget(m_errorParserComboBox);
|
|
|
|
|
parserLayout->addWidget(m_customParserSettingsButton);
|
|
|
|
|
m_mainLayout->addRow(tr("&Error parser:"), parserLayoutWidget);
|
2013-01-09 21:40:34 +02:00
|
|
|
addErrorLabel();
|
|
|
|
|
|
|
|
|
|
setFromToolchain();
|
|
|
|
|
m_predefinedDetails->updateSummaryText();
|
|
|
|
|
m_headerDetails->updateSummaryText();
|
|
|
|
|
|
2016-01-29 16:38:37 +02:00
|
|
|
connect(m_compilerCommand, &PathChooser::rawPathChanged, this, &ToolChainConfigWidget::dirty);
|
|
|
|
|
connect(m_makeCommand, &PathChooser::rawPathChanged, this, &ToolChainConfigWidget::dirty);
|
|
|
|
|
connect(m_abiWidget, &AbiWidget::abiChanged, this, &ToolChainConfigWidget::dirty);
|
|
|
|
|
connect(m_predefinedMacros, &QPlainTextEdit::textChanged,
|
|
|
|
|
this, &CustomToolChainConfigWidget::updateSummaries);
|
|
|
|
|
connect(m_headerPaths, &QPlainTextEdit::textChanged,
|
|
|
|
|
this, &CustomToolChainConfigWidget::updateSummaries);
|
|
|
|
|
connect(m_cxx11Flags, &QLineEdit::textChanged, this, &ToolChainConfigWidget::dirty);
|
|
|
|
|
connect(m_mkspecs, &QLineEdit::textChanged, this, &ToolChainConfigWidget::dirty);
|
|
|
|
|
connect(m_errorParserComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
|
|
|
|
this, &CustomToolChainConfigWidget::errorParserChanged);
|
|
|
|
|
connect(m_customParserSettingsButton, &QAbstractButton::clicked,
|
|
|
|
|
this, &CustomToolChainConfigWidget::openCustomParserSettingsDialog);
|
2013-08-05 21:21:49 +03:00
|
|
|
errorParserChanged(m_errorParserComboBox->currentIndex());
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CustomToolChainConfigWidget::updateSummaries()
|
|
|
|
|
{
|
|
|
|
|
if (sender() == m_predefinedMacros)
|
|
|
|
|
m_predefinedDetails->updateSummaryText();
|
|
|
|
|
else
|
|
|
|
|
m_headerDetails->updateSummaryText();
|
2013-08-04 20:57:50 +03:00
|
|
|
emit dirty();
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
|
|
|
|
|
2013-08-05 21:21:49 +03:00
|
|
|
void CustomToolChainConfigWidget::errorParserChanged(int index)
|
|
|
|
|
{
|
2013-08-05 21:30:41 +03:00
|
|
|
m_customParserSettingsButton->setEnabled(index == m_errorParserComboBox->count() - 1);
|
2013-08-05 21:21:49 +03:00
|
|
|
emit dirty();
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-05 21:30:41 +03:00
|
|
|
void CustomToolChainConfigWidget::openCustomParserSettingsDialog()
|
|
|
|
|
{
|
|
|
|
|
CustomParserConfigDialog dialog;
|
|
|
|
|
dialog.setSettings(m_customParserSettings);
|
|
|
|
|
|
|
|
|
|
if (dialog.exec() == QDialog::Accepted) {
|
|
|
|
|
m_customParserSettings = dialog.settings();
|
|
|
|
|
if (dialog.isDirty())
|
|
|
|
|
emit dirty();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-09 21:40:34 +02:00
|
|
|
void CustomToolChainConfigWidget::applyImpl()
|
|
|
|
|
{
|
|
|
|
|
if (toolChain()->isAutoDetected())
|
|
|
|
|
return;
|
|
|
|
|
|
2016-04-13 15:52:14 +02:00
|
|
|
auto tc = static_cast<CustomToolChain *>(toolChain());
|
2013-01-09 21:40:34 +02:00
|
|
|
Q_ASSERT(tc);
|
|
|
|
|
QString displayName = tc->displayName();
|
|
|
|
|
tc->setCompilerCommand(m_compilerCommand->fileName());
|
2013-01-27 21:36:49 +01:00
|
|
|
tc->setMakeCommand(m_makeCommand->fileName());
|
2013-01-09 21:40:34 +02:00
|
|
|
tc->setTargetAbi(m_abiWidget->currentAbi());
|
|
|
|
|
tc->setPredefinedMacros(m_predefinedDetails->entries());
|
|
|
|
|
tc->setHeaderPaths(m_headerDetails->entries());
|
|
|
|
|
tc->setCxx11Flags(m_cxx11Flags->text().split(QLatin1Char(',')));
|
|
|
|
|
tc->setMkspecs(m_mkspecs->text());
|
|
|
|
|
tc->setDisplayName(displayName); // reset display name
|
2013-08-05 21:21:49 +03:00
|
|
|
tc->setOutputParserType((CustomToolChain::OutputParser)m_errorParserComboBox->currentIndex());
|
2013-08-05 21:30:41 +03:00
|
|
|
tc->setCustomParserSettings(m_customParserSettings);
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CustomToolChainConfigWidget::setFromToolchain()
|
|
|
|
|
{
|
|
|
|
|
// subwidgets are not yet connected!
|
|
|
|
|
bool blocked = blockSignals(true);
|
2016-04-13 15:52:14 +02:00
|
|
|
auto tc = static_cast<CustomToolChain *>(toolChain());
|
2013-01-09 21:40:34 +02:00
|
|
|
m_compilerCommand->setFileName(tc->compilerCommand());
|
2015-02-03 23:59:04 +02:00
|
|
|
m_makeCommand->setFileName(FileName::fromString(tc->makeCommand(Environment())));
|
2013-01-09 21:40:34 +02:00
|
|
|
m_abiWidget->setAbis(QList<Abi>(), tc->targetAbi());
|
2014-08-23 01:19:53 +02:00
|
|
|
m_predefinedMacros->setPlainText(tc->rawPredefinedMacros().join(QLatin1Char('\n')));
|
|
|
|
|
m_headerPaths->setPlainText(tc->headerPathsList().join(QLatin1Char('\n')));
|
|
|
|
|
m_cxx11Flags->setText(tc->cxx11Flags().join(QLatin1Char(',')));
|
2013-01-09 21:40:34 +02:00
|
|
|
m_mkspecs->setText(tc->mkspecs());
|
2013-08-05 21:21:49 +03:00
|
|
|
m_errorParserComboBox->setCurrentIndex(tc->outputParserType());
|
2013-08-05 21:30:41 +03:00
|
|
|
m_customParserSettings = tc->customParserSettings();
|
2013-01-09 21:40:34 +02:00
|
|
|
blockSignals(blocked);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CustomToolChainConfigWidget::isDirtyImpl() const
|
|
|
|
|
{
|
2016-04-13 15:52:14 +02:00
|
|
|
auto tc = static_cast<CustomToolChain *>(toolChain());
|
2013-01-09 21:40:34 +02:00
|
|
|
Q_ASSERT(tc);
|
|
|
|
|
return m_compilerCommand->fileName() != tc->compilerCommand()
|
2015-02-03 23:59:04 +02:00
|
|
|
|| m_makeCommand->path() != tc->makeCommand(Environment())
|
2013-01-09 21:40:34 +02:00
|
|
|
|| m_abiWidget->currentAbi() != tc->targetAbi()
|
|
|
|
|
|| m_predefinedDetails->entries() != tc->rawPredefinedMacros()
|
|
|
|
|
|| m_headerDetails->entries() != tc->headerPathsList()
|
|
|
|
|
|| m_cxx11Flags->text().split(QLatin1Char(',')) != tc->cxx11Flags()
|
2013-08-05 21:21:49 +03:00
|
|
|
|| m_mkspecs->text() != tc->mkspecs()
|
2013-08-05 21:30:41 +03:00
|
|
|
|| m_errorParserComboBox->currentIndex() == tc->outputParserType()
|
|
|
|
|
|| m_customParserSettings != tc->customParserSettings();
|
2013-01-09 21:40:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CustomToolChainConfigWidget::makeReadOnlyImpl()
|
|
|
|
|
{
|
|
|
|
|
m_mainLayout->setEnabled(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace ProjectExplorer
|