ProjectExplorer: Add lld output parser

Fixes: QTCREATORBUG-22623
Change-Id: I2c38466cf7206e07d1cb77520ce502179e3cc82f
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
Christian Kandeler
2019-07-11 17:48:09 +02:00
parent 333b33edbe
commit 52a58afc79
8 changed files with 249 additions and 1 deletions

View File

@@ -109,6 +109,7 @@ add_qtc_plugin(ProjectExplorer
kitmodel.cpp kitmodel.h kitmodel.cpp kitmodel.h
kitoptionspage.cpp kitoptionspage.h kitoptionspage.cpp kitoptionspage.h
ldparser.cpp ldparser.h ldparser.cpp ldparser.h
lldparser.cpp lldparser.h
linuxiccparser.cpp linuxiccparser.h linuxiccparser.cpp linuxiccparser.h
localenvironmentaspect.cpp localenvironmentaspect.h localenvironmentaspect.cpp localenvironmentaspect.h
makestep.cpp makestep.h makestep.ui makestep.cpp makestep.h makestep.ui

View File

@@ -25,6 +25,7 @@
#include "gccparser.h" #include "gccparser.h"
#include "ldparser.h" #include "ldparser.h"
#include "lldparser.h"
#include "task.h" #include "task.h"
#include "projectexplorerconstants.h" #include "projectexplorerconstants.h"
#include "buildmanager.h" #include "buildmanager.h"
@@ -34,6 +35,7 @@
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
using namespace ProjectExplorer; using namespace ProjectExplorer;
using namespace Utils;
// opt. drive letter + filename: (2 brackets) // opt. drive letter + filename: (2 brackets)
static const char FILE_PATTERN[] = "(<command[ -]line>|([A-Za-z]:)?[^:]+):"; static const char FILE_PATTERN[] = "(<command[ -]line>|([A-Za-z]:)?[^:]+):";
@@ -58,6 +60,7 @@ GccParser::GccParser()
m_regExpGccNames.setPattern(QLatin1String(COMMAND_PATTERN)); m_regExpGccNames.setPattern(QLatin1String(COMMAND_PATTERN));
QTC_CHECK(m_regExpGccNames.isValid()); QTC_CHECK(m_regExpGccNames.isValid());
appendOutputParser(new Internal::LldParser);
appendOutputParser(new LdParser); appendOutputParser(new LdParser);
} }
@@ -875,6 +878,130 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
) )
<< QString(); << QString();
const auto task = [categoryCompile](Task::TaskType type, const QString &msg,
const QString &file = {}, int line = -1) {
return Task(type, msg, FilePath::fromString(file), line, categoryCompile);
};
const auto errorTask = [&task](const QString &msg, const QString &file = {}, int line = -1) {
return task(Task::Error, msg, file, line);
};
const auto unknownTask = [&task](const QString &msg, const QString &file = {}, int line = -1) {
return task(Task::Unknown, msg, file, line);
};
QTest::newRow("lld: undefined reference with debug info")
<< "ld.lld: error: undefined symbol: func()\n"
">>> referenced by test.cpp:5\n"
">>> /tmp/ccg8pzRr.o:(main)\n"
"collect2: error: ld returned 1 exit status"
<< OutputParserTester::STDERR << QString() << QString()
<< Tasks{
errorTask("ld.lld: error: undefined symbol: func()"),
unknownTask("referenced by test.cpp:5", "test.cpp", 5),
unknownTask("/tmp/ccg8pzRr.o:(main)", "/tmp/ccg8pzRr.o"),
errorTask("collect2: error: ld returned 1 exit status")}
<< QString();
QTest::newRow("lld: undefined reference with debug info (more verbose format)")
<< "ld.lld: error: undefined symbol: someFunc()\n"
">>> referenced by main.cpp:10 (/tmp/untitled4/main.cpp:10)\n"
">>> /tmp/Debug4/untitled4.5abe06ac/3a52ce780950d4d9/main.cpp.o:(main)\n"
"clang-8: error: linker command failed with exit code 1 (use -v to see invocation)"
<< OutputParserTester::STDERR << QString()
<< QString("clang-8: error: linker command failed with exit code 1 (use -v to see invocation)\n")
<< Tasks{
errorTask("ld.lld: error: undefined symbol: someFunc()"),
unknownTask("referenced by main.cpp:10 (/tmp/untitled4/main.cpp:10)",
"/tmp/untitled4/main.cpp", 10),
unknownTask("/tmp/Debug4/untitled4.5abe06ac/3a52ce780950d4d9/main.cpp.o:(main)",
"/tmp/Debug4/untitled4.5abe06ac/3a52ce780950d4d9/main.cpp.o")}
<< QString();
QTest::newRow("lld: undefined reference without debug info")
<< "ld.lld: error: undefined symbol: func()\n"
">>> referenced by test.cpp\n"
">>> /tmp/ccvjyJph.o:(main)\n"
"collect2: error: ld returned 1 exit status"
<< OutputParserTester::STDERR << QString() << QString()
<< Tasks{
errorTask("ld.lld: error: undefined symbol: func()"),
unknownTask("referenced by test.cpp", "test.cpp"),
unknownTask("/tmp/ccvjyJph.o:(main)", "/tmp/ccvjyJph.o"),
errorTask("collect2: error: ld returned 1 exit status")}
<< QString();
if (HostOsInfo::isWindowsHost()) {
QTest::newRow("lld: undefined reference with mingw")
<< "lld-link: error: undefined symbol: __Z4funcv\n"
">>> referenced by C:\\Users\\orgads\\AppData\\Local\\Temp\\cccApKoz.o:(.text)\n"
"collect2.exe: error: ld returned 1 exit status"
<< OutputParserTester::STDERR << QString() << QString()
<< Tasks{
errorTask("lld-link: error: undefined symbol: __Z4funcv"),
unknownTask("referenced by C:\\Users\\orgads\\AppData\\Local\\Temp\\cccApKoz.o:(.text)",
"C:/Users/orgads/AppData/Local/Temp/cccApKoz.o"),
errorTask("collect2.exe: error: ld returned 1 exit status")}
<< QString();
}
QTest::newRow("lld: multiple definitions with debug info")
<< "ld.lld: error: duplicate symbol: func()\n"
">>> defined at test1.cpp:1\n"
">>> test1.o:(func())\n"
">>> defined at test1.cpp:1\n"
">>> test1.o:(.text+0x0)\n"
"collect2: error: ld returned 1 exit status"
<< OutputParserTester::STDERR << QString() << QString()
<< Tasks{
errorTask("ld.lld: error: duplicate symbol: func()"),
unknownTask("defined at test1.cpp:1", "test1.cpp", 1),
unknownTask("test1.o:(func())", "test1.o"),
unknownTask("defined at test1.cpp:1", "test1.cpp", 1),
unknownTask("test1.o:(.text+0x0)", "test1.o"),
errorTask("collect2: error: ld returned 1 exit status")}
<< QString();
QTest::newRow("lld: multiple definitions with debug info (more verbose format)")
<< "ld.lld: error: duplicate symbol: theFunc()\n"
">>> defined at file.cpp:1 (/tmp/untitled3/file.cpp:1)\n"
">>> /tmp/Debug/untitled3.dade828b/3a52ce780950d4d9/file.cpp.o:(theFunc())\n"
">>> defined at main.cpp:5 (/tmp/untitled3/main.cpp:5)\n"
">>> /tmp/Debug/untitled3.dade828b/3a52ce780950d4d9/main.cpp.o:(.text+0x0)\n"
"collect2: error: ld returned 1 exit status"
<< OutputParserTester::STDERR << QString() << QString()
<< Tasks{
errorTask("ld.lld: error: duplicate symbol: theFunc()"),
unknownTask("defined at file.cpp:1 (/tmp/untitled3/file.cpp:1)",
"/tmp/untitled3/file.cpp", 1),
unknownTask("/tmp/Debug/untitled3.dade828b/3a52ce780950d4d9/file.cpp.o:(theFunc())",
"/tmp/Debug/untitled3.dade828b/3a52ce780950d4d9/file.cpp.o"),
unknownTask("defined at main.cpp:5 (/tmp/untitled3/main.cpp:5)",
"/tmp/untitled3/main.cpp", 5),
unknownTask("/tmp/Debug/untitled3.dade828b/3a52ce780950d4d9/main.cpp.o:(.text+0x0)",
"/tmp/Debug/untitled3.dade828b/3a52ce780950d4d9/main.cpp.o"),
errorTask("collect2: error: ld returned 1 exit status")}
<< QString();
QTest::newRow("lld: multiple definitions without debug info")
<< "ld.lld: error: duplicate symbol: func()\n"
">>> defined at test1.cpp\n"
">>> test1.o:(func())\n"
">>> defined at test1.cpp\n"
">>> test1.o:(.text+0x0)\n"
"collect2: error: ld returned 1 exit status"
<< OutputParserTester::STDERR << QString() << QString()
<< Tasks{
errorTask("ld.lld: error: duplicate symbol: func()"),
unknownTask("defined at test1.cpp", "test1.cpp"),
unknownTask("test1.o:(func())", "test1.o"),
unknownTask("defined at test1.cpp", "test1.cpp"),
unknownTask("test1.o:(.text+0x0)", "test1.o"),
errorTask("collect2: error: ld returned 1 exit status")}
<< QString();
if (HostOsInfo::isWindowsHost()) {
QTest::newRow("lld: multiple definitions with mingw")
<< "lld-link: error: duplicate symbol: __Z4funcv in test1.o and in test2.o\n"
"collect2.exe: error: ld returned 1 exit status"
<< OutputParserTester::STDERR << QString() << QString()
<< Tasks{
errorTask("lld-link: error: duplicate symbol: __Z4funcv in test1.o and in test2.o"),
errorTask("collect2.exe: error: ld returned 1 exit status", {})}
<< QString();
}
QTest::newRow("Mac: ranlib warning") QTest::newRow("Mac: ranlib warning")
<< QString::fromLatin1("ranlib: file: lib/libtest.a(Test0.cpp.o) has no symbols") << QString::fromLatin1("ranlib: file: lib/libtest.a(Test0.cpp.o) has no symbols")
<< OutputParserTester::STDERR << OutputParserTester::STDERR

