This is an archive of the discontinued LLVM Phabricator instance.

[clangd] When querying drivers by binary, look in PATH too
ClosedPublic

Authored by rapgenic on Dec 20 2020, 12:17 PM.

Details

Summary

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

Diff Detail

Event Timeline

rapgenic created this revision.Dec 20 2020, 12:17 PM
rapgenic requested review of this revision.Dec 20 2020, 12:17 PM
Herald added a project: Restricted Project. · View Herald TranscriptDec 20 2020, 12:17 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript
rapgenic retitled this revision from When querying drivers by binary, look in PATH too to [clangd] When querying drivers by binary, look in PATH too.Dec 20 2020, 12:18 PM
rapgenic added a reviewer: sammccall.

Just wanted to say that this is my first patch submission to the LLVM/clangd project, so please call me out on any mistake!

The arc tool caught me by surprise by opening the revision before I could double check it, hence the rename and edits...

Thanks, this looks like a good idea to me, but some quibbles with the details:

  • for any string, we statically know whether it's path or WD-relative
  • we should make sure all the IO gets cached
clang-tools-extra/clangd/QueryDriverDatabase.cpp
350

Oops, this has come up before (in CommandMangler).
Your idea here makes sense (if the driver is "clang" we should look it up on the PATH) and the approach is backwards-compatible.

However when we think more carefully, by allowing the driver to be both WD-relative and dir-relative, we're emulating shell behavior (which makes sense, we have an argv!).
But shells don't generally try one then the other, they instead distinguish three cases:

  • bare name clang is looked up on PATH
  • relative path bin/clang is resolved against WD
  • absolute path /usr/bin/clang is used as-is

So I think we'd rather have something like:

if (llvm::none_of(Driver,
                     [](char C) { return llvm::sys::path::is_separator(C); })) {
  // resolve against path
} else {
  make_absolute(Cmd->Directory, Driver);
}
357

I'm not sure it's reasonable to do IO like this before we have a chance to hit the cache (but see above comment, I don't think we need the exists() at all)

359

hmm, this also does IO, and we obviously do need this.

I think we need to move this into the cached lookup, so:

  • if the path is "bin/clangd" we resolve it to absolute before querying the cache
  • if the path is "/usr/bin/clangd" we pass that absolute path to cache
  • but if the path is "clangd" we pass that exact string into extractSystemIncludesAndTarget(), which notices that it's relative and looks it up on PATH. Fortunately we can assume PATH doesn't change while running, so the cache is still correct.
rapgenic updated this revision to Diff 313259.Dec 22 2020, 1:16 AM
rapgenic marked 3 inline comments as done.Dec 22 2020, 1:22 AM

I think I have fixed what you asked!

About the test, I thought it would be reasonable to test the three cases separately, however I cannot get it to work with a single test file (I think it's some problem with the generated files). Should I duplicate it or is there any way to do it better?

Sorry for my trivial question, but I'm still learning to navigate the codebase...

sammccall accepted this revision.Dec 22 2020, 2:20 PM

Thanks, this looks good, just a couple of nits.

I guess you don't have commit access, I'm happy to land this for you when you're happy with it. Just need an email address to associate the commit with.

About the test, I thought it would be reasonable to test the three cases separately, however I cannot get it to work with a single test file (I think it's some problem with the generated files). Should I duplicate it or is there any way to do it better?

Yeah, these tests are a pain. I think you'd have to duplicate it, but honestly that's a maintenance trap, and it's really hard to factor out common logic in lit tests.
I think folding in the complicated case into the existing test as you've done is probably best.

clang-tools-extra/clangd/QueryDriverDatabase.cpp
145

maybe add an assert inside this if that there are no separators?

151

else log and return none?
We don't want to continue if we couldn't find clang on the path.

351–355

nit: !llvm::none_of -> llvm::any_of

This revision is now accepted and ready to land.Dec 22 2020, 2:20 PM
rapgenic updated this revision to Diff 313528.Dec 23 2020, 4:03 AM
rapgenic marked 3 inline comments as done.Dec 23 2020, 4:07 AM

Done! My email is:

Giulio Girardi <giulio.girardi@protechgroup.it>

Thank you for your help!

This revision was automatically updated to reflect the committed changes.

Sorry for the delay getting this landed, and thanks for the patch!
It'll be part of the clangd 12 release.