create_compdb.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. #!/usr/bin/env python3
  2. """Create a compilation database for Clang tools like `clangd`.
  3. If you want `clangd` to be able to index this project, run this script from
  4. the workspace root to generate a rich compilation database. After the first
  5. run, you should only need to run it if you encounter `clangd` problems, or if
  6. you want `clangd` to build an up-to-date index of the entire project. Note
  7. that in the latter case you may need to manually clear and rebuild clangd's
  8. index after running this script.
  9. Note that this script will build generated files in the Carbon project and
  10. otherwise touch the Bazel build. It works to do the minimum amount necessary.
  11. Once setup, generally subsequent builds, even of small parts of the project,
  12. different configurations, or that hit errors won't disrupt things. But, if
  13. you do hit errors, you can get things back to a good state by fixing the
  14. build of generated files and re-running this script.
  15. """
  16. __copyright__ = """
  17. Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  18. Exceptions. See /LICENSE for license information.
  19. SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  20. """
  21. import argparse
  22. import subprocess
  23. import sys
  24. import scripts_utils
  25. def _build_generated_files(
  26. bazel: str, logtostderr: bool, dump_files: bool
  27. ) -> None:
  28. print("Building the generated files so that tools can find them...")
  29. # Collect the generated file labels. Include some rules which generate
  30. # files but aren't classified as "generated file".
  31. kinds_query = (
  32. "filter("
  33. ' ".*\\.(h|cpp|cc|c|cxx|def|inc)$",'
  34. ' kind("(generated file|generate_llvm_tools_def|manifest_as_cpp)",'
  35. # tree_sitter is excluded here because it causes the query to failure on
  36. # `@platforms`.
  37. " deps(//... except //utils/tree_sitter/...))"
  38. ")"
  39. )
  40. log_to = None
  41. if not logtostderr:
  42. log_to = subprocess.DEVNULL
  43. generated_file_labels = subprocess.check_output(
  44. [bazel, "query", "--keep_going", "--output=label", kinds_query],
  45. stderr=log_to,
  46. encoding="utf-8",
  47. ).splitlines()
  48. if dump_files:
  49. for f in sorted(generated_file_labels):
  50. print(f)
  51. sys.exit(0)
  52. print(f"Found {len(generated_file_labels)} generated files...", flush=True)
  53. # Directly build these labels so that indexing can find them. Allow this to
  54. # fail in case there are build errors in the client, and just warn the user
  55. # that they may be missing generated files.
  56. subprocess.check_call(
  57. [bazel, "build", "--keep_going", "--remote_download_outputs=toplevel"]
  58. + generated_file_labels
  59. )
  60. def main() -> None:
  61. parser = argparse.ArgumentParser(
  62. description=__doc__,
  63. allow_abbrev=False,
  64. )
  65. parser.add_argument(
  66. "--alsologtostderr",
  67. action="store_true",
  68. help="Prints subcommand errors to stderr (default: False)",
  69. )
  70. parser.add_argument(
  71. "--dump-files",
  72. action="store_true",
  73. help="Dumps the full list of generated files (default: False)",
  74. )
  75. args = parser.parse_args()
  76. scripts_utils.chdir_repo_root()
  77. bazel = scripts_utils.locate_bazel()
  78. _build_generated_files(bazel, args.alsologtostderr, args.dump_files)
  79. print(
  80. "Generating compile_commands.json (may take a few minutes)...",
  81. flush=True,
  82. )
  83. subprocess.run([bazel, "run", "@hedron_compile_commands//:refresh_all"])
  84. if __name__ == "__main__":
  85. main()