Improve correctness of our Clang tooling infrastructure. (#392)

This restructures the `compile_flags.txt` to use the downloaded libc++ system
headers and avoid needing a virtual include directory to be built. It still
needs _some_ Bazel build to complete before working in order to have the libc++
system headers downloaded and the symlink to the Bazel tree created.

One (very) tricky part of making this work is to work around bugs in Clang's
tooling layer that incorrectly handle `..` path components after traversing
symlinks. To avoid this, we add a custom symlinks (`bazel-execroot` and
`bazel-clang-toolchain`) that hide the relevant traversal of the Bazel layout to
find build artifacts and the downloaded toolchain. These symlinks will be broken
until a build with Bazel downloads the toolchain and creates the basic output
tree structure.

It also adds a `create_compdb.py` script. Running this script improves the
tooling fidelity by taking a few steps:

1. It queries Bazel to find all the relevant files and adds them to a
   `compile_commands.json` database that allows `clangd` and other tools to
   index the entire project for improved cross-references, etc.
2. It builds all the generated files with Bazel so that they can be included
   successfully. This is very fast in my testing, taking only 10s of seconds. It
   is also very likely to be cached effectively.
3. It translates the arguments from `compile_flags.txt` to make them
   persistently use the built generated files include paths so that nothing
   breaks even as different targets are built potentially with different
   configurations.

There are still some limitations.

- It still requires running Bazel before anything works, even if a fast run.
- It will require re-running if new generated files are added and needed but not
  built.
- It assumes that the standard Bazel symlink names are used and available.

Much of the Python here was written by @geoffromer in #384 -- I've adapted it
here after discussing to try to fill in some of the blanks and use a slightly
different approach to querying Bazel. I use the normal `bazel query` rather than
`bazel aquery`. This, for example, allows the index to reliably cover header
files in header-only libraries more directly (rather than relying on transitive
inclusion). It also seems a bit simpler too parse, but that is a pretty minor
difference.

Co-authored-by: Geoffrey Romer <gromer@google.com>
This commit is contained in:
Chandler Carruth
2021-03-18 02:29:49 -07:00
committed by GitHub
co-authored by Geoffrey Romer
parent 7e1721dc01
commit e440b07eb3
7 changed files with 178 additions and 10 deletions
+1
View File
@@ -0,0 +1 @@
bazel-out/../../carbon