rules_autoconf
Bazel-native autoconf-style configuration. cc_check_{header,function,symbol} + config_header — replaces autoconf+m4 with a graph of cache-aware Bazel actions.
| Latest | 0.1.0 |
|---|---|
| Versions | 1 |
| Category | Bazel rules |
| Compat level | 1 |
| Maintainers | Matt Marshall |
| Registry | https://registry.tbzl.dev/modules/rules_autoconf/ |
| Source | github.com/tomato-bazel/rules_autoconf |
bazel_dep(name = "rules_autoconf", version = "0.1.0")
View source & releases on GitHub ↗
Bazel-native autoconf-style configuration. Replaces the autoconf+m4 shell pipeline with Bazel rules that compose probe results into a graph.
cc_check_header— autoconf’sAC_CHECK_HEADER. Bazel-native equivalent.cc_check_function— autoconf’sAC_CHECK_FUNC(compile + link test).cc_check_symbol— autoconf’sAC_CHECK_DECL/AC_CHECK_TYPE.config_header— autoconf’sAC_CONFIG_HEADERS. Renders aconfig.htemplate from adefinesdict + probe results.
See docs/defs.md for the full reference.
What this is and isn’t (v0.1)
Is: the Bazel-native seed of an autoconf replacement. Probes execute as
Bazel actions, so their results compose into the build graph and are
cache-aware. No shell, no m4, no configure script generation.
Isn’t (yet): a full autoconf clone. v0.1 covers the most common AC_*
primitives — enough to ground a hand-written config.h.in against the
host. The long tail (AC_C_BIGENDIAN, AC_CHECK_SIZEOF, AC_FUNC_*
function-specific tests, AC_PROG_* program detection) lands in
subsequent releases.
Doesn’t run real autoconf: v0.1 has no autoconf or m4 binary
dependency. The probes use the host C compiler (whatever $CC resolves
to, defaulting to cc). For projects that ship a pre-generated
configure script (like PostgreSQL), a future configure_run rule
will let you invoke it under Bazel sandboxing without needing autoconf
itself. For projects that need autoconf-generated configure scripts
built on the fly, that’s v0.3+ work.
Install
Add the registry to your .bazelrc:
common --registry=https://registry.fastverk.com/
common --registry=https://bcr.bazel.build/
In your MODULE.bazel:
bazel_dep(name = "rules_autoconf", version = "0.1.0")
Quick start
A typical autoconf project has a config.h.in template with #undef
stubs. Tell rules_autoconf which probes to run and what static values to
substitute:
load(
"@rules_autoconf//autoconf:defs.bzl",
"cc_check_function",
"cc_check_header",
"config_header",
)
cc_check_header(name = "have_stdio_h", header = "stdio.h")
cc_check_header(name = "have_sys_socket_h", header = "sys/socket.h")
cc_check_function(
name = "have_strlcpy",
function = "strlcpy",
header = "string.h",
)
cc_check_function(
name = "have_openssl_init_ssl",
function = "OPENSSL_init_ssl",
header = "openssl/ssl.h",
libraries = ["ssl", "crypto"],
)
config_header(
name = "config_h",
out = "config.h",
template = "config.h.in",
defines = {
"PACKAGE_NAME": "\"myproj\"",
"PACKAGE_VERSION": "\"0.1.0\"",
},
probes = [
":have_stdio_h",
":have_sys_socket_h",
":have_strlcpy",
":have_openssl_init_ssl",
],
)
bazel build //path/to:config_h runs each probe as a Bazel action,
captures its success/failure, and stamps the result into config.h:
/* config.h */
#define PACKAGE_NAME "myproj"
#define PACKAGE_VERSION "0.1.0"
#define HAVE_STDIO_H 1
#define HAVE_SYS_SOCKET_H 1
#define HAVE_STRLCPY 1
#undef HAVE_OPENSSL_INIT_SSL /* OpenSSL not in -lssl -lcrypto on this host */
The probes are content-addressed by their inputs (header name, function
signature, library list, host compiler), so they’re cached: rebuilding
without changing probe attrs reuses results. Changing a probe attr
invalidates only its own result and the downstream config_header.
How it differs from rules_foreign_cc
rules_foreign_cc wraps autoconf+make+cmake builds end-to-end as
opaque cc_library outputs. rules_autoconf instead replaces the
autoconf step with Bazel-native primitives — you keep fine-grained
control over the resulting cc_library graph, but you lose the
ability to drive an existing configure.ac directly. The two
complement each other:
- Use rules_foreign_cc if you want a Bazel-managed build of an autoconf project without doing the dependency surgery yourself.
- Use rules_autoconf if you want a hand-written, fine-grained
Bazel build of an autoconf project and just need the
config.hgenerated correctly.
Roadmap
| Version | Adds |
|---|---|
| v0.1 (this) | cc_check_{header,function,symbol}, config_header |
| v0.2 | cc_check_sizeof, cc_check_bigendian, cc_check_decl (compile-only function probe), cc_check_libraries (cumulative -l detection) |
| v0.3 | configure_run rule for projects shipping pre-generated configure scripts |
| v0.4 | autoconf+m4 binaries packaged as Bazel toolchains (built from source under Bazel via hand-rolled cc_library for m4) |
| v0.5+ | Long-tail AC_* macros, AC_ARG_ENABLE / AC_ARG_WITH equivalents, optional Bazel C-toolchain integration replacing host $CC |
Limitations of v0.1
- Probes use the host compiler via
$CC(defaultcc). The Bazel C toolchain integration that would make probes fully hermetic against the registeredcc_toolchainlands in v0.5+. - No cross-compilation — probes always run on the exec platform.
- No
AC_TRY_RUN-style probes that need to execute the test binary. Compile+link is sufficient for most checks; run-time probes (likeAC_C_BIGENDIAN’s fallback path) are deferred. - No
@VAR@substitution in non-header files yet — only the header template path. Adding generic file substitution is straightforward but not in v0.1.
Compatibility
- Bazel: 7.4+, bzlmod required.
- Host: a C compiler on
$PATH(or$CCset). - Platforms: any host with a working C compiler. Tested on darwin_aarch64 and linux_x86_64.
Contributing
Reference docs (docs/defs.md) are stardoc-generated from the .bzl
docstrings. After editing a rule docstring:
bazel run //docs:update
CI gates this via bazel test //docs/... plus the end-to-end smoke
build in examples/hello/.
License
MIT.
Usage#
Real usage, taken from the module’s examples/.
examples/hello/BUILD.bazel
load(
"@rules_autoconf//autoconf:defs.bzl",
"cc_check_function",
"cc_check_header",
"config_header",
)
# Header probes — should succeed for std headers, fail for the fake one.
cc_check_header(
name = "have_stdio_h",
header = "stdio.h",
)
cc_check_header(
name = "have_string_h",
header = "string.h",
)
cc_check_header(
name = "have_fake_h",
header = "this_header_does_not_exist.h",
)
# Function probes — strlen is libc; nonexistent_function_42 isn't.
cc_check_function(
name = "have_strlen",
function = "strlen",
header = "string.h",
)
cc_check_function(
name = "have_nonexistent",
define_name = "HAVE_NONEXISTENT_FUNCTION_42",
function = "nonexistent_function_42",
)
# Compose probes + static defines into config.h.
config_header(
name = "config_h",
out = "config.h",
defines = {
"PACKAGE_NAME": "\"hello\"",
"PACKAGE_VERSION": "\"0.1.0\"",
},
probes = [
":have_stdio_h",
":have_string_h",
":have_fake_h",
":have_strlen",
":have_nonexistent",
],
template = "config.h.in",
)Rules & providers#
Generated with Stardoc from the module's .bzl sources.
from docs/defs.md
User-facing rules for rules_autoconf.
The Bazel-native equivalents of common autoconf AC_* primitives. Each
rule emits a single result file that other rules (notably
config_header) consume — so probe results compose into a graph, not
into shell-script global state.
The probes use Python tools that shell out to the host C compiler. The
host compiler choice is the CC env var (defaults to cc). v0.1 does
NOT use Bazel’s @bazel_tools//tools/cpp C toolchain — it relies on
whatever cc resolves to on the host. v0.2+ will integrate the proper
Bazel C toolchain for full hermeticity.
Available rules: cc_check_header — autoconf’s AC_CHECK_HEADER cc_check_function — autoconf’s AC_CHECK_FUNC (link test) cc_check_symbol — autoconf’s AC_CHECK_DECL / AC_CHECK_TYPE config_header — autoconf’s AC_CONFIG_HEADERS (renders config.h from a template + define dict + probe results)
cc_check_function
load("@rules_autoconf//autoconf:defs.bzl", "cc_check_function")
cc_check_function(name, define_name, function, header, libraries)
Probe whether a C function is linkable. Bazel-native equivalent of autoconf’s AC_CHECK_FUNC.
ATTRIBUTES
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| define_name | Override the macro name. Defaults to HAVE_<FUNCTION> (uppercased). | String | optional | "" |
| function | Function to probe (e.g. “strlcpy”, “getifaddrs”). | String | required | |
| header | Optional header to #include (e.g. “string.h”). Some functions need a declaration to compile cleanly. | String | optional | "" |
| libraries | Libraries to link (each becomes -l | List of strings | optional | [] |
cc_check_header
load("@rules_autoconf//autoconf:defs.bzl", "cc_check_header")
cc_check_header(name, define_name, header)
Probe whether a C header is includable. Bazel-native equivalent of autoconf’s AC_CHECK_HEADER.
ATTRIBUTES
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| define_name | Override the macro name. Defaults to HAVE_<HEADER> (uppercased, non-alphanumeric -> underscore). | String | optional | "" |
| header | Header to probe (e.g. “string.h”, “sys/socket.h”). | String | required |
cc_check_symbol
load("@rules_autoconf//autoconf:defs.bzl", "cc_check_symbol")
cc_check_symbol(name, define_name, header, symbol)
Probe whether a symbol is declared. Bazel-native equivalent of autoconf’s AC_CHECK_DECL.
ATTRIBUTES
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| define_name | Override the macro name. Defaults to HAVE_DECL_<SYMBOL>. | String | optional | "" |
| header | Header to #include to bring the symbol into scope. | String | optional | "" |
| symbol | Symbol/identifier to probe. Works for type names, macros, enum members, function declarations. | String | required |
config_header
load("@rules_autoconf//autoconf:defs.bzl", "config_header")
config_header(name, out, defines, probes, template)
Render an autoconf-style config header from a template + defines + probe results.
ATTRIBUTES
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| out | The rendered config header. | Label | required | |
| defines | Static substitutions. Values become both #define bodies (for #undef VAR lines) and @VAR@ substitutions. | Dictionary: String -> String | optional | {} |
| probes | Probe targets (cc_check_header / cc_check_function / etc.). Each contributes <DEFINE_NAME>=1 to defines iff the probe result is ‘1’ (autoconf’s HAVE_* convention). | List of labels | optional | [] |
| template | The template header (typically config.h.in). Lines matching #undef VAR are substituted with #define VAR <value> when VAR is in defines. @VAR@ substitutions are also applied. | Label | required |
ProbeResultInfo
load("@rules_autoconf//autoconf:defs.bzl", "ProbeResultInfo")
ProbeResultInfo(result_file, define_name)
A compile-test probe result.
FIELDS
| Name | Description |
|---|---|
| result_file | File: contains ‘1’ if the feature is present, ‘0’ otherwise. |
| define_name | string: the macro name this probe defines when present (e.g. “HAVE_STRLCPY”). |
Conformance#
No gate findings. 8 contested atoms. See how gating works or the full report.
Contested atoms
Third-party modules where this module resolves a different version than others do. Not a violation of anything this module did — it is the actionable form of a registry-level convergence finding, and the sentence a maintainer can act on.
| Atom | Resolved here | Elsewhere |
|---|---|---|
apple_support | 1.24.2 | 2.2.0 ×1 |
bazel_skylib | 1.8.2 | 1.9.0 ×2 |
nlohmann_json | 3.6.1 | 3.12.0.bcr.1 ×1 |
protobuf | 33.4 | 34.0.bcr.1 ×2 |
rules_jvm_external | 6.7 | 6.8 ×4 |
rules_python | 1.7.0 | 2.0.1 ×1 |
rules_swift | 3.1.2 | 3.6.1 ×1 |
upb | 0.0.0-20220923-a547704 | 0.0.0-20230516-61a97ef ×1 |
Dependencies#
Depends on
Versions#
1 published version, newest first. Each resolves to an immutable, integrity-checked archive.
| Version | Integrity (sha256) | Source archive |
|---|---|---|
0.1.0 latest | duRlcN1c6qSLOGaz… | tag archive ↗ |
Changelog#
All notable changes to rules_autoconf. The format is loosely Keep a Changelog — version headers mirror the published bazel-registry entries.
0.1.0 — initial release
- Initial scaffold of Bazel-native autoconf replacement: probes run as
Bazel actions, composing into the build graph and the action cache
instead of an out-of-band
configureshell pipeline. - Ships the core autoconf primitives:
cc_check_header,cc_check_function,cc_check_symbol, andconfig_header(rendersconfig.hfrom adefinesdict + probe results). - No
autoconf/m4runtime dependency — probes use the host C compiler ($CC, defaultcc).