Projects#

pw_ide: Code editor and IDE support for Pigweed projects

There are broadly two types of Pigweed projects that Pigweed’s IDE tooling supports:

  • Bootstrap projects, in which a development environment is populated by sourcing binary dependencies from CIPD, and is accessed by setting environment variables via bootstrap and activate shell scripts. Usually, the build system is GN or CMake.

  • Bazel projects, in which Bazel is the build system, Bazel manages development environment dependencies, and the bazel (or bazelisk) command is the entry point into all tooling

Other project configurations are possible, but these are the two that our IDE tooling recognizes and supports.

Project structure#

For both project types, we look for the presence of a pigweed.json file to indicate the root of the project directory.

Bootstrap projects#

This project structure has the following properties:

  • Development tools and dependences are located in an environment directory.

Note

The location and name of the environment can be actually customized when running bootstrap.sh, and multiple independent environments are supported.

  • Access to the development environment is provided through mutations to the shell environment; the $PATH is modified to point to locations in environment, and Pigweed-specific environment variables are used to configure the development environment.

  • A bootstrap.sh script creates the environment directory, populates it with development tools and dependencies, and modifies the environment of the shell in which the script was run to provide access to the development environment.

  • As a side effect of the bootstrap process, an actions.json file is created in the environment directory that describes the mutations to the shell environment required to provide access to the development environment.

  • Pigweed commands are made available via an executable called pw.

Assuming the environment has already been bootstrapped, exposing the development environment to an IDE or other developer tooling requires:

  • Finding the environment directory, or potentially multiple environment directories. We do this by looking for directories with an actions.json file.

  • Executing commands within a shell environment modified per the actions.json file. How this is done depends on the language and runtime of the IDE. An example in JavaScript:

// Assuming `actionsJson` is a parsed `actions.json` file, and `activateEnv`
// is a function that applies the mutations described in `actionsJson` to
// a shell environment.
const activatedEnv = activateEnv(process.env, actionsJson);
child_process.exec("clang", activatedEnv);

If the environment has not been bootstrapped yet, we just need to run bootstrap.sh. It’s not necessary to capture the mutated shell environment that results from running the script, since we have access to it through the steps described above.

Bazel projects#

This project structure has the following properties:

  • Development tools and dependences are managed by Bazel. There are multiple mechanisms for this, including WORKSPACE and bzlmod. Regardless of the mechanism used, Bazel manages the tools and dependencies, and their location on disk.

  • The Bazel environment is created and updated by running a Bazel build command.

  • Access to tools and commands in the development environment is provided by Bazel itself. In other words, the bazel executable is the entry point to all project operations.

So all that’s required to expose the development environment to an IDE is to execute bazel run commands.

Managing Bazel environments#

It’s important to use the version of Bazel specified by the project, and to use a single Bazel environment and build directory regardless of the tools the developer is using. For example, a developer should be able to edit code in their IDE and run Bazel commands from a separate terminal and be sure that all of those actions will execute within the same environment.

We ensure that behavior by using bazelisk instead of plain bazel. It wraps bazel and ensures that your project uses the exact version of Bazel specified in the project’s .bazelversion file.

A developer can have multiple installations of bazelisk from different sources, and invocations of any of those executables on the same project will all run in the same Bazel environment. So we can actually bundle bazelisk with the IDE, ensuring that it’s available to IDE functionality, without worrying about it conflicting with the developer’s use of bazelisk in the terminal or in other tools.