diff --git a/clang-tools-extra/clangd/QueryDriverDatabase.cpp b/clang-tools-extra/clangd/QueryDriverDatabase.cpp --- a/clang-tools-extra/clangd/QueryDriverDatabase.cpp +++ b/clang-tools-extra/clangd/QueryDriverDatabase.cpp @@ -62,6 +62,7 @@ struct DriverInfo { std::vector SystemIncludes; std::string Target; + std::string GccVersion; }; bool isValidTarget(llvm::StringRef Triple) { @@ -79,6 +80,7 @@ const char SIS[] = "#include <...> search starts here:"; const char SIE[] = "End of search list."; const char TS[] = "Target: "; + const char VS[] = "gcc version "; llvm::SmallVector Lines; Output.split(Lines, '\n', /*MaxSplit=*/-1, /*KeepEmpty=*/false); @@ -89,6 +91,7 @@ } State = Initial; bool SeenIncludes = false; bool SeenTarget = false; + bool SeenVersion = false; for (auto *It = Lines.begin(); State != Done && It != Lines.end(); ++It) { auto Line = *It; switch (State) { @@ -109,6 +112,17 @@ vlog("System include extraction: target extracted: \"{0}\"", TargetLine); } + } else if (!SeenVersion && Line.trim().startswith(VS)) { + SeenVersion = true; + llvm::StringRef GccVersionLine = Line.trim(); + GccVersionLine.consume_front(VS); + Info.GccVersion = GccVersionLine + .take_while([](unsigned char C) { + return C == '.' || std::isdigit(C); + }) + .str(); + vlog("System include extraction: GCC version extracted: \"{0}\"", + Info.GccVersion); } break; case IncludesExtracting: @@ -231,8 +245,11 @@ if (!Info) return llvm::None; log("System includes extractor: successfully executed {0}\n\tgot includes: " - "\"{1}\"\n\tgot target: \"{2}\"", - Driver, llvm::join(Info->SystemIncludes, ", "), Info->Target); + "\"{1}\"\n\tgot target: \"{2}\"{3}", + Driver, llvm::join(Info->SystemIncludes, ", "), Info->Target, + Info->GccVersion.empty() + ? std::string() + : llvm::formatv("\n\tgot GCC version: \"{0}\"", Info->GccVersion)); return Info; } @@ -260,6 +277,19 @@ return Cmd; } +tooling::CompileCommand &setGccVersion(tooling::CompileCommand &Cmd, + const std::string &GccVersion) { + if (!GccVersion.empty()) { + // We do not want to override existing GCC version with extracted one. + for (llvm::StringRef Arg : Cmd.CommandLine) { + if (Arg.startswith("-fgnuc-version")) + return Cmd; + } + Cmd.CommandLine.push_back("-fgnuc-version=" + GccVersion); + } + return Cmd; +} + /// Converts a glob containing only ** or * into a regex. std::string convertGlobToRegex(llvm::StringRef Glob) { std::string RegText; @@ -345,7 +375,9 @@ return extractSystemIncludesAndTarget( Driver, Lang, Cmd->CommandLine, QueryDriverRegex); })) { - setTarget(addSystemIncludes(*Cmd, Info->SystemIncludes), Info->Target); + setGccVersion(setTarget(addSystemIncludes(*Cmd, Info->SystemIncludes), + Info->Target), + Info->GccVersion); } return Cmd; } diff --git a/clang-tools-extra/clangd/test/system-include-extractor.test b/clang-tools-extra/clangd/test/system-include-extractor.test --- a/clang-tools-extra/clangd/test/system-include-extractor.test +++ b/clang-tools-extra/clangd/test/system-include-extractor.test @@ -16,6 +16,7 @@ # RUN: echo 'echo " $* " | grep " --sysroot /my/sysroot/path " || exit' >> %t.dir/bin/my_driver.sh # RUN: echo 'echo line to ignore >&2' >> %t.dir/bin/my_driver.sh # RUN: echo 'printf "Target: arm-linux-gnueabihf\r\n" >&2' >> %t.dir/bin/my_driver.sh +# RUN: echo 'printf "gcc version 8.3.0 (Rev2)\r\n" >&2' >> %t.dir/bin/my_driver.sh # RUN: echo 'printf "#include <...> search starts here:\r\n" >&2' >> %t.dir/bin/my_driver.sh # RUN: echo 'echo %t.dir/my/dir/ >&2' >> %t.dir/bin/my_driver.sh # RUN: echo 'echo %t.dir/my/dir2/ >&2' >> %t.dir/bin/my_driver.sh @@ -49,7 +50,7 @@ "uri": "file://INPUT_DIR/the-file.cpp", "languageId":"cpp", "version":1, - "text":"#include \n#include \n#if !defined(__ARM_ARCH) || !defined(__gnu_linux__)\n#error \"Invalid target\"\n#endif" + "text":"#include \n#include \n#if !defined(__ARM_ARCH) || !defined(__gnu_linux__)\n#error \"Invalid target\"\n#endif\n#if !defined(__GNUC__) || __GNUC__ != 8\n#error \"Incorrect GCC version\"\n#endif" } } }