Differential D8317 Diff 20822 plugins/custom-definesandincludes/compilerprovider/gcclikecompiler.cpp
Changeset View
Changeset View
Standalone View
Standalone View
plugins/custom-definesandincludes/compilerprovider/gcclikecompiler.cpp
Show All 30 Lines | |||||
31 | #include <interfaces/iruntimecontroller.h> | 31 | #include <interfaces/iruntimecontroller.h> | ||
32 | 32 | | |||
33 | #include <debug.h> | 33 | #include <debug.h> | ||
34 | 34 | | |||
35 | using namespace KDevelop; | 35 | using namespace KDevelop; | ||
36 | 36 | | |||
37 | namespace | 37 | namespace | ||
38 | { | 38 | { | ||
39 | // compilers don't deduplicate QStringLiteral | | |||
40 | QString minusXC() { return QStringLiteral("-xc"); } | | |||
41 | QString minusXCPlusPlus() { return QStringLiteral("-xc++"); } | | |||
42 | 39 | | |||
43 | QStringList languageOptions(const QString& arguments) | 40 | QString languageOption(Utils::LanguageType type) | ||
44 | { | 41 | { | ||
42 | switch (type) { | ||||
43 | case Utils::C: | ||||
44 | return QStringLiteral("-xc"); | ||||
45 | case Utils::Cpp: | ||||
46 | return QStringLiteral("-xc++"); | ||||
47 | case Utils::OpenCl: | ||||
48 | return QStringLiteral("-xcl"); | ||||
49 | case Utils::Cuda: | ||||
50 | return QStringLiteral("-xcuda"); | ||||
51 | case Utils::ObjC: | ||||
52 | return QStringLiteral("-xobjective-c"); | ||||
53 | default: | ||||
54 | Q_UNREACHABLE(); | ||||
aaronpuchert: Clang can't really parse `Utils::Other` files, so there is nothing reasonable we can do here. | |||||
55 | } | ||||
56 | } | ||||
45 | 57 | | |||
58 | QString languageStandard(const QString& arguments) | ||||
59 | { | ||||
46 | // TODO: handle -ansi flag: In C mode, this is equivalent to -std=c90. In C++ mode, it is equivalent to -std=c++98. | 60 | // TODO: handle -ansi flag: In C mode, this is equivalent to -std=c90. In C++ mode, it is equivalent to -std=c++98. | ||
47 | // TODO: check for -x flag on command line | | |||
48 | const QRegularExpression regexp(QStringLiteral("-std=(\\S+)")); | 61 | const QRegularExpression regexp(QStringLiteral("-std=(\\S+)")); | ||
49 | // see gcc manpage or llvm/tools/clang/include/clang/Frontend/LangStandards.def for list of valid language options | | |||
50 | auto result = regexp.match(arguments); | 62 | auto result = regexp.match(arguments); | ||
51 | if(result.hasMatch()){ | 63 | if (result.hasMatch()) | ||
52 | const auto standard = result.captured(0); | 64 | return result.captured(0); | ||
53 | const auto mode = result.capturedRef(1); | | |||
54 | QString language; | | |||
55 | if (mode.startsWith(QLatin1String("c++")) || mode.startsWith(QLatin1String("gnu++"))) { | | |||
56 | language = minusXCPlusPlus(); | | |||
57 | } else if (mode.startsWith(QLatin1String("iso9899:"))) { | | |||
58 | // all iso9899:xxxxx modes are C standards | | |||
59 | language = minusXC(); | | |||
60 | } else { | | |||
61 | // check for c11, gnu99, etc: all of them have a digit after the c/gnu | | |||
62 | const QRegularExpression cRegexp(QStringLiteral("(c|gnu)\\d.*")); | | |||
63 | if (cRegexp.match(mode).hasMatch()) { | | |||
64 | language = minusXC(); | | |||
65 | } | | |||
66 | } | | |||
67 | if (language.isEmpty()) { | | |||
68 | qCWarning(DEFINESANDINCLUDES) << "Failed to determine language from -std= flag:" << arguments; | | |||
69 | language = minusXCPlusPlus(); | | |||
70 | } | | |||
71 | return {standard, language}; | | |||
72 | 65 | | |||
73 | } | | |||
74 | // no -std= flag passed -> assume c++11 | 66 | // no -std= flag passed -> assume c++11 | ||
75 | return {QStringLiteral("-std=c++11"), minusXCPlusPlus()}; | 67 | return QStringLiteral("-std=c++11"); | ||
76 | } | 68 | } | ||
77 | 69 | | |||
78 | } | 70 | } | ||
79 | 71 | | |||
80 | Defines GccLikeCompiler::defines(const QString& arguments) const | 72 | Defines GccLikeCompiler::defines(Utils::LanguageType type, const QString& arguments) const | ||
81 | { | 73 | { | ||
82 | auto& data = m_definesIncludes[arguments]; | 74 | auto& data = m_definesIncludes[arguments]; | ||
83 | if (!data.definedMacros.isEmpty() ) { | 75 | if (!data.definedMacros.isEmpty() ) { | ||
84 | return data.definedMacros; | 76 | return data.definedMacros; | ||
85 | } | 77 | } | ||
86 | 78 | | |||
87 | // #define a 1 | 79 | // #define a 1 | ||
88 | // #define a | 80 | // #define a | ||
89 | QRegExp defineExpression( "#define\\s+(\\S+)(?:\\s+(.*)\\s*)?"); | 81 | QRegExp defineExpression( "#define\\s+(\\S+)(?:\\s+(.*)\\s*)?"); | ||
90 | 82 | | |||
91 | const auto rt = ICore::self()->runtimeController()->currentRuntime(); | 83 | const auto rt = ICore::self()->runtimeController()->currentRuntime(); | ||
92 | QProcess proc; | 84 | QProcess proc; | ||
93 | proc.setProcessChannelMode( QProcess::MergedChannels ); | 85 | proc.setProcessChannelMode( QProcess::MergedChannels ); | ||
94 | 86 | | |||
95 | // TODO: what about -mXXX or -target= flags, some of these change search paths/defines | 87 | // TODO: what about -mXXX or -target= flags, some of these change search paths/defines | ||
96 | auto compilerArguments = languageOptions(arguments); | 88 | QStringList compilerArguments{languageOption(type), languageStandard(arguments)}; | ||
97 | compilerArguments.append(QStringLiteral("-dM")); | 89 | compilerArguments.append(QStringLiteral("-dM")); | ||
98 | compilerArguments.append(QStringLiteral("-E")); | 90 | compilerArguments.append(QStringLiteral("-E")); | ||
99 | compilerArguments.append(QProcess::nullDevice()); | 91 | compilerArguments.append(QProcess::nullDevice()); | ||
100 | 92 | | |||
101 | proc.setProgram(path()); | 93 | proc.setProgram(path()); | ||
102 | proc.setArguments(compilerArguments); | 94 | proc.setArguments(compilerArguments); | ||
103 | rt->startProcess(&proc); | 95 | rt->startProcess(&proc); | ||
104 | 96 | | |||
Show All 13 Lines | 107 | while ( proc.canReadLine() ) { | |||
118 | if ( defineExpression.indexIn( line ) != -1 ) { | 110 | if ( defineExpression.indexIn( line ) != -1 ) { | ||
119 | data.definedMacros[defineExpression.cap( 1 )] = defineExpression.cap( 2 ).trimmed(); | 111 | data.definedMacros[defineExpression.cap( 1 )] = defineExpression.cap( 2 ).trimmed(); | ||
120 | } | 112 | } | ||
121 | } | 113 | } | ||
122 | 114 | | |||
123 | return data.definedMacros; | 115 | return data.definedMacros; | ||
124 | } | 116 | } | ||
125 | 117 | | |||
126 | Path::List GccLikeCompiler::includes(const QString& arguments) const | 118 | Path::List GccLikeCompiler::includes(Utils::LanguageType type, const QString& arguments) const | ||
127 | { | 119 | { | ||
128 | auto& data = m_definesIncludes[arguments]; | 120 | auto& data = m_definesIncludes[arguments]; | ||
129 | if ( !data.includePaths.isEmpty() ) { | 121 | if ( !data.includePaths.isEmpty() ) { | ||
130 | return data.includePaths; | 122 | return data.includePaths; | ||
131 | } | 123 | } | ||
132 | 124 | | |||
133 | const auto rt = ICore::self()->runtimeController()->currentRuntime(); | 125 | const auto rt = ICore::self()->runtimeController()->currentRuntime(); | ||
134 | QProcess proc; | 126 | QProcess proc; | ||
135 | proc.setProcessChannelMode( QProcess::MergedChannels ); | 127 | proc.setProcessChannelMode( QProcess::MergedChannels ); | ||
136 | 128 | | |||
137 | // The following command will spit out a bunch of information we don't care | 129 | // The following command will spit out a bunch of information we don't care | ||
138 | // about before spitting out the include paths. The parts we care about | 130 | // about before spitting out the include paths. The parts we care about | ||
139 | // look like this: | 131 | // look like this: | ||
140 | // #include "..." search starts here: | 132 | // #include "..." search starts here: | ||
141 | // #include <...> search starts here: | 133 | // #include <...> search starts here: | ||
142 | // /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2 | 134 | // /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2 | ||
143 | // /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/i486-linux-gnu | 135 | // /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/i486-linux-gnu | ||
144 | // /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/backward | 136 | // /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/backward | ||
145 | // /usr/local/include | 137 | // /usr/local/include | ||
146 | // /usr/lib/gcc/i486-linux-gnu/4.1.2/include | 138 | // /usr/lib/gcc/i486-linux-gnu/4.1.2/include | ||
147 | // /usr/include | 139 | // /usr/include | ||
148 | // End of search list. | 140 | // End of search list. | ||
149 | 141 | | |||
150 | auto compilerArguments = languageOptions(arguments); | 142 | QStringList compilerArguments{languageOption(type), languageStandard(arguments)}; | ||
151 | compilerArguments.append(QStringLiteral("-E")); | 143 | compilerArguments.append(QStringLiteral("-E")); | ||
152 | compilerArguments.append(QStringLiteral("-v")); | 144 | compilerArguments.append(QStringLiteral("-v")); | ||
153 | compilerArguments.append(QProcess::nullDevice()); | 145 | compilerArguments.append(QProcess::nullDevice()); | ||
154 | 146 | | |||
155 | proc.setProgram(path()); | 147 | proc.setProgram(path()); | ||
156 | proc.setArguments(compilerArguments); | 148 | proc.setArguments(compilerArguments); | ||
157 | rt->startProcess(&proc); | 149 | rt->startProcess(&proc); | ||
158 | 150 | | |||
▲ Show 20 Lines • Show All 64 Lines • Show Last 20 Lines |
Clang can't really parse Utils::Other files, so there is nothing reasonable we can do here.
Of course we can fix that particular bug by returning an empty string instead.