View File

@@ -65,7 +65,7 @@ void LdParser::stdError(const QString &line)
return; return;
} }
if (lne.startsWith(QLatin1String("collect2:"))) { if (lne.startsWith("collect2:") || lne.startsWith("collect2.exe:")) {
Task task = Task(Task::Error, Task task = Task(Task::Error,
lne /* description */, lne /* description */,
Utils::FilePath() /* filename */, Utils::FilePath() /* filename */,

View File

@@ -25,6 +25,7 @@
#include "linuxiccparser.h" #include "linuxiccparser.h"
#include "ldparser.h" #include "ldparser.h"
#include "lldparser.h"
#include "projectexplorerconstants.h" #include "projectexplorerconstants.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -62,6 +63,7 @@ LinuxIccParser::LinuxIccParser() :
m_pchInfoLine.setMinimal(true); m_pchInfoLine.setMinimal(true);
QTC_CHECK(m_pchInfoLine.isValid()); QTC_CHECK(m_pchInfoLine.isValid());
appendOutputParser(new Internal::LldParser);
appendOutputParser(new LdParser); appendOutputParser(new LdParser);
} }

View File

@@ -0,0 +1,76 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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
** 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.
**
** 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.
**
****************************************************************************/
#include "lldparser.h"
#include "projectexplorerconstants.h"
#include "task.h"
#include <utils/fileutils.h>
#include <QStringList>
namespace ProjectExplorer {
namespace Internal {
void LldParser::stdError(const QString &line)
{
const QString trimmedLine = rightTrimmed(line);
if (trimmedLine.contains("error:") && trimmedLine.contains("lld")) {
emit addTask({Task::Error, trimmedLine, Utils::FilePath(), -1,
Constants::TASK_CATEGORY_COMPILE});
return;
}
static const QStringList prefixes{">>> referenced by ", ">>> defined at ", ">>> "};
for (const QString &prefix : prefixes) {
if (!trimmedLine.startsWith(prefix))
continue;
int lineNo = -1;
const int locOffset = trimmedLine.lastIndexOf(':');
if (locOffset != -1) {
const int endLocOffset = trimmedLine.indexOf(')', locOffset);
const int numberWidth = endLocOffset == -1 ? -1 : endLocOffset - locOffset - 1;
bool isNumber = true;
lineNo = trimmedLine.mid(locOffset + 1, numberWidth).toInt(&isNumber);
if (!isNumber)
lineNo = -1;
}
int filePathOffset = trimmedLine.lastIndexOf('(', locOffset);
if (filePathOffset != -1)
++filePathOffset;
else
filePathOffset = prefix.length();
const int filePathLen = locOffset == -1 ? -1 : locOffset - filePathOffset;
const auto file = Utils::FilePath::fromUserInput(
trimmedLine.mid(filePathOffset, filePathLen).trimmed());
emit addTask({Task::Unknown, trimmedLine.mid(4).trimmed(), file, lineNo,
Constants::TASK_CATEGORY_COMPILE});
return;
}
IOutputParser::stdError(line);
}
} // namespace Internal
} // namespace ProjectExplorer

View File

@@ -0,0 +1,39 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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
** 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.
**
** 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.
**
****************************************************************************/
#pragma once
#include "ioutputparser.h"
namespace ProjectExplorer {
namespace Internal {
class LldParser : public IOutputParser
{
void stdError(const QString &line) override;
};
} // namespace Internal
} // namespace ProjectExplorer

View File

@@ -102,6 +102,7 @@ HEADERS += projectexplorer.h \
miniprojecttargetselector.h \ miniprojecttargetselector.h \
buildenvironmentwidget.h \ buildenvironmentwidget.h \
ldparser.h \ ldparser.h \
lldparser.h \
linuxiccparser.h \ linuxiccparser.h \
runconfigurationaspects.h \ runconfigurationaspects.h \
processparameters.h \ processparameters.h \
@@ -253,6 +254,7 @@ SOURCES += projectexplorer.cpp \
miniprojecttargetselector.cpp \ miniprojecttargetselector.cpp \
buildenvironmentwidget.cpp \ buildenvironmentwidget.cpp \
ldparser.cpp \ ldparser.cpp \
lldparser.cpp \
linuxiccparser.cpp \ linuxiccparser.cpp \
runconfigurationaspects.cpp \ runconfigurationaspects.cpp \
taskhub.cpp \ taskhub.cpp \

View File

@@ -91,6 +91,7 @@ Project {
"kitmodel.cpp", "kitmodel.h", "kitmodel.cpp", "kitmodel.h",
"kitoptionspage.cpp", "kitoptionspage.h", "kitoptionspage.cpp", "kitoptionspage.h",
"ldparser.cpp", "ldparser.h", "ldparser.cpp", "ldparser.h",
"lldparser.cpp", "lldparser.h",
"linuxiccparser.cpp", "linuxiccparser.h", "linuxiccparser.cpp", "linuxiccparser.h",
"localenvironmentaspect.cpp", "localenvironmentaspect.h", "localenvironmentaspect.cpp", "localenvironmentaspect.h",
"makestep.cpp", "makestep.h", "makestep.ui", "makestep.cpp", "makestep.h", "makestep.ui",