1 | // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. |
2 | // |
3 | // SPDX-License-Identifier: GPL-3.0-or-later |
4 | |
5 | #include "ldparser.h" |
6 | |
7 | #include "ldparser.h" |
8 | #include "services/builder/task.h" |
9 | |
10 | #include "common/util/qtcassert.h" |
11 | |
12 | namespace { |
13 | // opt. drive letter + filename: (2 brackets) |
14 | const char * const FILE_PATTERN = "(([A-Za-z]:)?[^:]+\\.[^:]+):" ; |
15 | // line no. or elf segment + offset (1 bracket) |
16 | const char * const POSITION_PATTERN = "(\\S+|\\(\\..+?[+-]0x[a-fA-F0-9]+\\)):" ; |
17 | const char * const COMMAND_PATTERN = "^(.*[\\\\/])?([a-z0-9]+-[a-z0-9]+-[a-z0-9]+-)?(ld|gold)(-[0-9\\.]+)?(\\.exe)?: " ; |
18 | const char *const RANLIB_PATTERN = "ranlib(.exe)?: (file: (.*) has no symbols)$" ; |
19 | } |
20 | |
21 | const char TASK_CATEGORY_COMPILE[] = "Task.Category.Compile" ; |
22 | |
23 | LdParser::LdParser() |
24 | { |
25 | setObjectName(QLatin1String("LdParser" )); |
26 | ranlib.setPattern(QLatin1String(RANLIB_PATTERN)); |
27 | QTC_CHECK(ranlib.isValid()); |
28 | regExpLinker.setPattern(QLatin1Char('^') + |
29 | QString::fromLatin1(FILE_PATTERN) + QLatin1Char('(') + |
30 | QString::fromLatin1(FILE_PATTERN) + QLatin1String(")?(" ) + |
31 | QLatin1String(POSITION_PATTERN) + QLatin1String(")?\\s(.+)$" )); |
32 | QTC_CHECK(regExpLinker.isValid()); |
33 | |
34 | regExpGccNames.setPattern(QLatin1String(COMMAND_PATTERN)); |
35 | QTC_CHECK(regExpGccNames.isValid()); |
36 | } |
37 | |
38 | void LdParser::stdError(const QString &line) |
39 | { |
40 | QString lne = rightTrimmed(line); |
41 | if (lne.startsWith(QLatin1String("TeamBuilder " )) |
42 | || lne.startsWith(QLatin1String("distcc[" )) |
43 | || lne.contains(QLatin1String("ar: creating " ))) { |
44 | IOutputParser::stdError(line); |
45 | return; |
46 | } |
47 | |
48 | if (lne.startsWith(QLatin1String("collect2:" ))) { |
49 | Task task = Task(Task::Error, |
50 | lne /* description */, |
51 | Utils::FileName() /* filename */, |
52 | -1 /* linenumber */, |
53 | TASK_CATEGORY_COMPILE); |
54 | emit addTask(task, 1); |
55 | return; |
56 | } |
57 | |
58 | QRegularExpressionMatch match = ranlib.match(lne); |
59 | if (match.hasMatch()) { |
60 | QString description = match.captured(2); |
61 | Task task(Task::Warning, description, |
62 | Utils::FileName(), -1, |
63 | TASK_CATEGORY_COMPILE); |
64 | emit addTask(task, 1); |
65 | return; |
66 | } |
67 | |
68 | match = regExpGccNames.match(lne); |
69 | if (match.hasMatch()) { |
70 | QString description = lne.mid(match.capturedLength()); |
71 | Task::TaskType type = Task::Error; |
72 | if (description.startsWith(QLatin1String("warning: " ))) { |
73 | type = Task::Warning; |
74 | description = description.mid(9); |
75 | } else if (description.startsWith(QLatin1String("fatal: " ))) { |
76 | description = description.mid(7); |
77 | } |
78 | Task task(type, description, Utils::FileName() /* filename */, -1 /* line */, |
79 | TASK_CATEGORY_COMPILE); |
80 | emit addTask(task, 1); |
81 | return; |
82 | } |
83 | |
84 | match = regExpLinker.match(lne); |
85 | if (match.hasMatch()) { |
86 | bool ok; |
87 | int lineno = match.captured(7).toInt(&ok); |
88 | if (!ok) |
89 | lineno = -1; |
90 | Utils::FileName filename = Utils::FileName::fromUserInput(match.captured(1)); |
91 | const QString sourceFileName = match.captured(4); |
92 | if (!sourceFileName.isEmpty() |
93 | && !sourceFileName.startsWith(QLatin1String("(.text" )) |
94 | && !sourceFileName.startsWith(QLatin1String("(.data" ))) { |
95 | filename = Utils::FileName::fromUserInput(sourceFileName); |
96 | } |
97 | QString description = match.captured(8).trimmed(); |
98 | Task::TaskType type = Task::Error; |
99 | if (description.startsWith(QLatin1String("At global scope" )) || |
100 | description.startsWith(QLatin1String("At top level" )) || |
101 | description.startsWith(QLatin1String("instantiated from " )) || |
102 | description.startsWith(QLatin1String("In " )) || |
103 | description.startsWith(QLatin1String("first defined here" )) || |
104 | description.startsWith(QLatin1String("note:" ), Qt::CaseInsensitive)) { |
105 | type = Task::Unknown; |
106 | } else if (description.startsWith(QLatin1String("warning: " ), Qt::CaseInsensitive)) { |
107 | type = Task::Warning; |
108 | description = description.mid(9); |
109 | } |
110 | Task task(type, description, filename, lineno, TASK_CATEGORY_COMPILE); |
111 | emit addTask(task, 1); |
112 | return; |
113 | } |
114 | |
115 | IOutputParser::stdError(line); |
116 | } |
117 | |