如何正确使用Bazel Transition进行多元构建

发布于 2025-02-08 20:44:23 字数 1317 浏览 2 评论 0原文

我正在尝试定义一个Bazel规则,该规则将为2个不同的平台构建2个不同的CC_Binaries,只有1个不同的平台,只有1个Bazel Build Invocation。我为如何正确定义过渡并将其连接而苦苦挣扎。

我最终希望能够做类似的事情:

cc_binary(
    name = "binary_platform_a"
    ...
)

cc_binary(
    name = "binary_platform_b"
    ...
)

my_custom_multi_arch_rule(
    name = "multiarch_build",
    binary_a = ":binary_platform_a",
    binary_b = ":binary_platform_b",
    ...
)

我从Bazel文件中推论出来:[https://bazel.build/rules/config#user-defined-transitions]我需要在<代码> defs.bzl :

def _impl(settings, attr):
    _ignore = (settings, attr)
    return {
        "Platform A": {"//command_line_option:platform": "platform_a"},
        "Platform B": {"//command_line_option:platform": "platform_b"},
    }

multi_arch_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:platform"]
)

def _rule_impl(ctx):
    # How to implement this?

my_custom_multi_arch_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "binary_a": attr.label(cfg = multi_arch_transition)
        "binary_b": attr.label(cfg = multi_arch_transition)
        ...
    })

最佳案例最终方案将能够发行:

bazel build //path/to/my:multiarch_build

它成功地为其各自平台构建了我的2个单独的二进制文件。

I'm trying to define a bazel rule that will build 2 different cc_binaries for 2 different platforms with just 1 bazel build invocation. I'm struggling with how to define the transition properly and attach it.

I would like ultimately to be able to do something like:

cc_binary(
    name = "binary_platform_a"
    ...
)

cc_binary(
    name = "binary_platform_b"
    ...
)

my_custom_multi_arch_rule(
    name = "multiarch_build",
    binary_a = ":binary_platform_a",
    binary_b = ":binary_platform_b",
    ...
)

I have deduced from bazel documents: [https://bazel.build/rules/config#user-defined-transitions] that I need to do something like the following in a defs.bzl:

def _impl(settings, attr):
    _ignore = (settings, attr)
    return {
        "Platform A": {"//command_line_option:platform": "platform_a"},
        "Platform B": {"//command_line_option:platform": "platform_b"},
    }

multi_arch_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:platform"]
)

def _rule_impl(ctx):
    # How to implement this?

my_custom_multi_arch_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "binary_a": attr.label(cfg = multi_arch_transition)
        "binary_b": attr.label(cfg = multi_arch_transition)
        ...
    })

The best-case final scenario would be able to issue:

bazel build //path/to/my:multiarch_build

and it successfully builds my 2 separate binaries for their respective platforms.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

倒带 2025-02-15 20:44:23

这是一个不同的实现,但包括所有零件,包括平台(“@Platforms // cpu:x86_64”)。

::::::::::::::
hello.c
::::::::::::::
#include <stdio.h>
int main(char *argv) { printf("Hello\n"); }

::::::::::::::
BUILD.bazel
::::::::::::::
load("@bazel_tools//tools/build_defs/pkg:pkg.bzl", "pkg_tar")
load("multi_arch.bzl", "multi_arch")

cc_binary(
    name = "a",
    srcs = ["hello.c"],
)
cc_binary(
    name = "b",
    srcs = ["hello.c"],
)

我发现的每个示例中不清楚的部分是platforms =必须指向platform(),该使用@platforms //来定义约束。正如我在这里证明的那样:(续)

multi_arch(
    name = "a.arm",
    image = ":a",
    platforms = [":arm"],
)
multi_arch(
    name = "b.x86",
    image = ":b",
    platforms = [":x86"],
)

platform(
    name = "x86",
    constraint_values = [
        "@platforms//cpu:x86_64",
        "@platforms//os:linux",
    ]
)
platform(
    name = "arm",
    constraint_values = [
        "@platforms//cpu:aarch64",
        "@platforms//os:linux",
    ]
)

pkg_tar(
    name = "tar-t",
    srcs = [
        ":a.arm",
        ":b.x86",
    ],
)
::::::::::::::
multi_arch.bzl
::::::::::::::    
def _multi_arch_transition_impl(settings, attr):
    return [
        {"//command_line_option:platforms": str(platform)}
        for platform in attr.platforms
    ]

multi_arch_transition = transition(
    implementation = _multi_arch_transition_impl,
    inputs = [],
    outputs = ["//command_line_option:platforms"],
)

def _multi_arch_impl(ctx):
    return DefaultInfo(files = depset(ctx.files.image))

multi_arch = rule(
    implementation = _multi_arch_impl,
    attrs = {
        "image": attr.label(cfg=multi_arch_transition),
        "platforms": attr.label_list(),
        "_allowlist_function_transition": attr.label(
            default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
        )
    }
)

在建造焦油并解开包装后,证明它有效:

$ file /tmp/[ab]
/tmp/a: ELF 64-bit LSB executable, ARM aarch64...
/tmp/b: ELF 64-bit LSB shared object, x86-64...

警告:这是我第一次进行过渡,没有告诉我我是否犯了菜鸟的错误,但肯定适用于我想要什么!

Here's a different implementation, but complete with all the parts, including the platform ("@platforms//cpu:x86_64").

::::::::::::::
hello.c
::::::::::::::
#include <stdio.h>
int main(char *argv) { printf("Hello\n"); }

::::::::::::::
BUILD.bazel
::::::::::::::
load("@bazel_tools//tools/build_defs/pkg:pkg.bzl", "pkg_tar")
load("multi_arch.bzl", "multi_arch")

cc_binary(
    name = "a",
    srcs = ["hello.c"],
)
cc_binary(
    name = "b",
    srcs = ["hello.c"],
)

The unclear part in every example I've found is that platforms= must point to a platform() which defines constraints using @platforms// as I demonstrate here: (cont'd)

