comp_db.bzl
1 # prelude/cxx/comp_db.bzl 2 # 3 # Compilation database support for IDE integration. 4 # Generates compile_commands.json for clangd, ccls, etc. 5 # 6 # Extracted from buck2-prelude/cxx/comp_db.bzl (76 lines) 7 # 8 # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 9 # PRELUDE ARCHAEOLOGY 10 # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 11 # 12 # The compilation database is essential for IDE tooling: 13 # - clangd uses it for code navigation, completion, diagnostics 14 # - ccls, cquery use it similarly 15 # - IDE plugins consume compile_commands.json 16 # 17 # The upstream implementation: 18 # - CxxCompilationDbInfo provider: exposes compilation commands 19 # - make_compilation_db_info: creates provider from compile commands 20 # - create_compilation_database: generates compile_commands.json 21 # 22 # What's worth keeping: 23 # - Provider definition (for integration) 24 # - Database generation logic (essential for IDEs) 25 # 26 # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 27 28 load("@straylight_prelude//:paths.bzl", "paths") 29 load("@straylight_prelude//cxx:cxx_toolchain_types.bzl", "CxxPlatformInfo", "CxxToolchainInfo") 30 load("@straylight_prelude//utils:argfile.bzl", "at_argfile") 31 load( 32 "@straylight_prelude//cxx:compile_types.bzl", 33 "CxxSrcCompileCommand", 34 ) 35 load("@straylight_prelude//cxx:cxx_context.bzl", "get_cxx_toolchain_info") 36 37 # Provider that exposes the compilation database information. 38 # Used by IDE tools to understand how to compile each source file. 39 CxxCompilationDbInfo = provider(fields = { 40 # A map of the file (an Artifact) to its corresponding CxxSrcCompileCommand 41 "info": provider_field(typing.Any, default = None), 42 # Platform for this compilation database 43 "platform": provider_field(typing.Any, default = None), 44 # Toolchain for this compilation database 45 "toolchain": provider_field(typing.Any, default = None), 46 }) 47 48 def make_compilation_db_info( 49 src_compile_cmds: list[CxxSrcCompileCommand], 50 toolchainInfo: CxxToolchainInfo, 51 platformInfo: CxxPlatformInfo) -> CxxCompilationDbInfo: 52 """Create a CxxCompilationDbInfo from a list of compile commands.""" 53 info = {} 54 for src_compile_cmd in src_compile_cmds: 55 info.update({src_compile_cmd.src: src_compile_cmd}) 56 57 return CxxCompilationDbInfo( 58 info = info, 59 toolchain = toolchainInfo, 60 platform = platformInfo, 61 ) 62 63 def create_compilation_database( 64 ctx: AnalysisContext, 65 src_compile_cmds: list[CxxSrcCompileCommand], 66 identifier: str) -> DefaultInfo: 67 """ 68 Generate a compile_commands.json for the given source compile commands. 69 70 This is the standard format consumed by clangd, ccls, and other tools. 71 """ 72 mk_comp_db = get_cxx_toolchain_info(ctx).internal_tools.make_comp_db 73 74 # Generate the per-source compilation DB entries 75 entries = {} 76 other_outputs = [] 77 78 for src_compile_cmd in src_compile_cmds: 79 cdb_path = paths.join(identifier, "__comp_db__", src_compile_cmd.src.short_path + ".comp_db.json") 80 if cdb_path not in entries: 81 entry = ctx.actions.declare_output(cdb_path) 82 cmd = cmd_args( 83 mk_comp_db, 84 "gen", 85 cmd_args(entry.as_output(), format = "--output={}"), 86 src_compile_cmd.src.basename, 87 cmd_args(src_compile_cmd.src, parent = 1), 88 "--", 89 src_compile_cmd.cxx_compile_cmd.base_compile_cmd, 90 src_compile_cmd.cxx_compile_cmd.argsfile.cmd_form, 91 src_compile_cmd.args, 92 ) 93 entry_identifier = paths.join(identifier, src_compile_cmd.src.short_path) 94 ctx.actions.run(cmd, category = "cxx_compilation_database", identifier = entry_identifier) 95 96 # Add all inputs the command uses to runtime files 97 other_outputs.append(cmd) 98 entries[cdb_path] = entry 99 100 # Merge all entries into the actual compilation DB 101 db = ctx.actions.declare_output(paths.join(identifier, "compile_commands.json")) 102 cmd = cmd_args(mk_comp_db) 103 cmd.add("merge") 104 cmd.add(cmd_args(db.as_output(), format = "--output={}")) 105 cmd.add(at_argfile( 106 actions = ctx.actions, 107 name = identifier + ".cxx_comp_db_argsfile", 108 args = entries.values(), 109 )) 110 111 ctx.actions.run(cmd, category = "cxx_compilation_database_merge", identifier = identifier) 112 113 return DefaultInfo(default_output = db, other_outputs = other_outputs)