Goal: Enable awesome tooling for Bazel users of the C language family.

Overview

Hedron's Compile Commands Extractor for Bazel — User Interface

What is this project trying to do for me?

First, provide Bazel users cross-platform autocomplete for (Objective-)C(++) to make development more efficient and fun. More generally, export Bazel build actions into the compile_commands.json format that enables great tooling decoupled from Bazel.

Status: Pretty great with minor rough edges. We use this every day and love it.

If there haven't been commits in a while, it's because of stability, not neglect. This is in daily use at Hedron.

For everyday use, we'd recommend using this rather than the platform-specific IDE adapters (like Tulsi or ASwB), except the times when you need some platform-editor-specific feature (e.g. Apple's NextStep Interface Builder) that's not ever going to be supported in a cross-platform editor.

Usage Visuals

Usage Animation

▲ Extracts compile_commands.json, enabling clangd autocomplete in your editor ▼

clangd help example

Usage

Howdy, Bazel user 🤠 . Let's get you set up fast with some awesome tooling for the C language family.

There's a bunch of text here but only because we're trying to spell things out and make them easy. If you have issues, let us know; we'd love your help making things even better and more complete!

First, do the usual WORKSPACE setup.

Copy this into your Bazel WORKSPACE file to add this repo as an external dependency.

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")


# Hedron's Compile Commands Extractor for Bazel
# https://github.com/hedronvision/bazel-compile-commands-extractor
http_archive(
    name = "hedron_compile_commands",

    # Replace the commit hash in both places (below) with the latest. 
    # Even better, set up Renovate and let it do the work for you (see "Suggestion: Updates" below).
    url = "https://github.com/hedronvision/bazel-compile-commands-extractor/archive/486d6eaf87255b7e15640bb9add58f0a77c1e2b6.tar.gz",
    strip_prefix = "bazel-compile-commands-extractor-486d6eaf87255b7e15640bb9add58f0a77c1e2b6",
)
load("@hedron_compile_commands//:workspace_setup.bzl", "hedron_compile_commands_setup")
hedron_compile_commands_setup()

Suggestion: Updates

We'd strongly recommend you set up Renovate (or similar) at some point to keep this dependency (and others) up-to-date by default. [We aren't affiliated with Renovate or anything, but we think it's awesome. It watches for new versions and sends you PRs for review or automated testing. It's free and easy to set up. It's been astoundingly useful in our codebase, and and we've worked with the wonderful maintainer to polish off any rough edges for Bazel use.]