multi_arch(
    name = "a.arm",
    image = ":a",
    platforms = [":arm"],
)
multi_arch(
    name = "b.x86",
    image = ":b",
    platforms = [":x86"],
)

platform(
    name = "x86",
    constraint_values = [
        "@platforms//cpu:x86_64",
        "@platforms//os:linux",
    ]
)
platform(
    name = "arm",
    constraint_values = [
        "@platforms//cpu:aarch64",
        "@platforms//os:linux",
    ]
)

pkg_tar(
    name = "tar-t",
    srcs = [
        ":a.arm",
        ":b.x86",
    ],
)
::::::::::::::
multi_arch.bzl
::::::::::::::    
def _multi_arch_transition_impl(settings, attr):
    return [
        {"//command_line_option:platforms": str(platform)}
        for platform in attr.platforms
    ]

multi_arch_transition = transition(
    implementation = _multi_arch_transition_impl,
    inputs = [],
    outputs = ["//command_line_option:platforms"],
)

def _multi_arch_impl(ctx):
    return DefaultInfo(files = depset(ctx.files.image))

multi_arch = rule(
    implementation = _multi_arch_impl,
    attrs = {
        "image": attr.label(cfg=multi_arch_transition),
        "platforms": attr.label_list(),
        "_allowlist_function_transition": attr.label(
            default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
        )
    }
)

After building the tar and unpacking it, proof that it worked:

$ file /tmp/[ab]
/tmp/a: ELF 64-bit LSB executable, ARM aarch64...
/tmp/b: ELF 64-bit LSB shared object, x86-64...

CAVEAT: This is my first time working with transitions, there's no telling whether I'm making noob mistakes, but it definitely works for what I want!

书间行客 2025-02-15 20:44:23

使用ctx.split_attr。

def _rule_impl(ctx):
   binary_a_platform_a = ctx.split_attr.binary_a["Platform A"]
   binary_a_platform_b = ctx.split_attr.binary_b["Platform B"]
   # ...

   return [DefaultInfo(files = depset([binary_a_platform_a, binary_b_platform_b, ...]))]

https://bazel.build/rules/config#accessing-attributes-with-过渡

Use ctx.split_attr.<attr name>[<transition key>] to get the configured Target object representing a particular arch configuration of a binary.

def _rule_impl(ctx):
   binary_a_platform_a = ctx.split_attr.binary_a["Platform A"]
   binary_a_platform_b = ctx.split_attr.binary_b["Platform B"]
   # ...

   return [DefaultInfo(files = depset([binary_a_platform_a, binary_b_platform_b, ...]))]

https://bazel.build/rules/config#accessing-attributes-with-transitions

始终不够爱げ你 2025-02-15 20:44:23

有了一些错别字和其他修复程序,我可以同时使用您和 jin's 示例。

def _impl(settings, attr):
    _ignore = (settings, attr)

    # I'm using my default platform and a custom ARM
    # platform I have as platforms A and B.
    return {
        "Platform A": {"//command_line_option:platforms": "@local_config_platform//:host"},            
        "Platform B": {"//command_line_option:platforms": "//platforms:arm64"},
    }

multi_arch_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:platforms"],
)

def _rule_impl(ctx):
    binary_a_platform_a = ctx.split_attr.binary_a["Platform A"]
    binary_b_platform_b = ctx.split_attr.binary_b["Platform B"]
    files = binary_a_platform_a.files.to_list() + binary_b_platform_b.files.to_list()

    return [DefaultInfo(
        files = depset(direct = files),
    )]

my_custom_multi_arch_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "_allowlist_function_transition": attr.label(
            default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
        ),
        "binary_a": attr.label(cfg = multi_arch_transition),
        "binary_b": attr.label(cfg = multi_arch_transition),
    },
)

With a few typos and other fixes, I got this to work using both you and jin's examples.

def _impl(settings, attr):
    _ignore = (settings, attr)

    # I'm using my default platform and a custom ARM
    # platform I have as platforms A and B.
    return {
        "Platform A": {"//command_line_option:platforms": "@local_config_platform//:host"},            
        "Platform B": {"//command_line_option:platforms": "//platforms:arm64"},
    }

multi_arch_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:platforms"],
)

def _rule_impl(ctx):
    binary_a_platform_a = ctx.split_attr.binary_a["Platform A"]
    binary_b_platform_b = ctx.split_attr.binary_b["Platform B"]
    files = binary_a_platform_a.files.to_list() + binary_b_platform_b.files.to_list()

    return [DefaultInfo(
        files = depset(direct = files),
    )]

my_custom_multi_arch_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "_allowlist_function_transition": attr.label(
            default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
        ),
        "binary_a": attr.label(cfg = multi_arch_transition),
        "binary_b": attr.label(cfg = multi_arch_transition),
    },
)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文