Como criar uma macro simbólica

IMPORTANTE: este tutorial é para macros simbólicas , o novo sistema de macros introduzido no Bazel 8. Se você precisar oferecer suporte a versões mais antigas do Bazel, crie uma macro legada em vez disso. Consulte Criar uma macro legada.

Imagine que você precisa executar uma ferramenta como parte da sua build. Por exemplo, talvez você queira gerar ou pré-processar um arquivo de origem ou compactar um binário. Neste tutorial, você vai criar uma macro simbólica que redimensiona uma imagem.

As macros são adequadas para tarefas simples. Se você quiser fazer algo mais complicado, por exemplo, adicionar suporte a uma nova linguagem de programação, considere criar uma regra. As regras oferecem mais controle e flexibilidade.

A maneira mais fácil de criar uma macro que redimensiona uma imagem é usar uma genrule:

genrule(
    name = "logo_miniature",
    srcs = ["logo.png"],
    outs = ["small_logo.png"],
    cmd = "convert $< -resize 100x100 $@",
)

cc_binary(
    name = "my_app",
    srcs = ["my_app.cc"],
    data = [":logo_miniature"],
)

Se você precisar redimensionar mais imagens, talvez queira reutilizar o código. Para fazer isso, defina uma função de implementação e uma declaração de macro em um arquivo separado .bzl, e chame o arquivo miniature.bzl:

# Implementation function
def _miniature_impl(name, visibility, src, size, **kwargs):
    native.genrule(
        name = name,
        visibility = visibility,
        srcs = [src],
        outs = [name + "_small_" + src.name],
        cmd = "convert $< -resize " + size + " $@",
        **kwargs,
    )

# Macro declaration
miniature = macro(
    doc = """Create a miniature of the src image.

    The generated file name will be prefixed with `name + "_small_"`.
    """,
    implementation = _miniature_impl,
    # Inherit most of genrule's attributes (such as tags and testonly)
    inherit_attrs = native.genrule,
    attrs = {
        "src": attr.label(
            doc = "Image file",
            allow_single_file = True,
            # Non-configurable because our genrule's output filename is
            # suffixed with src's name. (We want to suffix the output file with
            # srcs's name because some tools that operate on image files expect
            # the files to have the right file extension.)
            configurable = False,
        ),
        "size": attr.string(
            doc = "Output size in WxH format",
            default = "100x100",
        ),
        # Do not allow callers of miniature() to set srcs, cmd, or outs -
        # _miniature_impl overrides their values when calling native.genrule()
        "srcs": None,
        "cmd": None,
        "outs": None,
    },
)

Algumas observações:

  • As funções de implementação de macro simbólica precisam ter name e visibility parâmetros. Elas precisam ser usadas para o destino principal da macro.

  • Para documentar o comportamento de uma macro simbólica, use doc parâmetros para macro() e os atributos dela.

  • Para chamar um genrule ou qualquer outra regra nativa, use native..

  • Use **kwargs para encaminhar os argumentos herdados extras para a genrule subjacente. Ela funciona da mesma forma que em Python. Isso é útil para que um usuário possa definir atributos padrão, como tags ou testonly.

Agora, use a macro do arquivo BUILD:

load("//path/to:miniature.bzl", "miniature")

miniature(
    name = "logo_miniature",
    src = "image.png",
)

cc_binary(
    name = "my_app",
    srcs = ["my_app.cc"],
    data = [":logo_miniature"],
)