bazelbuild / bazelbuild/rules_cc
composable configurations for C/C++ rules
- Dominant language
- Starlark
- Stars
- 247
- Forks
- 196
- PR merge metrics
- No merged PRs in 30d
Description
When maintaining BUILD files for cross-platform C/C++ libraries, I often run into cases where the same condition needs to affect several attributes at once. A platform may require its own sources, configuration headers, include paths, defines, compiler options, and linker options.
[V8](https://github.com/v8/v8/blob/main/BUILD.bazel) and [OpenSSL](https://registry.bazel.build/modules/openssl/4.0.1.bcr.0/overlay/BUILD.bazel) both have examples of this. The OpenSSL BCR overlay already organizes a large amount of configuration by OS and architecture, but the same platform conditions still have to be repeated across attributes such as `srcs`, `copts`, `includes`, and `linkopts`.
A target will typically end up looking something like this:
```starlark
cc_library(
name = "portable",
srcs = select(OS_SRCS) + select(CPU_SRCS),
hdrs = select(OS_HDRS),
includes = select(OS_INCLUDES),
copts = select(OS_COPTS) + select(COMPILER_COPTS),
local_defines = select(OS_DEFINES) + select(FEATURE_DEFINES),
linkopts = select(OS_LINKOPTS),
)
```
This works, but it scatters a platform's configuration across the target. Adding a platform means updating several separate `select()` expressions, and reusing the same configuration in another target is awkward.
Another option is to define separate targets for combinations such as `linux_x86_clang`, `linux_arm64_clang`, and `windows_x86_msvc`. As the number of operating systems, CPU architectures, compilers, and feature flags grows, these combinations quickly become difficult to maintain.
It would be useful to declare a related set of C/C++ attributes as a reusable configuration, then select and compose those configurations in a `cc_library`. The following is only pseudocode intended to illustrate the idea; `cc_config`, `configs`, and the individual attribute names do not need to be the final API:
```starlark
cc_config(
name = "common",
local_defines = ["EVENT_LOOP_BUILD=1"],
)
cc_config(
name = "posix",
configs = [":common"],
srcs = ["platform/posix.c"],
hdrs = ["config/posix.h"],
includes = ["config"],
)
cc_config(
name = "linux",
configs = [":posix"],
srcs = ["platform/epoll.c"],
local_defines = ["USE_EPOLL=1"],
)
cc_config(
name = "windows",
configs = [":common"],
srcs = ["platform/iocp.c"],
hdrs = ["config/windows.h"],
includes = ["config"],
linkopts = ["-lws2_32"],
)
cc_config(
name = "arm64",
srcs = ["arch/arm64.c"],
)
cc_config(
name = "clang",
copts = ["-Wno-deprecated-declarations"],
)
cc_config(
name = "tracing",
local_defines = ["ENABLE_TRACING=1"],
)
cc_library(
name = "event_loop",
srcs = ["event_loop.c"],
configs = (
select({
"@platforms//os:linux": [":linux"],
"@platforms//os:windows": [":windows"],
"//conditions:default": [":posix"],
}) +
select({
"@platforms//cpu:arm64": [":arm64"],
"//conditions:default": [],
}) +
select({
":using_clang": [":clang"],
"//conditions:default": [],
}) +
select({
":tracing_enabled": [":tracing"],
"//conditions:default": [],
})
),
)
```
In this example, Linux can reuse the POSIX and common configuration, while the OS, CPU architecture, compiler, and tracing settings remain independently maintained. A combined configuration is only needed when two dimensions genuinely interact.
I realize that Bazel can already express the same result using repeated `select()` expressions, macros, or generated BUILD files. This request is mainly about ergonomics and maintainability: a standard mechanism in `rules_cc` would keep each project from having to invent its own way to organize these configurations.
As an optional API, this would not require changes to existing BUILD files. A simpler way to organize C/C++ configuration could also lower the cost of adding and maintaining Bazel support in third-party projects, help Bazel cover more of the existing C/C++ ecosystem, and improve the experience of adopting Bazel.
Contributor guide
Research direction
Start by comparing the repeated select() patterns in the linked V8 and OpenSSL BUILD.bazel examples with the proposed cc_config and cc_library configs API. Trace how rules_cc currently handles C/C++ attributes and configuration composition, then define the API scope and tests needed to show reusable OS, CPU, compiler, and feature configurations work together.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, cpp
- Domain
- build-system
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100