Add best effort toolchain feature docs#701
Conversation
I took a pass at doing some base level documentation for all the magic features that apply to cc toolchains. This doesn't exhaustively list their behavior, but it gives a useful bit of context for folks. This is useful for folks who are trying to enable specific things and who are writing their own toolchains. I tried to put enough comments in here about how this doesn't mean it's treated as public API.
|
Pure gold ! How I wish I had access to such documentation when starting writing CC toolchain. |
Dragnalith
left a comment
There was a problem hiding this comment.
Documenting features is a great. The information is strongly missing when you are new to bazel rules_cc and want to create a new toolchain from scratch.
I made a lot of comment about the structure, I hope it is not overwhelming. I have integrated all my suggestion into another version (co-authored with Claude Opus 4.7) of the beginning of features.md, just to give an idea.
CC Toolchain Features
This document covers rules_cc well-known C++ toolchain features.
NOTE: This document may drift from the rules_cc implementation, as it is not kept in sync. Please file issues or submit PRs for any inaccuracies.
Feature basics
A feature is a named piece of C++ toolchain configuration. It has two independent states: defined and enabled.
A feature is defined when the toolchain configuration declares it, typically as a known_features = [':feature1', ':feature2', ':feature3', ...] entry in the toolchain's Starlark referecing some cc_features rules.
A feature is enabled when feature resolution selects it for a given build. Enabling a feature can do two things:
- contribute command-line arguments to compile, link, archive, or other toolchain actions, via the feature's flag sets;
- influence
rules_ccrule implementation logic, but only when the feature name is known marker to that logic.
A feature can become enabled through several mechanisms:
- by default in the toolchain, via
enabled_features = [':feature1', ':feature3',...]; - by the user on the command line, via --features;
- by the features attribute on
repo,package, orcc_*rules; - by
rules_ccbased on other configuration, such as enabling theoptfeature when--compilation_mode=opt; - implicitly via feature relationships in the toolchain, such as
implies.
Feature resolution takes these requests together with the toolchain's constraints (requires, implies, provides, disabled features) and computes the final set of enabled features. This final set may contain more features than were explicitly requested.
Kinds of well-known features
Well-known features fall into three kinds:
Marker features. rules_cc or Bazel core reads the name and branches on whether the feature is enabled. Some markers also need flag_sets for the overall behavior to be correct: generated_debug_symbols makes the rules expose a .pdb as an additional output, but the toolchain must contribute /DEBUG so the linker actually produces it. Others are pure markers with no flags, like targets_windows, which only informs rules_cc about the target platform.
Configuration features. rules_cc or Bazel core enables the feature based on the build configuration, as a hook for the toolchain to respond. --compilation_mode=opt enables the opt feature; a toolchain wanting -O2 in opt builds attaches a flag_set to opt. The rules forward the configuration through the feature system without knowing what flags the toolchain chooses.
Conventional features. The name is an ecosystem convention, but neither rules_cc nor Bazel core reads it. Behavior comes entirely from the flag_sets the toolchain attaches. treat_warnings_as_errors is typical: a toolchain that defines it adds -Werror-style flags; a toolchain that doesn't has no such feature. The name itself carries no guarantee.
| NOTE: It's possible this document has drifted, please file issues or | ||
| submit PRs for any inaccuracies you find | ||
|
|
||
| ## Toolchain features |
There was a problem hiding this comment.
I think it is possible to restructure this paragraph by first introducing the concept of feature, then the different types of features.
I can imagine the following structure:
- Features Basics
- feature definition
- feature state (defined and enabled)
- what enabled feature do: add cli args and modify rules logic
- how are features enabled
- Features Types
- Marker Features: enable logic
- Configuration Features: are enabled by certain configuration state (etc. --compilation_mode=opt)
- Conventional Features: named not recognized by rules_cc, but convention in the bazel ecosystem (e.g treat_warnings_as_error)
Those types can be used as category to group features in the reference paragraph below
| NOTE: It's possible this document has drifted, please file issues or | ||
| submit PRs for any inaccuracies you find | ||
|
|
||
| ## Toolchain features |
There was a problem hiding this comment.
It would be great in the future to elaborate a bit more on this section. As a user some parts surprise me but maybe I'm not yet well familiar with the vision for rules_cc. I guess that such written vision for the entire rules_cc would be required first.
Right now rules_cc mentions in the main readme that it provides autodetected toolchains, and that there are other toolchains that provide hermetic toolchains.
https://github.com/bazelbuild/rules_cc#using-the-rules_cc-toolchain
A very fundamental use of toolchain features, is to provide the same semantic meaning accross toolchains. As a user, you can use the feature name to communicate what you want and the different toolchains can implement it the best way they can.
In the moment that you say that the feature names are not part of the public API, raises a bit of concerns to me. Because this would mean that every time a feature name changes, another toolchain that is not part of rules_cc would have to be adapted.
Every time that I thought what should be part of rules_cc or not, I always had mix feelings. One one side rules_cc cannot consider every single C++ compiler, compiler version, and build flags. On the otherside, leaving that part to compiler specific toolchain might not be the best, considering that there are some kind of compiler families that they user very similar flags.
In the end with this comment I just wanted to share my thoughts. This is great work and it is clearly better to have it here than having it in code. At least with a readme it might job a bit better intention.
I believe that any improvement can be done afterwards.
There was a problem hiding this comment.
@limdor I share the same opinion.
In rules_cc, features fit on a fence. The communication around makes user believe features are not part of the public API. But in practice they are public API because you can't implement a cc_toolchain without using well-known features.
Also, C++ library developer can't decouple their BUILD file from the toolchain implementation. For instance if you want to enable C++20, you either need to believe the toolchain expose a feature for that (e.g cxx_standard_20) or you need to branch on @rules_cc//cc/compiler's value to select between -std=c++20 for gcc/clang or /std:c++20 for msvc. Either the feature or the compiler name needs to be standardized.
@keith is there a desire from the rules_cc's maintainers to progress into that direction? If we would like to contribute what is the best way? start by writing a design doc?
|
|
||
| This feature must be enabled if targeting Windows. | ||
|
|
||
| ### `treat_warnings_as_errors` |
There was a problem hiding this comment.
I have the impression treat_warnings_as_errors may not belong to that list.
In the contrary of all other feature which are recognized by bazel and rules_cc, this one is just a name convention used by default toolchains, no?
I took a pass at doing some base level documentation for all the magic
features that apply to cc toolchains. This doesn't exhaustively list
their behavior, but it gives a useful bit of context for folks. This is
useful for folks who are trying to enable specific things and who are
writing their own toolchains. I tried to put enough comments in here
about how this doesn't mean it's treated as public API.