Skip to content

Commit 235f5c8

Browse files
committed
fix: fall back to system compilers when database compiler is unavailable
When use-system-stdlib is enabled and the compiler specified in the compilation database cannot be found (e.g. synthetic databases that reference "clang" on systems with only GCC), try common fallback compilers (g++, gcc, clang++, clang, c++) to discover system include paths. This prevents fatal "stddef.h not found" errors when running mrdocs on systems where the database compiler isn't installed.
1 parent 1de676d commit 235f5c8

1 file changed

Lines changed: 54 additions & 17 deletions

File tree

src/tool/CompilerInfo.cpp

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@
1818
namespace mrdocs {
1919

2020
Optional<std::string>
21-
getCompilerVerboseOutput(llvm::StringRef compilerPath)
21+
getCompilerVerboseOutput(llvm::StringRef compilerPath)
2222
{
2323
if ( ! llvm::sys::fs::exists(compilerPath))
2424
{
2525
return std::nullopt;
2626
}
2727

2828
llvm::SmallString<128> outputPath;
29-
if (auto ec = llvm::sys::fs::createTemporaryFile("compiler-info", "txt", outputPath))
29+
if (auto ec = llvm::sys::fs::createTemporaryFile("compiler-info", "txt", outputPath))
3030
{
3131
return std::nullopt;
3232
}
@@ -35,7 +35,7 @@ getCompilerVerboseOutput(llvm::StringRef compilerPath)
3535
std::vector<llvm::StringRef> const args = {compilerPath, "-v", "-E", "-x", "c++", "-"};
3636
llvm::ArrayRef<llvm::StringRef> emptyEnv;
3737
int const result = ExecuteAndWaitWithLogging(compilerPath, args, emptyEnv, redirects);
38-
if (result != 0)
38+
if (result != 0)
3939
{
4040
llvm::sys::fs::remove(outputPath);
4141
return std::nullopt;
@@ -51,26 +51,26 @@ getCompilerVerboseOutput(llvm::StringRef compilerPath)
5151
return bufferOrError.get()->getBuffer().str();
5252
}
5353

54-
std::vector<std::string>
55-
parseIncludePaths(std::string const& compilerOutput)
54+
std::vector<std::string>
55+
parseIncludePaths(std::string const& compilerOutput)
5656
{
5757
std::vector<std::string> includePaths;
5858
std::istringstream stream(compilerOutput);
5959
std::string line;
6060
bool capture = false;
6161

62-
while (std::getline(stream, line))
62+
while (std::getline(stream, line))
6363
{
64-
if (line.find("#include <...> search starts here:") != std::string::npos)
64+
if (line.find("#include <...> search starts here:") != std::string::npos)
6565
{
6666
capture = true;
6767
continue;
6868
}
69-
if (line.find("End of search list.") != std::string::npos)
69+
if (line.find("End of search list.") != std::string::npos)
7070
{
7171
break;
7272
}
73-
if (capture)
73+
if (capture)
7474
{
7575
line.erase(0, line.find_first_not_of(" "));
7676
includePaths.push_back(line);
@@ -80,8 +80,30 @@ parseIncludePaths(std::string const& compilerOutput)
8080
return includePaths;
8181
}
8282

83-
std::unordered_map<std::string, std::vector<std::string>>
84-
getCompilersDefaultIncludeDir(clang::tooling::CompilationDatabase const& compDb, bool useSystemStdlib)
83+
namespace {
84+
85+
// Try to get include paths from a compiler found by name in PATH.
86+
// Returns the include paths if successful, empty vector otherwise.
87+
std::vector<std::string>
88+
tryCompilerByName(llvm::StringRef name)
89+
{
90+
auto found = llvm::sys::findProgramByName(name);
91+
if (!found)
92+
{
93+
return {};
94+
}
95+
auto output = getCompilerVerboseOutput(*found);
96+
if (!output)
97+
{
98+
return {};
99+
}
100+
return parseIncludePaths(*output);
101+
}
102+
103+
} // anonymous namespace
104+
105+
std::unordered_map<std::string, std::vector<std::string>>
106+
getCompilersDefaultIncludeDir(clang::tooling::CompilationDatabase const& compDb, bool useSystemStdlib)
85107
{
86108
if (!useSystemStdlib)
87109
{
@@ -100,14 +122,30 @@ getCompilersDefaultIncludeDir(clang::tooling::CompilationDatabase const& compDb,
100122
continue;
101123
}
102124

103-
std::vector<std::string> includePaths;
104-
auto const compilerOutput = getCompilerVerboseOutput(compilerPath);
105-
if (!compilerOutput)
125+
// Try the compiler specified in the compilation database
126+
auto compilerOutput = getCompilerVerboseOutput(compilerPath);
127+
if (compilerOutput)
106128
{
107-
res.emplace(compilerPath, includePaths);
129+
auto includePaths = parseIncludePaths(*compilerOutput);
130+
res.emplace(compilerPath, std::move(includePaths));
108131
continue;
109132
}
110-
includePaths = parseIncludePaths(*compilerOutput);
133+
134+
// The compiler from the database wasn't found.
135+
// Try common fallback compilers to discover system
136+
// include paths.
137+
static constexpr std::string_view fallbackCompilers[] = {
138+
"g++", "gcc", "clang++", "clang", "c++"
139+
};
140+
std::vector<std::string> includePaths;
141+
for (auto const& fallback : fallbackCompilers)
142+
{
143+
includePaths = tryCompilerByName(fallback);
144+
if (!includePaths.empty())
145+
{
146+
break;
147+
}
148+
}
111149
res.emplace(compilerPath, std::move(includePaths));
112150
}
113151
}
@@ -116,4 +154,3 @@ getCompilersDefaultIncludeDir(clang::tooling::CompilationDatabase const& compDb,
116154
}
117155

118156
} // mrdocs
119-

0 commit comments

Comments
 (0)