Skip to content

Commit 2f8d1e9

Browse files
rapgenicsam-mccall
authored andcommitted
[clangd] When querying drivers by binary, look in PATH too
Sometimes compile_commands.json databases are created without an absolute path for the driver in the command field. By default the driver name is appended to the current directory, however if no driver is found in that location assume it was in the default PATH and try finding it there Reviewed By: sammccall Differential Revision: https://reviews.llvm.org/D93600
1 parent 0e4d236 commit 2f8d1e9

File tree

2 files changed

+39
-16
lines changed

2 files changed

+39
-16
lines changed

clang-tools-extra/clangd/QueryDriverDatabase.cpp

+22-2
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,26 @@ llvm::Optional<DriverInfo> parseDriverOutput(llvm::StringRef Output) {
136136
}
137137

138138
llvm::Optional<DriverInfo>
139-
extractSystemIncludesAndTarget(PathRef Driver, llvm::StringRef Lang,
139+
extractSystemIncludesAndTarget(llvm::SmallString<128> Driver,
140+
llvm::StringRef Lang,
140141
llvm::ArrayRef<std::string> CommandLine,
141142
const llvm::Regex &QueryDriverRegex) {
142143
trace::Span Tracer("Extract system includes and target");
144+
145+
if (!llvm::sys::path::is_absolute(Driver)) {
146+
assert(llvm::none_of(
147+
Driver, [](char C) { return llvm::sys::path::is_separator(C); }));
148+
auto DriverProgram = llvm::sys::findProgramByName(Driver);
149+
if (DriverProgram) {
150+
vlog("System include extraction: driver {0} expanded to {1}", Driver,
151+
*DriverProgram);
152+
Driver = *DriverProgram;
153+
} else {
154+
elog("System include extraction: driver {0} not found in PATH", Driver);
155+
return llvm::None;
156+
}
157+
}
158+
143159
SPAN_ATTACH(Tracer, "driver", Driver);
144160
SPAN_ATTACH(Tracer, "lang", Lang);
145161

@@ -332,7 +348,11 @@ class QueryDriverDatabase : public GlobalCompilationDatabase {
332348
}
333349

334350
llvm::SmallString<128> Driver(Cmd->CommandLine.front());
335-
llvm::sys::fs::make_absolute(Cmd->Directory, Driver);
351+
if (llvm::any_of(Driver,
352+
[](char C) { return llvm::sys::path::is_separator(C); }))
353+
// Driver is a not a single executable name but instead a path (either
354+
// relative or absolute).
355+
llvm::sys::fs::make_absolute(Cmd->Directory, Driver);
336356

337357
if (auto Info =
338358
QueriedDrivers.get(/*Key=*/(Driver + ":" + Lang).str(), [&] {

clang-tools-extra/clangd/test/system-include-extractor.test

+17-14
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,24 @@
33
# The mock driver below is a shell script:
44
# REQUIRES: shell
55

6+
# Create a bin directory to store the mock-driver and add it to the path
7+
# RUN: mkdir -p %t.dir/bin
8+
# RUN: export PATH=%t.dir/bin:$PATH
69
# Generate a mock-driver that will print %temp_dir%/my/dir and
710
# %temp_dir%/my/dir2 as include search paths.
8-
# RUN: echo '#!/bin/sh' >> %t.dir/my_driver.sh
9-
# RUN: echo '[ "$0" = "%t.dir/my_driver.sh" ] || exit' >> %t.dir/my_driver.sh
10-
# RUN: echo 'args="$*"' >> %t.dir/my_driver.sh
11-
# RUN: echo '[ -z "${args##*"-nostdinc"*}" ] || exit' >> %t.dir/my_driver.sh
12-
# RUN: echo '[ -z "${args##*"-isysroot=/isysroot"*}" ] || exit' >> %t.dir/my_driver.sh
13-
# RUN: echo 'echo " $* " | grep " --sysroot /my/sysroot/path " || exit' >> %t.dir/my_driver.sh
14-
# RUN: echo 'echo line to ignore >&2' >> %t.dir/my_driver.sh
15-
# RUN: echo 'printf "Target: arm-linux-gnueabihf\r\n" >&2' >> %t.dir/my_driver.sh
16-
# RUN: echo 'printf "#include <...> search starts here:\r\n" >&2' >> %t.dir/my_driver.sh
17-
# RUN: echo 'echo %t.dir/my/dir/ >&2' >> %t.dir/my_driver.sh
18-
# RUN: echo 'echo %t.dir/my/dir2/ >&2' >> %t.dir/my_driver.sh
19-
# RUN: echo 'printf "End of search list.\r\n" >&2' >> %t.dir/my_driver.sh
20-
# RUN: chmod +x %t.dir/my_driver.sh
11+
# RUN: echo '#!/bin/sh' >> %t.dir/bin/my_driver.sh
12+
# RUN: echo '[ "$0" = "%t.dir/bin/my_driver.sh" ] || exit' >> %t.dir/bin/my_driver.sh
13+
# RUN: echo 'args="$*"' >> %t.dir/bin/my_driver.sh
14+
# RUN: echo '[ -z "${args##*"-nostdinc"*}" ] || exit' >> %t.dir/bin/my_driver.sh
15+
# RUN: echo '[ -z "${args##*"-isysroot=/isysroot"*}" ] || exit' >> %t.dir/bin/my_driver.sh
16+
# RUN: echo 'echo " $* " | grep " --sysroot /my/sysroot/path " || exit' >> %t.dir/bin/my_driver.sh
17+
# RUN: echo 'echo line to ignore >&2' >> %t.dir/bin/my_driver.sh
18+
# RUN: echo 'printf "Target: arm-linux-gnueabihf\r\n" >&2' >> %t.dir/bin/my_driver.sh
19+
# RUN: echo 'printf "#include <...> search starts here:\r\n" >&2' >> %t.dir/bin/my_driver.sh
20+
# RUN: echo 'echo %t.dir/my/dir/ >&2' >> %t.dir/bin/my_driver.sh
21+
# RUN: echo 'echo %t.dir/my/dir2/ >&2' >> %t.dir/bin/my_driver.sh
22+
# RUN: echo 'printf "End of search list.\r\n" >&2' >> %t.dir/bin/my_driver.sh
23+
# RUN: chmod +x %t.dir/bin/my_driver.sh
2124

2225
# Create header files my/dir/a.h and my/dir2/b.h
2326
# RUN: mkdir -p %t.dir/my/dir
@@ -27,7 +30,7 @@
2730

2831
# Generate a compile_commands.json that will query the mock driver we've
2932
# created. Which should add a.h and b.h into include search path.
30-
# RUN: echo '[{"directory": "%/t.dir", "command": "%/t.dir/my_driver.sh the-file.cpp -nostdinc --sysroot /my/sysroot/path -isysroot=/isysroot", "file": "the-file.cpp"}]' > %t.dir/compile_commands.json
33+
# RUN: echo '[{"directory": "%/t.dir", "command": "my_driver.sh the-file.cpp -nostdinc --sysroot /my/sysroot/path -isysroot=/isysroot", "file": "the-file.cpp"}]' > %t.dir/compile_commands.json
3134

3235
# RUN: sed -e "s|INPUT_DIR|%/t.dir|g" %s > %t.test.1
3336
# On Windows, we need the URI in didOpen to look like "uri":"file:///C:/..."

0 commit comments

Comments
 (0)