Skip to content


Folders and files

Last commit message
Last commit date

Latest commit



67 Commits

Repository files navigation

Bazel build rules for GNU M4

The m4 macro processing language is commonly used as an intermediate format for text-based Unix development tools such as Bison and Flex.

This Bazel ruleset allows GNU M4 to be integrated into a Bazel build. It can be used to perform macro expansion with the //m4:m4.bzl%m4 build rule, or as a dependency in other rules via the Bazel toolchain system.

Currently, the only implementation of m4 supported by this ruleset is GNU M4.

API reference: docs/


As a module dependency (bzlmod)

Add the following to your MODULE.bazel:

bazel_dep(name = "rules_m4", version = "0.2.3")

To specify a version or build with additional C compiler options, use the m4_repository_ext module extension:

m4 = use_extension(
    name = "m4",
    version = "1.4.17",
    extra_copts = ["-O3"],
use_repo(m4, "m4")

Note that repository names registered with a given bzlmod module extension must be unique within the scope of that extension. See the Bazel module extensions documentation for more details.

As a workspace dependency

Add the following to your WORKSPACE.bazel:

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

    name = "rules_m4",
    # Obtain the package checksum from the release page:
    sha256 = "",
    urls = [""],

load("@rules_m4//m4:m4.bzl", "m4_register_toolchains")

m4_register_toolchains(version = "1.4.18")

To specify a version or build with additional C compiler options, use the m4_repository and m4_toolchain_repository repository rules:

load("@rules_m4//m4:m4.bzl", "m4_repository", "m4_toolchain_repository")

    name = "m4_v1.4.17_fast",
    version = "1.4.17",
    extra_copts = ["-O3"],

    name = "m4_toolchain_v1.4.17_fast",
    m4_repository = "@m4_v1.4.17_fast",



Macro expansion with the //m4:m4.bzl%m4 build rule:

load("@rules_m4//m4:m4.bzl", "m4")

    name = "hello_world",
    srcs = [""],
    output = "hello_world.txt",

Macro expansion in a genrule:

    name = "hello_world_gen",
    srcs = [""],
    outs = ["hello_world_gen.txt"],
    cmd = "$(M4) $(SRCS) > $@",
    toolchains = ["@rules_m4//m4:current_m4_toolchain"],

Writing a custom rule that depends on m4 as a toolchain:

load("@rules_m4//m4:m4.bzl", "M4_TOOLCHAIN_TYPE", "m4_toolchain")

def _my_rule(ctx):
    m4 = m4_toolchain(ctx)
        tools = [m4.m4_tool],
        env = m4.m4_env,
        # ...

my_rule = rule(
    implementation = _my_rule,
    toolchains = [M4_TOOLCHAIN_TYPE],