25
25
#include " indexer/LlvmCommandLineParsing.h"
26
26
27
27
namespace {
28
- enum class CompilerKind {
29
- Gcc,
30
- Clang,
31
- };
32
28
33
29
struct CompletedProcess {
34
30
int exitCode;
@@ -41,12 +37,87 @@ struct CompletedProcess {
41
37
}
42
38
};
43
39
44
- struct ToolchainPathsResult {
40
+ using ToolchainInfo = scip_clang::compdb::ToolchainInfo;
41
+ using CompilerKind = scip_clang::compdb::CompilerKind;
42
+
43
+ struct ClangToolchainInfo : ToolchainInfo {
45
44
std::string resourceDir;
46
- std::vector<std::string> cliInvocation;
47
- CompilerKind compilerKind;
48
- std::string compilerDriverPath; // non-null for Clang
45
+ std::vector<std::string> findResourceDirInvocation;
46
+ std::string compilerDriverPath;
47
+ std::vector<std::string> findDriverInvocation;
48
+
49
+ // All strings and vectors above should be non-empty for
50
+ // a valid toolchain.
51
+
52
+ ClangToolchainInfo (std::string resourceDir,
53
+ std::vector<std::string> findResourceDirInvocation,
54
+ std::string compilerDriverPath,
55
+ std::vector<std::string> findDriverInvocation)
56
+ : ToolchainInfo(), resourceDir(resourceDir),
57
+ findResourceDirInvocation (findResourceDirInvocation),
58
+ compilerDriverPath(compilerDriverPath),
59
+ findDriverInvocation(findDriverInvocation){};
60
+
61
+ virtual CompilerKind kind () const override {
62
+ return CompilerKind::Clang;
63
+ }
64
+
65
+ virtual bool isWellFormed () const override {
66
+ if (!std::filesystem::exists (this ->resourceDir )) {
67
+ spdlog::error (
68
+ " clang resource directory '{}' does not exist (obtained via {})" ,
69
+ this ->resourceDir , fmt::join (this ->findResourceDirInvocation , " " ));
70
+ return false ;
71
+ }
72
+ if (!std::filesystem::exists (this ->compilerDriverPath )) {
73
+ spdlog::error (" compiler driver at '{}' does not exist (obtained via {})" ,
74
+ this ->compilerDriverPath ,
75
+ fmt::join (this ->findDriverInvocation , " " ));
76
+ return false ;
77
+ }
78
+ return true ;
79
+ }
80
+
81
+ virtual void
82
+ adjustCommandLine (std::vector<std::string> &commandLine) const override {
83
+ commandLine[0 ] = this ->compilerDriverPath ;
84
+ commandLine.push_back (" -resource-dir" );
85
+ commandLine.push_back (this ->resourceDir );
86
+ }
49
87
};
88
+
89
+ struct GccToolchainInfo : ToolchainInfo {
90
+ std::string installDir;
91
+ std::vector<std::string> findInstallDirInvocation;
92
+
93
+ GccToolchainInfo (std::string installDir,
94
+ std::vector<std::string> findInstallDirInvocation)
95
+ : ToolchainInfo(), installDir(installDir),
96
+ findInstallDirInvocation (findInstallDirInvocation) {}
97
+
98
+ virtual CompilerKind kind () const override {
99
+ return CompilerKind::Gcc;
100
+ }
101
+
102
+ virtual bool isWellFormed () const override {
103
+ if (!std::filesystem::exists (this ->installDir )) {
104
+ spdlog::error (
105
+ " GCC install directory '{}' does not exist (obtained via {})" ,
106
+ this ->installDir , fmt::join (this ->findInstallDirInvocation , " " ));
107
+ return false ;
108
+ }
109
+ return true ;
110
+ }
111
+
112
+ virtual void
113
+ adjustCommandLine (std::vector<std::string> &commandLine) const override {
114
+ commandLine.push_back (" -resource-dir" );
115
+ commandLine.push_back (this ->installDir );
116
+ // gcc-7 adds headers like limits.h and syslimits.h in include-fixed
117
+ commandLine.push_back (fmt::format (" -I{}/include-fixed" , this ->installDir ));
118
+ }
119
+ };
120
+
50
121
} // namespace
51
122
52
123
static CompletedProcess runProcess (std::vector<std::string> &args,
@@ -78,81 +149,92 @@ static CompletedProcess runProcess(std::vector<std::string> &args,
78
149
return out;
79
150
}
80
151
81
- // / Returns an empty path if we failed to determine the resource dir
82
- ToolchainPathsResult static determineToolchainPaths (
83
- const scip_clang::AbsolutePath &compilerPath) {
84
- ToolchainPathsResult out{" " ,
85
- {compilerPath.asStringRef (), " -print-resource-dir" },
86
- CompilerKind::Clang,
87
- " " };
152
+ /* static*/ std::unique_ptr<ToolchainInfo>
153
+ ToolchainInfo::infer (const scip_clang::AbsolutePath &compilerPath) {
88
154
89
155
auto noteStdlib = []() {
90
156
spdlog::warn (" may be unable to locate standard library headers" );
91
157
spdlog::info (" compilation errors are suppressed by default, but can be "
92
158
" turned on using --show-compiler-diagnostics" );
93
159
};
94
160
95
- auto printResourceDirResult =
96
- ::runProcess (out.cliInvocation, " attempting to find resource dir" );
161
+ std::vector<std::string> findResourceDirInvocation = {
162
+ compilerPath.asStringRef (), " -print-resource-dir" };
163
+ auto failure = std::unique_ptr<ToolchainInfo>(nullptr );
164
+
165
+ auto printResourceDirResult = ::runProcess (findResourceDirInvocation,
166
+ " attempting to find resource dir" );
97
167
if (printResourceDirResult.isSuccess ()) {
98
168
if (printResourceDirResult.stdoutLines .empty ()) {
99
- spdlog::warn (
100
- " -print-resource-dir succeeded but returned an empty result " );
101
- return out ;
169
+ spdlog::warn (" {} succeeded but returned an empty result " ,
170
+ fmt::join (findResourceDirInvocation, " " ) );
171
+ return failure ;
102
172
}
103
- out. resourceDir = std::string (
173
+ auto resourceDir = std::string (
104
174
absl::StripAsciiWhitespace (printResourceDirResult.stdoutLines .front ()));
105
- out.cliInvocation = {compilerPath.asStringRef (), " -###" };
175
+ spdlog::debug (" got resource dir {} from {}" , resourceDir,
176
+ compilerPath.asStringRef ());
177
+
178
+ std::vector<std::string> findDriverInvocation = {compilerPath.asStringRef (),
179
+ " -###" };
106
180
auto hashHashHashResult = ::runProcess (
107
- out.cliInvocation , " attempting to find installed directory" );
181
+ findDriverInvocation, " attempting to find installed directory" );
182
+ std::string compilerDriverPath = " " ;
108
183
if (hashHashHashResult.isSuccess ()) {
109
184
for (auto &line : hashHashHashResult.stderrLines ) {
110
185
auto clangDriverDir = absl::StripPrefix (line, " InstalledDir: " );
111
186
if (clangDriverDir.length () != line.length ()) {
112
- out.compilerDriverPath = absl::StripAsciiWhitespace (clangDriverDir);
113
- out.compilerDriverPath .push_back (
114
- std::filesystem::path::preferred_separator);
115
- out.compilerDriverPath .append (" clang" );
187
+ compilerDriverPath = scip_clang::joinPath (
188
+ absl::StripAsciiWhitespace (clangDriverDir), " clang" );
189
+ spdlog::debug (" found compiler driver at {}" , compilerDriverPath);
116
190
break ;
117
191
}
118
192
}
119
193
}
120
- if (out. compilerDriverPath .empty ()) {
194
+ if (compilerDriverPath.empty ()) {
121
195
spdlog::warn (
122
196
" failed to determine compiler path using -### for compiler at '{}'" ,
123
197
compilerPath.asStringRef ());
124
198
noteStdlib ();
199
+ return failure;
125
200
}
126
- return out;
201
+
202
+ return std::make_unique<ClangToolchainInfo>(
203
+ resourceDir, findResourceDirInvocation, compilerDriverPath,
204
+ findDriverInvocation);
127
205
}
128
- out.compilerKind = CompilerKind::Gcc;
129
- out.cliInvocation = {compilerPath.asStringRef (), " -print-search-dirs" };
206
+
207
+ std::vector<std::string> findSearchDirsInvocation = {
208
+ compilerPath.asStringRef (), " -print-search-dirs" };
130
209
auto printSearchDirsResult =
131
- ::runProcess (out.cliInvocation, " attempting to find search dirs" );
132
- if (!printSearchDirsResult.isSuccess ()) {
133
- spdlog::warn (
134
- " both -print-resource-dir and -print-search-dirs failed for {}" ,
135
- compilerPath.asStringRef ());
136
- noteStdlib ();
137
- return out;
138
- }
139
- absl::c_any_of (
140
- printSearchDirsResult.stdoutLines , [&](const std::string &line) -> bool {
141
- if (line.starts_with (" install:" )) {
142
- out.resourceDir =
143
- absl::StripAsciiWhitespace (absl::StripPrefix (line, " install:" ));
144
- return true ;
145
- }
146
- return false ;
147
- });
148
- if (out.resourceDir .empty ()) {
149
- spdlog::warn (
150
- " missing 'install:' line in -print-search-dirs from GCC(-like?) {}" ,
151
- compilerPath.asStringRef ());
152
- noteStdlib ();
153
- return out;
210
+ ::runProcess (findSearchDirsInvocation, " attempting to find search dirs" );
211
+ if (printSearchDirsResult.isSuccess ()) {
212
+ std::string installDir;
213
+ absl::c_any_of (printSearchDirsResult.stdoutLines ,
214
+ [&](const std::string &line) -> bool {
215
+ if (line.starts_with (" install:" )) {
216
+ installDir = absl::StripAsciiWhitespace (
217
+ absl::StripPrefix (line, " install:" ));
218
+ return true ;
219
+ }
220
+ return false ;
221
+ });
222
+ if (installDir.empty ()) {
223
+ spdlog::warn (
224
+ " missing 'install:' line in -print-search-dirs from GCC(-like?) {}" ,
225
+ compilerPath.asStringRef ());
226
+ noteStdlib ();
227
+ return failure;
228
+ }
229
+ spdlog::debug (" found gcc install directory at {}" , installDir);
230
+ return std::make_unique<GccToolchainInfo>(installDir,
231
+ findSearchDirsInvocation);
154
232
}
155
- return out;
233
+
234
+ spdlog::warn (" compiler at '{}' is not one of clang/clang++/gcc/g++" ,
235
+ compilerPath.asStringRef ());
236
+ noteStdlib ();
237
+ return failure;
156
238
}
157
239
158
240
namespace scip_clang {
@@ -589,7 +671,7 @@ compdb::File::openAndExitOnErrors(const StdPath &path,
589
671
// static
590
672
ParseOptions ParseOptions::create (size_t refillCount, bool forTesting) {
591
673
ENFORCE (refillCount > 0 );
592
- return ParseOptions{refillCount, /* inferResourceDir */ !forTesting,
674
+ return ParseOptions{refillCount, /* adjustCommandLine */ !forTesting,
593
675
/* skipNonMainFileTuEntries*/ !forTesting,
594
676
/* checkFilesExist*/ !forTesting};
595
677
}
@@ -684,43 +766,39 @@ void ResumableParser::parseMore(std::vector<compdb::CommandObject> &out) {
684
766
this ->handler ->commands .clear ();
685
767
}
686
768
687
- if (this ->options .inferResourceDir ) {
769
+ if (this ->options .adjustCommandLine ) {
688
770
for (auto &cmd : out) {
689
771
if (cmd.arguments .empty ()) {
690
772
continue ;
691
773
}
692
- this ->tryInferResourceDir (cmd.workingDirectory , cmd.arguments );
774
+ this ->adjustCommandLine (cmd.workingDirectory , cmd.arguments );
693
775
}
694
776
}
695
777
}
696
778
697
- void ResumableParser::tryInferResourceDir (
698
- const std::string &directoryPath, std::vector<std::string> &commandLine) {
779
+ void ResumableParser::adjustCommandLine ( const std::string &directoryPath,
780
+ std::vector<std::string> &commandLine) {
699
781
auto &compilerOrWrapperPath = commandLine.front ();
700
- auto adjustCommandLine = [](auto &commandLine, auto it) {
701
- if (!it->second .compilerDriverPath .empty ()) {
702
- commandLine[0 ] = it->second .compilerDriverPath ;
703
- }
704
- for (auto &extraArg : it->second .extraArgs ) {
705
- commandLine.push_back (extraArg);
782
+ auto it = this ->toolchainInfoMap .find (compilerOrWrapperPath);
783
+ if (it != this ->toolchainInfoMap .end ()) {
784
+ auto &toolchain = it->second ;
785
+ if (toolchain) {
786
+ toolchain->adjustCommandLine (commandLine);
706
787
}
707
- };
708
- auto it = this ->toolchainConfigMap .find (compilerOrWrapperPath);
709
- if (it != this ->toolchainConfigMap .end ()) {
710
- adjustCommandLine (commandLine, it);
711
788
return ;
712
789
}
713
- AbsolutePath compilerInvocationPath;
790
+
714
791
auto fail = [&]() {
715
- this ->toolchainConfigMap .insert (
716
- {compilerOrWrapperPath, ToolchainConfig{ " " , {}} });
792
+ this ->toolchainInfoMap .insert (
793
+ {compilerOrWrapperPath, std::unique_ptr<ToolchainInfo>( nullptr ) });
717
794
};
718
795
796
+ AbsolutePath compilerInvocationPath;
719
797
if (compilerOrWrapperPath.find (std::filesystem::path::preferred_separator)
720
798
== std::string::npos) {
721
799
auto absPath = boost::process::search_path (compilerOrWrapperPath).native ();
722
800
if (absPath.empty ()) {
723
- this ->emitResourceDirError (fmt::format (
801
+ this ->emitError (fmt::format (
724
802
" scip-clang needs to be invoke '{0}' (found via the compilation"
725
803
" database) to determine the resource directory, but couldn't find"
726
804
" '{0}' on PATH. Hint: Use a modified PATH to invoke scip-clang,"
@@ -733,9 +811,8 @@ void ResumableParser::tryInferResourceDir(
733
811
AbsolutePath (std::string (absPath.data (), absPath.size ()));
734
812
} else if (llvm::sys::path::is_relative (compilerOrWrapperPath)) {
735
813
if (llvm::sys::path::is_absolute (directoryPath)) {
736
- compilerInvocationPath = AbsolutePath (fmt::format (
737
- " {}{}{}" , directoryPath, std::filesystem::path::preferred_separator,
738
- compilerOrWrapperPath));
814
+ compilerInvocationPath = AbsolutePath (
815
+ scip_clang::joinPath (directoryPath, compilerOrWrapperPath));
739
816
} else {
740
817
spdlog::warn (
741
818
R"( "directory": "{}" key in compilation database is not an absolute path)"
@@ -746,40 +823,27 @@ void ResumableParser::tryInferResourceDir(
746
823
ENFORCE (llvm::sys::path::is_absolute (compilerOrWrapperPath));
747
824
compilerInvocationPath = AbsolutePath (std::string (compilerOrWrapperPath));
748
825
}
826
+
749
827
if (compilerInvocationPath.asStringRef ().empty ()) {
750
828
return fail ();
751
829
}
752
- auto toolchainPathsResult = ::determineToolchainPaths (compilerInvocationPath);
753
- if (toolchainPathsResult.resourceDir .empty ()) {
754
- return fail ();
755
- }
756
- auto &resourceDir = toolchainPathsResult.resourceDir ;
757
- std::vector<std::string> extraArgs{" -resource-dir" , resourceDir};
758
- if (toolchainPathsResult.compilerKind == CompilerKind::Gcc) {
759
- // gcc-7 adds headers like limits.h and syslimits.h in include-fixed
760
- extraArgs.push_back (fmt::format (" -I{}/include-fixed" , resourceDir));
761
- }
762
- spdlog::debug (" got resource dir '{}'" , resourceDir);
763
- if (!std::filesystem::exists (resourceDir)) {
764
- this ->emitResourceDirError (fmt::format (
765
- " '{}' returned '{}' but the directory does not exist" ,
766
- fmt::join (toolchainPathsResult.cliInvocation , " " ), resourceDir));
830
+ auto optToolchainInfo = ToolchainInfo::infer (compilerInvocationPath);
831
+ if (!optToolchainInfo || !optToolchainInfo->isWellFormed ()) {
767
832
return fail ();
768
833
}
769
- auto [newIt, inserted] = this ->toolchainConfigMap .emplace (
770
- compilerOrWrapperPath,
771
- ToolchainConfig{toolchainPathsResult.compilerDriverPath ,
772
- std::move (extraArgs)});
834
+
835
+ auto [newIt, inserted] = this ->toolchainInfoMap .emplace (
836
+ compilerOrWrapperPath, std::move (optToolchainInfo));
773
837
ENFORCE (inserted);
774
- adjustCommandLine (commandLine, newIt );
838
+ newIt-> second -> adjustCommandLine (commandLine);
775
839
}
776
840
777
- void ResumableParser::emitResourceDirError (std::string &&error) {
841
+ void ResumableParser::emitError (std::string &&error) {
778
842
auto [it, inserted] = this ->emittedErrors .emplace (std::move (error));
779
843
if (inserted) {
780
844
spdlog::error (" {}" , *it);
781
845
}
782
846
}
783
847
784
848
} // namespace compdb
785
- } // namespace scip_clang
849
+ } // namespace scip_clang
0 commit comments