Using a Pigweed module in an existing Bazel project#

This guide explains how to start using a Pigweed module in your existing Bazel-based C or C++ project. We’ll assume you’re familiar with the build system at the level of the Bazel tutorial.

Supported Bazel versions#

Pigweed uses Bazel 8 features like platform-based flags, and so not all of Pigweed works with Bazel 7. However, as of 2024 Dec 13 we are still working on getting Pigweed to build with the final, released 8.0.0 version (b/372510795).

The upshot is that there’s no released version of Bazel with which all of Pigweed is guaranteed to build. In our own testing, we use the following pre-release version of Bazel 8:

1ff5af18d045e8f30a2a0367470db4e8225a785c

Add Pigweed as an external dependency#

Pigweed can be used in both bzlmod and WORKSPACE based projects.

We recommend using bzlmod (it’s the future!), but note that Pigweed’s FuzzTest and GoogleTest integration cannot yet be used in bzlmod-based projects (https://pwbug.dev/365103864).

Use a git_override:

bazel_dep(name = "pigweed")
bazel_dep(name = "pw_toolchain")

git_override(
    module_name = "pigweed",
    commit = "c00e9e430addee0c8add16c32eb6d8ab94189b9e",
    remote = "https://pigweed.googlesource.com/pigweed/pigweed.git",
)

git_override(
    module_name = "pw_toolchain",
    commit = "c00e9e430addee0c8add16c32eb6d8ab94189b9e",
    remote = "https://pigweed.googlesource.com/pigweed/pigweed.git",
    strip_prefix = "pw_toolchain_bazel",
)

You can find the latest tip-of-tree commit in the History tab in CodeSearch.

If you manage your dependencies as submodules, you can add Pigweed as a submodule, too, and then add it to your MODULE.bazel as a local_path_override:

local_path_override(
    module_name = "pigweed",
    path = "third_party/pigweed",
)

local_path_override(
    module_name = "pw_toolchain",
    path = "third_party/pigweed/pw_toolchain_bazel",
)

Pigweed is not yet published to the Bazel Central Registry. If this is a pain point for you, please reach out to us on chat.

Add Pigweed as a git_repository in your WORKSPACE:

git_repository(
    name = "pigweed",
    commit = "c00e9e430addee0c8add16c32eb6d8ab94189b9e",
    remote = "https://pigweed.googlesource.com/pigweed/pigweed.git",
)

git_repository(
    name = "pw_toolchain",
    commit = "c00e9e430addee0c8add16c32eb6d8ab94189b9e",
    remote = "https://pigweed.googlesource.com/pigweed/pigweed.git",
    strip_prefix = "pw_toolchain_bazel",
)

You can find the latest tip-of-tree commit in the History tab in CodeSearch.

If you manage your dependencies as submodules, you can add Pigweed as a submodule, too, and then add it to your WORKSPACE as a local_repository:

local_repository(
    name = "pigweed",
    path = "third_party/pigweed",
)

Use Pigweed in your project#

Let’s say you want to use pw::Vector from pw_containers, our embedded-friendly replacement for std::vector.

  1. Include the header you want in your code:

    #include "pw_containers/vector.h"
    
  2. Look at the module’s build file to figure out which build target you need to provide the header and implementation. For pw_containers/vector.h, it’s //pw_containers:vector.

  3. Add this target to the deps of your cc_library or cc_binary:

    cc_library(
        name = "my_library",
        srcs  = ["my_library.cc"],
        hdrs = ["my_library.h"],
        deps = [
            "@pigweed//pw_containers:vector",  # <-- The new dependency
        ],
    )
    
  4. Add a dependency on @pigweed//pw_build:default_link_extra_lib to your final binary target. See Libraries required at linktime for a discussion of why this is necessary, and what the alternatives are.

    cc_binary(
        name = "my_binary",
        srcs  = ["my_binary.cc"],
        deps = [
            ":my_library",
            "@pigweed//pw_build:default_link_extra_lib",  # <-- The new dependency
        ],
    )
    

Set the required Bazel flags#

Pigweed projects need to set certain flags in their .bazelrc. These generally pre-adopt Bazel features that will become default in the future and improve cache performance, disambiguate Python imports, etc. These flags are listed below. Unfortunately there’s no way to automatically import them, see b/353750350.

# Copyright 2024 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.

# Standard Bazel configuration flags required for all Pigweed projects.

# Don't automatically create __init__.py files.
#
# This prevents spurious package name collisions at import time, and should be
# the default (https://github.com/bazelbuild/bazel/issues/7386). It's
# particularly helpful for Pigweed, because we have many potential package name
# collisions due to a profusion of stuttering paths like
# pw_transfer/py/pw_transfer.
common --incompatible_default_to_explicit_init_py

# Required for new toolchain resolution API.
build --incompatible_enable_cc_toolchain_resolution

# Do not attempt to configure an autodetected (local) toolchain. We vendor all
# our toolchains, and CI VMs may not have any local toolchain to detect.
common --repo_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1

# Don't propagate flags or defines to the exec config. This will become the
# default one day (https://github.com/bazelbuild/bazel/issues/22457) and will
# improve cache hit rates between builds targeting different platforms.
common --experimental_exclude_defines_from_exec_config
common --experimental_exclude_starlark_flags_from_exec_config

# Enforces consistent action environment variables. This is important to
# address Protobuf's rebuild sensitivity on changes to the environment
# variables. It also improves cache hit rates. Should be true by default one
# day (https://github.com/bazelbuild/bazel/issues/7026).
build --incompatible_strict_action_env

# Expose exec toolchains for Python. We use these toolchains in some rule
# implementations (git grep for
# "@rules_python//python:exec_tools_toolchain_type").
build --@rules_python//python/config_settings:exec_tools_toolchain=enabled

Configure backends for facades you depend on#

Pigweed makes extensive use of Facades & backends, and any module you choose to use will likely have a transitive dependency on some facade (typically pw_assert or pw_log). Continuing with our example, pw::Vector depends on pw_assert.

In Bazel, facades already have a default backend (implementation) that works for host builds (builds targeting your local development machine). But to build a binary for your embedded target, you’ll need to select a suitable backend yourself.

Fortunately, the default backend for pw_assert is pw_assert_basic, which is a suitable place to start for most embedded targets, too. But it depends on pw_sys_io, another facade for which you will have to choose a backend yourself.

The simplest way to do so is to set the corresponding label flag when invoking Bazel. For example, to use the pw_sys_io_baremetal_stm32f429 backend for pw_sys_io provided in upstream Pigweed:

$ bazel build \
    --@pigweed//targets/pw_sys_io_backend=@pigweed//pw_sys_io_baremetal_stm32f429 \
    //path/to/your:target

You can also define backends within your own project. (If Pigweed doesn’t include a pw_sys_io backend suitable for your embedded platform, that’s what you should do now.) See Facades and backends tutorial for a tutorial that dives deeper into facade configuration with Bazel.