Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query Driver -- Oddities in Log #1378

Open
cpsauer opened this issue Nov 17, 2022 · 17 comments
Open

Query Driver -- Oddities in Log #1378

cpsauer opened this issue Nov 17, 2022 · 17 comments

Comments

@cpsauer
Copy link

cpsauer commented Nov 17, 2022

Hey wonderful clangd folks,

I'm seeing some oddities in the clangd log that makes me think there are at some issues with --query-driver, compounding each other. They end up leading, I think maybe, to a bunch of extraneous standard library warnings, degrading autocomplete.

Logs

I'm seeing things that look like this

System includes extractor: successfully executed ~/Library/Android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang
	got includes: "/usr/local/include, ~/Library/Android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/14.0.6/include, /System/Library/Frameworks (framework directory), /Library/Frameworks (framework directory)"
	got target: "x86_64-apple-darwin21.6.0"
<x4>
ASTWorker building file <whatever.cpp> version 1 with command <flags actually from compile_commands.json> -isystem /usr/local/include -isystem ~/Library/Android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/14.0.6/include -isystem "/System/Library/Frameworks (framework directory)" -isystem "/Library/Frameworks (framework directory)" -resource-dir=<clangd install>/lib/clang/16 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -- <whatever.cpp>

There are some fairly strange things in there.

  1. The includes extractor is getting a mix of Android and macOS (host) paths as default includes from Android NDK clang, which seems problematic.
    [It also logs that it thinks the target is darwin, which is the host. I can see that that is indeed the default target the compiler emits when run with -v and no other arguments, but, looking at the implementation, it looks like this value is then subsequently ignored because, e.g., --target=aarch64-linux-android21 is in the command.]
  2. [It logs the includes extraction 4 times, though maybe this is one per background thread or once per android architecture or something? That's the least of the issues.]
  3. -isystem "/System/Library/Frameworks (framework directory)" -isystem "/Library/Frameworks (framework directory)" gets added to the command verbatim. The framework directories would need to instead be added via -F or -iframework, (with " (framework directory)" stripped--not that they belong in an Android build command anyway.

FWIW, the original problem that got me looking in the logs was spurious errors like In included file: no member named 'int8_t' in the global namespace, which, when clicked down into, also shows a failed include_next in stdint.h Main file cannot be included recursively when building a preamble. Not sure how related those issues are to the problems spotted in the log--the top level false errors do disappear when --query-driver is removed...although an erroneous MacOSX.sdk does remain in the command in the log. Anyway, I figured you all would want a heads up about the oddities in the log.

System information

I'm seeing this with clangd 15.0.3 and the latest weekly snapshot, 20221113, in VSCode on macOS 12.2.1.

Thanks for reading and for all you do!
Chris

@cpsauer
Copy link
Author

cpsauer commented Nov 17, 2022

[@HighCommander4, I'm going to start by tagging you if that's okay, only since you've been great about narrowing these down in the past, and we just discussed an include_next symptomed issue of a different type.]

cpsauer added a commit to hedronvision/bazel-compile-commands-extractor that referenced this issue Nov 17, 2022
@cpsauer cpsauer changed the title Query Driver -- Issues apparent in log Query Driver -- Oddities in Log Nov 17, 2022
@cpsauer
Copy link
Author

cpsauer commented Nov 17, 2022

Aha. Okay, so I think (1) might be fixed by needing to preserve --target in the system includes extraction, cross-compiling being broken without that.

Executing without reproduces the problematic include paths. Executing with fixes them.

[(2) and (3) are separate, I think.]

❯ external/androidndk/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang -E - -v
Android (8490178, based on r450784d) clang version 14.0.6 (https://android.googlesource.com/toolchain/llvm-project 4c603efb0cca074e9238af8b4106c30add4418f6)
Target: x86_64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /Users/cpsauer/Desktop/Hedron/Product/external/androidndk/toolchains/llvm/prebuilt/darwin-x86_64/bin
 (in-process)
 "/Users/cpsauer/Library/Android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang-14" -cc1 -triple x86_64-apple-macosx12.0.0 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -E -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name - -mrelocation-model pic -pic-level 2 -mframe-pointer=all -ffp-contract=on -fno-rounding-math -funwind-tables=2 -fcompatibility-qualified-id-block-type-checking -fvisibility-inlines-hidden-static-local-var -target-cpu penryn -tune-cpu generic -debugger-tuning=lldb -target-linker-version 14.0.6 -v -fcoverage-compilation-dir=/Users/cpsauer/Desktop/Hedron/Product -resource-dir /Users/cpsauer/Library/Android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/14.0.6 -internal-isystem /usr/local/include -internal-isystem /Users/cpsauer/Library/Android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/14.0.6/include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/Users/cpsauer/Desktop/Hedron/Product -ferror-limit 19 -stack-protector 1 -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fmax-type-align=16 -fcolor-diagnostics -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o - -x c -
clang -cc1 version 14.0.6 based upon LLVM 14.0.6git default target x86_64-apple-darwin21.6.0
ignoring nonexistent directory "/usr/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/include
 /Users/cpsauer/Library/Android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/14.0.6/include
 /System/Library/Frameworks (framework directory)
 /Library/Frameworks (framework directory)
End of search list.

vs.

❯ external/androidndk/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang --target=aarch64-linux-android21 -E - -v
Android (8490178, based on r450784d) clang version 14.0.6 (https://android.googlesource.com/toolchain/llvm-project 4c603efb0cca074e9238af8b4106c30add4418f6)
Target: aarch64-unknown-linux-android21
Thread model: posix
InstalledDir: /Users/cpsauer/Desktop/Hedron/Product/external/androidndk/toolchains/llvm/prebuilt/darwin-x86_64/bin
 (in-process)
 "/Users/cpsauer/Library/Android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang-14" -cc1 -triple aarch64-unknown-linux-android21 -E -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name - -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=non-leaf -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu generic -target-feature +neon -target-feature +v8a -target-feature +fix-cortex-a53-835769 -target-abi aapcs -fallow-half-arguments-and-returns -debugger-tuning=gdb -target-linker-version 14.0.6 -v -fcoverage-compilation-dir=/Users/cpsauer/Desktop/Hedron/Product -resource-dir /Users/cpsauer/Library/Android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/14.0.6 -internal-isystem /Users/cpsauer/Library/Android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/14.0.6/include -internal-isystem /Users/cpsauer/Desktop/Hedron/Product/external/androidndk/toolchains/llvm/prebuilt/darwin-x86_64/bin/../sysroot/usr/local/include -internal-externc-isystem /Users/cpsauer/Desktop/Hedron/Product/external/androidndk/toolchains/llvm/prebuilt/darwin-x86_64/bin/../sysroot/usr/include/aarch64-linux-android -internal-externc-isystem /Users/cpsauer/Desktop/Hedron/Product/external/androidndk/toolchains/llvm/prebuilt/darwin-x86_64/bin/../sysroot/include -internal-externc-isystem /Users/cpsauer/Desktop/Hedron/Product/external/androidndk/toolchains/llvm/prebuilt/darwin-x86_64/bin/../sysroot/usr/include -fdebug-compilation-dir=/Users/cpsauer/Desktop/Hedron/Product -ferror-limit 19 -fno-signed-char -fgnuc-version=4.2.1 -fcolor-diagnostics -target-feature +outline-atomics -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o - -x c -
clang -cc1 version 14.0.6 based upon LLVM 14.0.6git default target x86_64-apple-darwin21.6.0
ignoring nonexistent directory "/Users/cpsauer/Desktop/Hedron/Product/external/androidndk/toolchains/llvm/prebuilt/darwin-x86_64/bin/../sysroot/include"
#include "..." search starts here:
#include <...> search starts here:
 /Users/cpsauer/Library/Android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/14.0.6/include
 /Users/cpsauer/Desktop/Hedron/Product/external/androidndk/toolchains/llvm/prebuilt/darwin-x86_64/bin/../sysroot/usr/local/include
 /Users/cpsauer/Desktop/Hedron/Product/external/androidndk/toolchains/llvm/prebuilt/darwin-x86_64/bin/../sysroot/usr/include/aarch64-linux-android
 /Users/cpsauer/Desktop/Hedron/Product/external/androidndk/toolchains/llvm/prebuilt/darwin-x86_64/bin/../sysroot/usr/include
End of search list.

@cpsauer
Copy link
Author

cpsauer commented Nov 17, 2022

I do also see another bug in that code, just reading quickly.
Looks like we'll miss the standard form of -isysroot<dir>, no quotes, no =.

Also heads that the phabricator links seem to be messed up somehow. Like look at llvm/llvm-project@6e8d6bc (which added this code) and click on the differential revision link. It points to some unrelated cmake change. So no additional context there.

@cpsauer
Copy link
Author

cpsauer commented Nov 18, 2022

I started spinning up a quick patch to fix (1) (plus a typo), but decided I should check in with someone more experienced with the codebase.

It occurred that maybe it'd be better to switch things over to reuse clang's arg parsing, like with ArgStripper in CompileCommands.cpp, unifying logic so we have fewer issues like the isysroot one, above?

Note that, like isysroot, the target flag doesn't fit cleanly into the ArgsToPreserve abstraction and does indeed have a different number of - in its = and non = forms. (ref)

Also, scrolling down quickly, I'm seeing more concerning things. There's another isysroot bug (!Has("-isysroot")) And if we think sysroots, targets, and the other flags enumerated effect the system includes, we'd better include them as part of the memoization key, right?

Anyway, saving out the mini patch here in public, just in case it's useful. Maybe we should push it as a stopgap? I want to flag the issues I'm seeing, but also want to keep us moving incrementally, rather than getting bogged down in trying to fix everything here atomically.

--- a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
+++ b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
@@ -184,13 +184,18 @@ extractSystemIncludesAndTarget(llvm::SmallString<128> Driver,
   const llvm::StringRef FlagsToPreserve[] = {
       "-nostdinc", "--no-standard-includes", "-nostdinc++", "-nobuiltininc"};
   // Preserves these flags and their values, either as separate args or with an
-  // equalsbetween them
+  // equals between them
   const llvm::StringRef ArgsToPreserve[] = {"--sysroot", "-isysroot"};
 
   for (size_t I = 0, E = CommandLine.size(); I < E; ++I) {
     llvm::StringRef Arg = CommandLine[I];
     if (llvm::is_contained(FlagsToPreserve, Arg)) {
       Args.push_back(Arg);
+    } else if (Arg.startswith("--target=")) {
+      Args.push_back(Arg);
+    } else if (I + 1 < E && Arg.equals("-target")) {
+      Args.push_back(CommandLine[I]);
+      Args.push_back(CommandLine[++I]);
     } else {
       const auto *Found =
           llvm::find_if(ArgsToPreserve, [&Arg](llvm::StringRef S) {

@HighCommander4
Copy link

Also heads that the phabricator links seem to be messed up somehow. Like look at llvm/llvm-project@6e8d6bc (which added this code) and click on the differential revision link. It points to some unrelated cmake change. So no additional context there.

I think what happens is that, since the workflows for submitting a patch for review and then merging the reviewed version are not fully automated/scripted, developers sometimes end up copying the Phabricator link into the commit message manually, leading to occasional errors.

The correct link in this case is https://reviews.llvm.org/D73453.

@HighCommander4
Copy link

HighCommander4 commented Nov 20, 2022

  1. [It logs the includes extraction 4 times, though maybe this is one per background thread or once per android architecture or something? That's the least of the issues.]

I'd guess it's once per file type (e.g. C header, C source file, C++ header, etc.), since the file type is part of the memoization key.

@HighCommander4
Copy link

Anyway, saving out the mini patch here in public, just in case it's useful. Maybe we should push it as a stopgap?

+1 -- I would say post it for review, and we can consider the larger changes to (1) reuse more proper argument parsing code and (2) include the preserved args (or a hash of them or something similar) in the memoization key, as follow-up improvements.

@HighCommander4
Copy link

HighCommander4 commented Nov 20, 2022

  1. -isystem "/System/Library/Frameworks (framework directory)" -isystem "/Library/Frameworks (framework directory)" gets added to the command verbatim. Unless there's special handling in isystem that I don't know about, I'd think that the framework directories would need to instead be added via -F or -iframework, (with " (framework directory)" stripped--not that they belong in an Android build command anyway.

(Not sure on this one, I will defer to someone who uses and is more familiar with Mac.)

@cpsauer
Copy link
Author

cpsauer commented Nov 23, 2022

Replying to each in turn :) Thanks for being great as usual, @HighCommander4.

Re (2), maybe it's once per language type. But it still seems curious to have multiple before building a c++ source file. Shouldn't the file type always be C++ source? Anyway, this one's the least of the problems.

Re (1) and the patch: Thanks for encouraging the incremental improvement. Done. https://reviews.llvm.org/D138546 Please do coach me! This is LLVM review number 2 for me.

Re the many other bugs in that file: Happy to help, but someone with more experience in the codebase should probably take the lead here, esp if we're trying to use existing parsing. That said, your utility libraries and online docs are oh-so-nice.

Re (3): I can be that person if you want :). It's a bug. I ran some quick experiments passing them in via -E - -v, parallel to the extractor, and I can confirm that there doesn't seem to be any special magic in -isystem that makes this right; they're ignored as non-existent. The right behavior would be to (at least on macOS) detect extracted paths ending in " (framework directory)", and then put them in a separate list to be added with -iframework instead of -isystem. Does clang --help on linux also list -iframework as a flag? (I'm trying to determine if we should condition on OS.)

Anyway, thanks again, Nathan :)

@HighCommander4
Copy link

Does clang --help on linux also list -iframework as a flag?

It seems to, yeah.

@cpsauer
Copy link
Author

cpsauer commented Nov 23, 2022

Sg. So on all platforms, then. One less special case to consider.

@kadircet
Copy link
Member

Hi all, i've put together the concerns around caching in #1403. I think we need to first get that sorted out to make progress here, patches welcome. i've also created #1404 for tracking -isysroot issue.

But in addition to that, i'd like to hear why you need query-driver in the first place @cpsauer, considering the actual driver you're querying is clang in the end (as I've pointed out in the review as well). This is not related to handling --target, we should preserve that no matter what (it hasn't been necessary so far, because the driver name for custom gcc toolchains already includes enough information that clang can infer which -target to pass).

@cpsauer
Copy link
Author

cpsauer commented Dec 8, 2022

Thanks, @kadircet, for being great :)
Looks like your call for help on those two issues is already being answered. Whoa! Beat me to it.

Re query-driver: Without it, I was seeing a host sysroot get incorrectly inferred, unfortunately. I'm guessing this has something to do, similarly, with the target affecting the default include directories in the driver? I don't yet know exactly how this works.

To give an example from the clangd log, as requested, ndk compilation, without query-driver, takes the form:

ASTWorker building file <AndroidSource>.cpp version 1 with command 
[<project directory>]
external/androidndk/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang <args from CDB, including --target=<arch>-linux-android21> -resource-dir=<clangd>/lib/clang/16 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -- <AndroidSource>.cpp

But more generally, Bazel folks (at least) have been finding they need to use query driver by default--both because of difficulties inferring, like the above, but also since toolchains just keep having custom driver wrappers scripts for one reason or another (annoying, I know, but prevalent), and query driver helps penetrate.

@kadircet
Copy link
Member

So you're saying that -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk is incorrect (which is inferred as part of something else we have specifically for mac).

Let me ask a couple more questions to clarify the situation here,

  • What's the expected sysroot?
  • Is the expected sysroot already part of the original compile flags but clangd is overwriting it somehow in the absence of query driver?
  • how does preserving --target as you mentioned above effect the sysroot, query driver doesn't really extract information about sysroot today and preserving any extra flags isn't likely to change that (instead we'll just have a bunch of extra system directories, which might take precedence over the wrong syroot clangd is still setting)
  • is external/androidndk/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang a regular clang ? or is it a wrapper script/something with customizations?

A general side note, https://github.com/llvm/llvm-project/blob/main/clang-tools-extra/clangd/CompileCommands.cpp#L335 is where we inject sysroot into compile flags. in non-mac systems this is mostly off, but on macs we set it to xcode's SDK ~always (https://github.com/llvm/llvm-project/blob/main/clang-tools-extra/clangd/CompileCommands.cpp#L129).

If not having sysroot at all is what you really want, the right way to fix this would be to change the sysroot detection logic we've for apple to only apply in cases where we're pointing at default clang and not when we've a special looking driver.

@cpsauer
Copy link
Author

cpsauer commented Dec 14, 2022

Yep. The macOS SDK isn't what one would expect to see inferred as the sysroot for the Android NDK.
(Though I've since discovered that the incorrect sysroot seems to get ignored by clangd before it becomes a problem; keep reading for more.)

One would hope instead to just infer the default system include directories for the NDK.

The include directories one gets by querying the driver with --target=<target> -E - -v look reasonable to me (as listed above in the second part of this comment--hence the --target patch for query driver). Note that the last three paths containing "sysroot" are indeed symlinked into the same directory as the first, as they appear to be.

That is, to succeed without querying the driver, we want to infer just the system include paths

$DRIVER_DIR/../lib64/clang/14.0.6/include
$DRIVER_DIR/../sysroot/usr/local/include
$DRIVER_DIR/../sysroot/usr/include/<target>
$DRIVER_DIR/../sysroot/usr/include

(where $DRIVER_DIR is just a stand in for the directory containing the driver, not a environment var clangd should depend on or anything.)

Those paths look like they're probably just standard? And, from browsing around, clangd's suggestions do already seem to infer them correctly, additionally rejecting host-specific includes, so it seems like things are working somehow, ignoring the host sysroot, though I'm not sure where or why. Basically, on closer inspection, things do seem to work without query-driver, I'd just been spooked by the log specifying a host sysroot for cross-compilation. Still seems a little wrong to infer a host sysroot for cross-compiling and then ignore it somehow, but it seems like the issue doesn't make its way into the editor.


Just to recap and make sure I'm explicitly answering each of your questions:

Yes, the macOS SDK sysroot does seem wrong, though it seems to get ignored before it breaks things for the user.

  • Assuming the relative system include paths listed above are standard for clang distributions and get inferred correctly, I don't think clangd should add a host sysroot when cross compiling, though again, it doesn't actually turn into a problem for users.
    • (If useful, it's not yet obvious to me why we need to supplement the sysroot when compiling for macOS; I haven't actually exercised this case, since the Bazel toolchains for Apple platforms always specify an isysroot and two framework search paths.)
  • For the android command we were discussing, there's no sysroot or isysroot change in the original command; the bazel NDK toolchain is relying on the driver to set the right system include paths.
  • --target seems to affect default system includes (as above), but I no longer think it has anything to do with the inclusion of the wrong-seemign isysroot, just the query-driver isystems. Sorry for the confusion, and thanks for your code links!
  • I think it's a regular clang (or rather, a symlink to a versioned clang). It points to a large regular binary, not a wrapper script. It's possible that the NDK folks have customized something in there. I'm not sure. For our purposes, maybe the right way to resolve this is whether those default system include paths look standard to you, too?

Anyway, thanks @kadircet for taking an interest, and for being so nice and thoughtful.

@kadircet
Copy link
Member

IIUC, everything is working as expected on your end (somewhat incidentally though). So glad to hear that.

Regarding the include paths you mentioned, yes those are the standard ones that would be heuristically detected by any clang (assuming argv[0] is mentioned correctly in compile commands, which seem to be the case for you). the "../sysroot" pieces look a little surprising, but apparently android toolchain does that.

The only action that we haven't discussed yet, coming out of this issue, seems like not setting isysroot when we have a non-generic driver name in argv[0]. The reason for setting it always is because xcode intalled clang searches for stdlib includes under this sysroot, hence if it isn't provided clangd doesn't work out-of-the-box for most mac users.

I'd suggest creating a new issue for not setting isysroot always and closing this one (as other oddities that we have discovered have their own issues now). Does that SG?

@cpsauer
Copy link
Author

cpsauer commented Jan 14, 2023

Hey, @kadircet! Indeed, the non-query driver case does seem to work for Android after all. (But I'd wanted to answer your questions about why people were using query-driver--and I hadn't realized the extent to which the problematic-looking host flag, logged, was ignored.)

Thanks for the link--and your kindness and interest. I had no idea there was that much special casing on triples for include paths!

Re the automatic mac isysroot, might we need logic to see if the triple is set to something besides macOS, so we don't get it if the Apple clang is being used for other targets? I figure we should resolve that before filing. Plus, you seem to have special magic for calling in help, given people had submitted diffs before I'd even read the new issues! Maybe just the help-wanted tag. Could I ask you do file this one, too, with that tag? I think you have a significantly better understanding of what's going on behind the scenes with this one than I do, so could you file?

I think we've also got one other outstanding sub-issue: The need to strip " (framework directory)" and put those paths under -iframework. That is, (3) in the original post

Perhaps we should keep this one open until the core, target -> query-driver change lands?

Thanks again,
Chris

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants