armbazelbazel-cpp

How to add a dependency to all linked targets using Bazel's cc_toolchain?


I've followed the tutorial here to create a custom Bazel toolchain that builds and links a binary for a baremetal ARM platform. My binary target currently looks like this:

cc_binary(
  name = "hello-world",
  srcs = [
    "hello-world.cpp",
  ],
  linkopts = ["-T", "$(location :FLASH.ld)"],
  deps = [
    "//libc:polyfill",
    ":FLASH.ld",
  ],
)

I'm using newlib, so the target //libc:polyfill is a static library that contains implementations of some C standard library functions for my platform--e.g., open(), sbrk(), etc. The definition for that target looks like this:

cc_library(
  name = "polyfill",
  srcs = [
    "syscalls.c",
    "sysmem.c",
  ],

  # Causes bazel to always link this library, and wrap it in
  # -Wl,--whole-archive, which is needed to prevent symbol resolution errors
  # related to link order (since this library implements some C standard
  # library functions). See:
  # https://bazel.build/reference/be/c-cpp#cc_library
  alwayslink = True,
)

I would like my toolchain to automatically add //libc:polyfill as a dependency for all linked targets using my toolchain. The Toolchains page provides an example using a totally custom rule, but I want to leverage cc_toolchain if possible. How can I accomplish this?


Solution

  • I've never found a good way of doing that with a Bazel rule. The best way I've found is compiling your library separately and then adding it to the appropriate sets of linker flags. You'll also need to add it to cc_toolchain.linker_files (or one of the other attributes) so your library is an input to the appropriate linking actions. You can use genrule to compile the library, but cc_library is awkward because you need a separate toolchain to avoid circular dependencies.

    The less-good way I've done this is by abusing --custom_malloc. You can set it to a library that uses select to add a dependency on your desired library for targets using this particular toolchain (--custom_malloc applies to all targets, including host ones, so you do need the select). You also have to use malloc = None on those libraries to avoid circular dependencies. I've used this approach before, but it gets kind of annoying when you start using query/cquery, and it's pretty bad for caching.