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 @@ -56,18 +56,34 @@ namespace clangd { namespace { -std::vector parseDriverOutput(llvm::StringRef Output) { +std::pair, std::string> +parseDriverOutput(llvm::StringRef Output) { std::vector SystemIncludes; + std::string Target; const char SIS[] = "#include <...> search starts here:"; const char SIE[] = "End of search list."; + const char TS[] = "Target: "; llvm::SmallVector Lines; Output.split(Lines, '\n', /*MaxSplit=*/-1, /*KeepEmpty=*/false); auto StartIt = llvm::find_if( - Lines, [SIS](llvm::StringRef Line) { return Line.trim() == SIS; }); + Lines, [TS](llvm::StringRef Line) { return Line.trim().startswith(TS); }); + + if (StartIt != Lines.end()) { + llvm::StringRef TargetLine = StartIt->trim(); + TargetLine.consume_front(TS); + Target = TargetLine.str(); + ++StartIt; + } else { + // Start from the beginning if target was not found. + StartIt = Lines.begin(); + } + StartIt = + llvm::find_if(llvm::make_range(StartIt, Lines.end()), + [SIS](llvm::StringRef Line) { return Line.trim() == SIS; }); if (StartIt == Lines.end()) { elog("System include extraction: start marker not found: {0}", Output); - return {}; + return {SystemIncludes, Target}; } ++StartIt; const auto EndIt = @@ -75,21 +91,21 @@ [SIE](llvm::StringRef Line) { return Line.trim() == SIE; }); if (EndIt == Lines.end()) { elog("System include extraction: end marker missing: {0}", Output); - return {}; + return {SystemIncludes, Target}; } for (llvm::StringRef Line : llvm::make_range(StartIt, EndIt)) { SystemIncludes.push_back(Line.trim().str()); vlog("System include extraction: adding {0}", Line); } - return SystemIncludes; + return {SystemIncludes, Target}; } -std::vector -extractSystemIncludes(PathRef Driver, llvm::StringRef Lang, - llvm::ArrayRef CommandLine, - const llvm::Regex &QueryDriverRegex) { - trace::Span Tracer("Extract system includes"); +std::pair, std::string> +extractSystemIncludesAndTarget(PathRef Driver, llvm::StringRef Lang, + llvm::ArrayRef CommandLine, + const llvm::Regex &QueryDriverRegex) { + trace::Span Tracer("Extract system includes and target"); SPAN_ATTACH(Tracer, "driver", Driver); SPAN_ATTACH(Tracer, "lang", Lang); @@ -168,11 +184,15 @@ return {}; } - auto Includes = parseDriverOutput(BufOrError->get()->getBuffer()); - log("System include extractor: successfully executed {0}, got includes: " + auto IncludesAndTarget = parseDriverOutput(BufOrError->get()->getBuffer()); + log("System includes extractor: successfully executed {0}, got includes: " "\"{1}\"", - Driver, llvm::join(Includes, ", ")); - return Includes; + Driver, llvm::join(IncludesAndTarget.first, ", ")); + if (!IncludesAndTarget.second.empty()) + log("Target extractor: successfully executed {0}, got target: " + "\"{1}\"", + Driver, IncludesAndTarget.second); + return IncludesAndTarget; } tooling::CompileCommand & @@ -186,6 +206,15 @@ return Cmd; } +tooling::CompileCommand &setTarget(tooling::CompileCommand &Cmd, + const std::string &Target) { + if (!Target.empty()) { + Cmd.CommandLine.push_back("-target"); + Cmd.CommandLine.push_back(Target); + } + return Cmd; +} + /// Converts a glob containing only ** or * into a regex. std::string convertGlobToRegex(llvm::StringRef Glob) { std::string RegText; @@ -268,13 +297,14 @@ llvm::SmallString<128> Driver(Cmd->CommandLine.front()); llvm::sys::fs::make_absolute(Cmd->Directory, Driver); - std::vector SystemIncludes = + std::pair, std::string> SystemIncludesAndTarget = QueriedDrivers.get(/*Key=*/(Driver + ":" + Lang).str(), [&] { - return extractSystemIncludes(Driver, Lang, Cmd->CommandLine, - QueryDriverRegex); + return extractSystemIncludesAndTarget(Driver, Lang, Cmd->CommandLine, + QueryDriverRegex); }); - return addSystemIncludes(*Cmd, SystemIncludes); + addSystemIncludes(*Cmd, SystemIncludesAndTarget.first); + return setTarget(*Cmd, SystemIncludesAndTarget.second); } llvm::Optional getProjectInfo(PathRef File) const override { @@ -283,7 +313,8 @@ private: // Caches includes extracted from a driver. Key is driver:lang. - Memoize>> QueriedDrivers; + Memoize, std::string>>> + QueriedDrivers; llvm::Regex QueryDriverRegex; std::unique_ptr Base; 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 @@ -12,6 +12,7 @@ # RUN: echo '[ -z "${args##*"-isysroot=/isysroot"*}" ] || exit' >> %t.dir/my_driver.sh # RUN: echo 'echo " $* " | grep " --sysroot /my/sysroot/path " || exit' >> %t.dir/my_driver.sh # RUN: echo 'echo line to ignore >&2' >> %t.dir/my_driver.sh +# RUN: echo 'printf "Target: arm-linux-gnueabihf\r\n" >&2' >> %t.dir/my_driver.sh # RUN: echo 'printf "#include <...> search starts here:\r\n" >&2' >> %t.dir/my_driver.sh # RUN: echo 'echo %t.dir/my/dir/ >&2' >> %t.dir/my_driver.sh # RUN: echo 'echo %t.dir/my/dir2/ >&2' >> %t.dir/my_driver.sh @@ -45,7 +46,7 @@ "uri": "file://INPUT_DIR/the-file.cpp", "languageId":"cpp", "version":1, - "text":"#include \n#include " + "text":"#include \n#include \n#if !defined(__ARM_ARCH) || !defined(__gnu_linux__)\n#error \"Invalid target\"\n#endif" } } }