[9.0.0] Add support for multiple module interfaces per `cc_library`
When multiple module_interfaces are specified on a single cc_library, the individual compilation actions form a DAG based on imports between these modules. Consider the following situation:
a.cppmimportsb.cppm, both of which are in themodule_interfacesof a singlecc_library.- Building the target populates the action cache with an entry for
a.pcmthat storesb.pcmas a discovered input. - Now edit
a.cppmandb.cppmso thatb.cppmimportsa.cppmanda.cppmno longer importsb.cppm. - Build again (optionally after a shutdown).
Before this commit, this resulted in an action cycle since during action cache checking, Bazel would reuse or look up the inputs discovered in the previous build, thus introducing an edge from a.pcm to b.pcm. Together with the newly discovered edge from b.pcm to a.pcm, this resulted in a cycle.
This is fixed by not requesting the previously discovered inputs (either retained in memory or in the action cache) if the mandatory inputs changed. In the case of C++20 modules, this is sufficient since the modmap file, which lists all transitive .pcm files required for compilation, is a mandatory input.
As part of this change, MetadataDigestUtils.fromMetadata had to be modified to always return a byte array of proper digest length, even if called with an empty map, to match the assumptions of the action cache.
This change is pretty much Fabian's PR https://github.com/bazelbuild/bazel/pull/27492 with a tiny fix added on top (not returning from computeMandatoryInputsDigest() early on valuesMissing() if inErrorBubbling() is true)
Closes #27492.
PiperOrigin-RevId: 842733471 Change-Id: I48fa2c0bceb888dcb58db29d50c30719b2122c5d (cherry picked from commit cb9bd8615210dda2104f79d281938e47187dc2de)
Closes #27544
Summary of Changes
Hello @fmeum, I'm Gemini Code Assist[^1]! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request addresses a critical issue in Bazel's action caching system that could lead to action cycles when working with C++20 modules, particularly when the import relationships between module_interfaces within a cc_library change. The core of the solution involves enhancing the action cache to track and validate a 'mandatory inputs digest'. This ensures that if the essential inputs of an action, such as the C++20 module map, change, the action is re-executed rather than relying on potentially stale discovered inputs, thereby preventing erroneous build cycles.
Highlights
- Action Cycle Prevention: Introduced a mechanism to prevent action cycles in Bazel's action cache when C++20 module import dependencies change. This is achieved by not reusing previously discovered inputs if the mandatory inputs for an action have been altered.
- Mandatory Inputs Digest: Added a new concept of 'mandatory inputs digest' to the action cache. This digest is computed for an action's essential inputs and is used to determine if a re-execution is necessary, even if previously discovered inputs are available.
- Action Cache Updates: Modified the
ActionCacheCheckerandActionCacheto store and check this new mandatory inputs digest, ensuring that the cache correctly invalidates entries when module dependencies shift. - Metadata Handling: Updated
MetadataDigestUtils.fromMetadatato consistently return a byte array of the correct digest length, even for empty metadata maps, to align with action cache assumptions. - C++20 Module Integration Tests: Added new integration tests specifically designed to validate the fix for action cycles when C++20 module import graphs change (e.g.,
aimportsbchanging tobimportsa).
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in pull request comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with :thumbsup: and :thumbsdown: on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
[^1]: Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.
@fmeum Could you please resolve the conflicts?
@iancha1992 Should be fixed