If not, maybe come back to this step later, or watch this repo for updates. [Or hey, maybe give us a quick star, while you're thinking about watching.] Like Abseil, we live at head; the latest commit to the main branch is the commit you want.

Make external code easily browsable.

From your Bazel workspace root (i.e. //), run:

ln -s bazel-out/../../../external .

This makes it easy for you—and for build tooling—to see the external dependencies you bring in. It also makes your source tree have the same directory structure as the build sandbox. It looks like long ago—and perhaps still inside Google—Bazel automatically created such an //external symlink. In any event, it's a win/win to add it: It's easier for you to browse the code you use, and it eliminates whole categories of edge cases for build tooling. We'd recommend you commit this symlink to your repo so your collaborators have it, too.

Get the extractor running.

We'll generate a compile_commands.json file in the root of the Bazel workspace (Product/).

That file describes how Bazel is compiling all the (Objective-)C(++) files. With the compile commands in a common format, build-system-independent tooling (e.g. clangd autocomplete, clang-tidy linting etc.), can get to work.

We'll get it running and then move onto the next section while it whirrs away. But in the future, every time you want tooling (like autocomplete) to see new BUILD-file changes, rerun the command you chose below! Clangd will automatically pick up the changes.

There are two common paths:

1. Have a relatively simple codebase, where every target builds without needing any additional configuration?

In that case, just bazel run @hedron_compile_commands//:refresh_all

2. Often, though, you'll want to specify the output targets you care about. This avoids issues where some targets can't be built on their own; they need configuration on the command line by a parent rule. android_binaries using transitions to configure android_libraries are an example of the latter.

In that case, you can easily specify the output targets you're working on and the flags needed to build them.

Open a BUILD file—we'd recommend using (or creating) //BUILD—and add something like:

load("@hedron_compile_commands//:refresh_compile_commands.bzl", "refresh_compile_commands")

refresh_compile_commands(
    name = "refresh_compile_commands",

    # Specify the targets of interest.
    # For example, specify a dict of targets and their arguments:
    targets = {
      "//:my_output_1": "--important_flag1 --important_flag2=true, 
      "//:my_output_2": ""
    },
    # For more details, feel free to look into refresh_compile_commands.bzl if you want.
)

Editor Setup — for autocomplete based on compile_commands.json

VSCode

Make sure you have clangd's extension installed and configured.

code --install-extension llvm-vs-code-extensions.vscode-clangd

Open VSCode workspace settings.

Add the following clangd flags (as written, VSCode will expand ${workspaceFolder}).

  • They get rid of (overzealous) header insertion and are needed to help it find the compile commands, even when browsing system headers.
  • If your Bazel WORKSPACE is a subdirectory of you project, change --compile-commands-dir to point into that subdirectory

In "clangd.arguments"

--header-insertion=never
--compile-commands-dir=${workspaceFolder}/

In VSCode user settings:

Turn on: Clangd: Check Updates

You may need to reload VSCode [(CMD/CTRL+SHIFT+P)->reload] for the plugin to load.

If afterwards clangd doesn't prompt you to download the actual clangd server binary, hit (CMD/CTRL+SHIFT+P)->check for language server updates.

Other Editors

If you're using another editor, you'll need to follow the same rough steps as above: get clangd set up to extend the editor and then supply the flags.

Once you've succeeded in setting up another editor—or set up clangtidy, or otherwise seen a way to improve this tool—we'd love it if you'd contribute what you know!

"Smooth Edges" — what we've enjoyed using this for.

You should now be all set to go! Way to make it through setup.

Here's what you should be expecting, based on our experience:

We use this tool every day to develop a cross-platform library for iOS and Android on macOS. Expect Android completion in Android source, macOS in macOS, iOS in iOS, etc. We have people using it on Linux/Ubuntu, too.

All the usual clangd features should work. CMD/CTRL+click navigation (or option if you've changed keybindings), smart rename, autocomplete, highlighting etc. Everything you expect in an IDE should be there (because most good IDEs are backed by clangd). As a general principle: If you're choosing tooling that needs to understand a programming language, you want it to be based on a compiler frontend for that language, which clangd does as part of the LLVM/clang project.

Everything should also work for generated files, though you may have to run a build for the generated file to exist.

We haven't yet tested on Windows. Windows might need some patching parallel to that for macOS (in extract.py), but it should be a relatively easy adaptation compared to writing things from scratch. If you're trying to use it on Windows, let us know here. We'd love to work together to get things working smoothly.

Rough Edges

We've self-filed issues for the rough edges we know about and are tracking. We'd love to hear from you there about what you're seeing, good and bad. Please add things if you find more rough edges, and let us know if you need help or more features.

On the other hand, if you've set things up and they're working well, we'd still love to hear from you. Please file a "non-issue" in the issues tab describing your success! We'd love to hear what you're working on, what platforms you're using, and what you're finding most useful. And maybe also toss a star our way so we know it was helpful to you.

We'd also love to work with you on contributions and improvements, of course! Development setup isn't onerous; we've got a great doc to guide you quickly into being able to make the changes you need. The codebase is super clean and friendly. Stepping into the code is a fun and efficient way to get the improvements you want.


Looking for implementation details instead? Want to dive into the codebase? See ImplementationReadme.md.

Bazel/Blaze maintainer reading this? If you'd be interested in integrating this into official Bazel tools, let us know in an issue or email, and let's talk! We love getting to use Bazel and would love to help.

Comments
  • Parse inputs from ActionGraphContainer instead of arguments

    Parse inputs from ActionGraphContainer instead of arguments

    For some targets the assert for multiple source files in _get_files stops the compile commands extraction. This is due to some generated directories ending with source file extensions.

    example:

    '-isystem', 'bazel-out/k8-opt/bin/someip-posix.cc'
    

    This change does not interpret arguments as source files if the previous argument is -isystem.

    opened by alexander-born 42
  • Windows!

    Windows!

    Update: Windows support landed! Thanks all. The latest commits should have it. You can go ahead and start using this tool on Windows.

    We haven't yet tested on Windows. Windows might need some patching parallel to that for macOS (in refresh.template.py), but it should be a relatively easy adaptation compared to writing things from scratch. If you're trying to use it on Windows, let us know here. We'd love to work together to get things working smoothly.

    opened by cpsauer 35
  • clangd has trouble resolving GCC include_next for C++ system headers for headers with a

    clangd has trouble resolving GCC include_next for C++ system headers for headers with a ".h" extension

    In my C++ project the file naming convention is foo.cc for source files and foo.h for headers, which I think is not too unusual. I was puzzled about why clangd seemed to be unable to find any system headers (e.g. #include <cassert>) only when looking at my header files -- the source files worked just fine. One exciting journey through the clangd source code later, I discovered that it extracts a different set of system include paths for C- and C++-language files (naturally), but, in the absence of a -x gcc flag specifying it explicitly, will guess the language based on the file's extension.

    I was able to work around this issue without renaming my header files by adding --cxxopt=-xc++ to the refresh_compile_commands() rule in my BUILD file, like so:

    refresh_compile_commands(
        name = "refresh_compile_commands",
        targets = {
            "//myproject/...": "--cxxopt=-xc++",
        },
    )
    

    This was a big headache to track down, though. Would it make sense for bazel-compile-commands-extractor to always add this flag when running bazel aquery? If not, maybe a note in the FAQ :)

    opened by NomiChirps 29
  • Proto generated headers (*.pb.h) not included in compile_commands.json output

    Proto generated headers (*.pb.h) not included in compile_commands.json output

    First, thanks for the tool. Extremely useful.

    My issue is that my bazel build includes some .proto files, which at compile time generate .pb.h headers in the bazel cache.

    These .pb.h files in compile_commands.json appear to have the wrong directory, which leads to clangd not finding them. For example, compile_commands.json lists directory as /path/to/bazel/repo/ instead of /path/to/.cache/path/to/header.pb.h.

    Am I missing something in my configuration to support this scenario? Or is there a suggested workaround I can attempt to implement?

    opened by eschumacher-s 28
  • [Windows] Support --features=compiler_param_file

    [Windows] Support --features=compiler_param_file

    Build using --features=compiler_param_file would wrap all source files and flags into a .params file, I think we should support to read from the .params file instead of reading from command line directly.

    opened by LoSealL 24
  • Why it is compiling my code? And generation time is very long.

    Why it is compiling my code? And generation time is very long.

    I have a huge Bazel repo and I want to generate compile_commands.json.

    After I run bazel run @hedron_compile_commands//:refresh_all, I found it is compiling my code, a lot of ccplus processes have been started:

    image

    My question is why does it need to compile my code? I believe that we can get the compile commands without compiling the source code.

    Besides, compiling my code needs a long time (about 15 minutes), so it takes a long time to generate compile_commands.json.

    opened by lixin-wei 20
  • support compiler_param_file features on Windows

    support compiler_param_file features on Windows

    Highlights:

    • When enable --feature=compiler_param_file on command line or .bazelrc file, _get_file can read the actual compile args in the file
    • Fully compatible without this feature or change this feature during the developmemt.

    Lowlights:

    • When using compile commands extractor along with --feature=compiler_param_file, user must build the target once, because bazel aquery won't actually generate the .params file. (Which I think is a bazel limitation)
    • Strip tail whitespaces and fix a typo whose charactor is not encoded as unicode..
    opened by LoSealL 18
  • Add attributes to control header and external source inclusion

    Add attributes to control header and external source inclusion

    emit_headers - controls whether header files are included in the generated compile_commands.json emit_externals - same, but for external sources or headers - bazel external workspace sources, etc.

    Both default to True - the existing behaviour.

    Some tools like ccls don't seem to work well with headers in the compile_commands.json, and some large projects can generate very large compile_commands.json databases when including all external files.

    opened by dave-hagedorn 17
  • compile_commands compiled with empty array []

    compile_commands compiled with empty array []

    Hi @cpsauer , this is RE https://github.com/bazelbuild/vscode-bazel/issues/179#issuecomment-1021133142

    Thanks a lot for offering to take a look, I realize this is not an issue with this project but my setup.

    Here's my setup: https://github.com/sekoyo/cpp-orderbook

    Just barebones lib + binary + test at the moment and trying to get (VSCode) intellisense to work.

    Any pointer much appreciated!

    Running on: MacOS armv8 Bazel: 5.0.0-homebrew

    opened by DominicTobias 17
  • .h files interpretted as C

    .h files interpretted as C

    I'm working on a project in which we use .h files for cpp headers. For some reason, clangd treats these like C files after I've run the hedron commands extractor, and then VSCode complains a lot because we're including C++ libraries in what it perceives to be C code. Is there some extra piece of config I can provide to either this tool, or to clangd directly that will instruct it to treat these files like cpp?

    opened by HaberR 17
  • Improving confusing behavior when flags are passed to the refresher build

    Improving confusing behavior when flags are passed to the refresher build

    I have been using the extractor with GCC with no issue. But when I try to use Clang, I get a lot of errors that are like this:

    clang-13: error: no such file or directory: 'bazel-out/k8-fastbuild/bin/external/sdformat/src/EmbeddedSdf.cc'
    clang-13: error: no input files
    clang-13: error: no such file or directory: 'bazel-out/k8-fastbuild/bin/external/yaml_cpp_internal/drake-src/convert.cpp'
    clang-13: error: no input files
    ...
    

    These external packages are the dependencies of another package.

    opened by aminya 15
  • Add customization for git ignore file

    Add customization for git ignore file

    Define hedron_compile_commands_setup to perform installation configuration. Values set during this step remain constant across invocations of refresh_compile_commands.

    This commit introduces a single install config parameter ignore_file. If not set, .gitignore is used. This can be replaced with the local, unversioned ignore file .git/info/exclude.

    opened by oliverlee 2
  • Can we support inputs filter in bazel aquery?

    Can we support inputs filter in bazel aquery?

    Bazel's aquery functions can combine many interesting usage. In my case, I am writing an extension integrating with compile_commands based on file granularity and I need a file filter from the root target.

    I have done a commit https://github.com/xinzhengzhang/bazel-compile-commands-extractor/commit/56e4147cdfcaed2a154d81d8933427681ba5d7d1 since the target configuration is a dictionary now I have not consider the use case of multiple targets. Back to the issue, do we need to support this feature? If there is any suggestion how to design the interface? I'd be happy to implement it.

    refresh_compile_commands(
      name = "refresh_compile_commands",
      targets = {
        "//path:target": ""
      },
      # This string will vary depending on the file opened by the extension
      input_filter = "a/b/c/file.c",
      tags = ["manual"],
    )
    
    opened by xinzhengzhang 25
  • [Self-Filed] Bzlmod support

    [Self-Filed] Bzlmod support

    opened by cpsauer 1
  • [Self-Filed] [Feature] Running clang-tidy from the command line

    [Self-Filed] [Feature] Running clang-tidy from the command line

    Hey all! Self-filing an issue to collect interest and feedback.

    Some people have been using this tool and compile_commands.json to run clang-tidy from the command line. [Clang-tidy can also run as part of clangd while editing.] Sounds like other tools have some issues around headers, which we can solve.

    Doing this well would probably involve creating a target that builds a script that runs a bazel-cached clang-tidy aspect over the codebase.

    LMK if interested. Would love some help on this one. I do think it'd be much easier to build well within the context of this tool than standalone.

    opened by cpsauer 3
  • [Self-Filed] For files compiled for multiple platforms, I'm seeing suggestions for a specific platform. Shouldn't I just see suggestions for what's accessible on all platforms?

    [Self-Filed] For files compiled for multiple platforms, I'm seeing suggestions for a specific platform. Shouldn't I just see suggestions for what's accessible on all platforms?

    Suggested Workaround: You should, but you'll have to do this in your head for now. At least there's autocomplete for everything you want to use--the issue is that there's also autocomplete for things you shouldn't use.

    Status: This'd be for clangd to fix. Filed an issue, but the fixes are likely fairly gnarly.

    opened by cpsauer 2
Owner
Hedron Vision
Hedron, like polyhedron. We make magical, visual software...
Hedron Vision
Secret santa is a fun and easy way to get together with your friends and/or family with a gift for them.

Secret Santa What is Secret Santa? Secret santa is a fun and easy way to get together with your friends and/or family with a gift for them. The idea i

null 2 Dec 6, 2021
Addon to give a keybind to automatically enable contact shadows on all lights in a scene

3-2-1 Contact(Shadow) An easy way to let you enable contact shadows on all your lights, because Blender doesn't enable it by default, and doesn't give

TDV Alinsa 3 Feb 2, 2022
Boot.img patcher for Tolino ebook readers to enable ADB and root.

I'm not responsible for any damage to your devices by running this tool. Please note that you may loose warranty when using this, although (This is no

Aaron Dewes 9 Nov 13, 2022
Battery conservation Python script for ubuntu to enable battery conservation mode at 60% 80% or 90%

Description Batteryconservation is a small python script wich creates an appindicator for ubuntu which can be used to enable / disable battery conserv

null 3 Jan 4, 2022
A Blender addon to enable reloading linked libraries from UI.

library_reload_linked_libraries A Blender addon to enable reloading linked libraries from UI.

null 3 Nov 27, 2022
Incident Response Process and Playbooks | Goal: Playbooks to be Mapped to MITRE Attack Techniques

PURPOSE OF PROJECT That this project will be created by the SOC/Incident Response Community Develop a Catalog of Incident Response Playbook for every

Austin Songer 987 Jan 2, 2023
run-js Goal: The Easiest Way to Run JavaScript in Python

run-js Goal: The Easiest Way to Run JavaScript in Python features Stateless Async JS Functions No Intermediary Files Functional Programming CommonJS a

Daniel J. Dufour 9 Aug 16, 2022
The goal of this program was to find the most common color in my living room.

The goal of this program was to find the most common color in my living room. I found a dataset online with colors names and their corr

null 1 Nov 9, 2021
Coursework project for DIP class. The goal is to use vision to guide the Dashgo robot through two traffic cones in bright color.

Coursework project for DIP class. The goal is to use vision to guide the Dashgo robot through two traffic cones in bright color.

Yueqian Liu 3 Oct 24, 2022
A code base for python programs the goal is to integrate all the useful and essential functions

Base Dev EN This GitHub will be available in French and English FR Ce GitHub sera disponible en français et en anglais Author License Screen EN ???? D

Pikatsuto 1 Mar 7, 2022
This alerts you when the avalanche score a goal

This alerts you when the avalanche score a goal

Davis Burrill 1 Jan 15, 2022
Bootstraparse is a personal project started with a specific goal in mind: creating static html pages for direct display from a markdown-like file

Bootstraparse is a personal project started with a specific goal in mind: creating static html pages for direct display from a markdown-like file

null 1 Jun 15, 2022
🏆 A ranked list of awesome Python open-source libraries and tools. Updated weekly.

Best-of Python ?? A ranked list of awesome Python open-source libraries & tools. Updated weekly. This curated list contains 230 awesome open-source pr

Machine Learning Tooling 2.7k Jan 3, 2023
This repository is an archive of emails that are sent by the awesome Quincy Larson every week.

Awesome Quincy Larson Email Archive This repository is an archive of emails that are sent by the awesome Quincy Larson every week. If you fi

Sourabh Joshi 912 Jan 5, 2023
Participants of Bertelsmann Technology Scholarship created an awesome list of resources and they want to share it with the world, if you find illegal resources please report to us and we will remove.

Participants of Bertelsmann Technology Scholarship created an awesome list of resources and they want to share it with the world, if you find illegal

Wissem Marzouki 29 Nov 28, 2022
A curated list of awesome things related to Pydantic! 🌪️

Awesome Pydantic A curated list of awesome things related to Pydantic. These packages have not been vetted or approved by the pydantic team. Feel free

Marcelo Trylesinski 186 Jan 5, 2023
laTEX is awesome but we are lazy -> groff with markdown syntax and inline code execution

pyGroff A wrapper for groff using python to have a nicer syntax for groff documents DOCUMENTATION Very similar to markdown. So if you know what that i

Subhaditya Mukherjee 27 Jul 23, 2022
A Curated Collection of Awesome Python Scripts

A Curated Collection of Awesome Python Scripts that will make you go wow. This repository will help you in getting those green squares. Hop in and enjoy the journey of open source. ??

Prathima Kadari 248 Dec 31, 2022
An awesome script to convert the University Of Oviedo web calendar to Google or Outlook calendars.

autoUniCalendar Un script en Python para convertir el calendario de la intranet de la Universidad de Oviedo en un calendario de Outlook o Google Calen

Bimo99B9 14 Sep 28, 2022