使用 Bazel 平台构建时如何获取当前目标架构

问题描述 投票:0回答:1

我正在交叉编译 Android 的本机库。我的

.bazelrc
是:

build:android --platforms=@io_bazel_rules_go//go/toolchain:android_arm64_cgo
build:android --extra_toolchains=@androidndk//:all

我构建本机 C++ 库,然后使用以下方法将该本机库打包到 jar 文件中:

java_library(
   name = "mylib",
   resources = ["//:my-native-lib.so"]
)

一切正常,我可以使用

bazel build --config //:mylib
构建我的 jar,它会生成
libmylib.jar
,其中包含我的 .so 本机库。到目前为止一切顺利。

但是我想在我的 jar 文件的名称中包含目标架构(在这种情况下

arm64
)。例如成为
libmylib-arm64.jar
。我不想硬编码该名称,而是想以某种方式从我用来构建的平台获取 CPU 架构。

有什么想法可以做到这一点吗?

android build cpu-architecture bazel platform
1个回答
0
投票

如果您进行交叉编译,则不需要主机的CPU,而是需要目标的CPU。一种方法是为您支持的每个 cpu 架构定义规则,bazel 将自动启用/禁用给定目标架构的适当规则。

例如,在类似

multi_cpu_rules.bzl
:

的文件中
supported_cpus = [
    "x86_64",
    "arm",
]

def must_be_str(val):
    if type(val) != "string":
        fail("invalid type, got: " + type(val))
    return val

def format(unformatted_data, cpu):
    if type(unformatted_data) == "list":
        return [
            must_be_str(data).format(cpu = cpu)
            for data in unformatted_data
        ]
    if type(unformatted_data) == "dict":
        return {
            key: must_be_str(value).format(cpu = cpu)
            for key, value in formatted_data.items()
        }
    
    return must_be_str(unformatted_data).format(cpu = cpu)

def fn_wrap_rule(function, **kwargs):
    for cpu in supported_cpus:
        values = {
            key: format(value, cpu)
            for key, value in kwargs.items()
        }
        function(
            **values
        )

target_compatible_with
属性是为所有规则定义的。

然后可以在构建文件中将目标定义为:

load("multi_cpu_rules.bzl", "fn_wrap_rule")

fn_wrap_rule(
    java_library,
    name = "mylib-{cpu}",
    resources = ["//:my-native-lib.so"],
    target_compatible_with = [
        "@platforms//cpu:{cpu}",
    ],
)

这将为每个目标架构定义一个工件,并且 bazel 将仅构建适合当前所选平台的工件。这些目标需要使用架构字符串在命令行上引用,但是 bazel 可以使用

构建包中的所有目标
bazel build //my_lib/...

或者,如果您只想检查编译器运行的主机平台,可以使用以下方式读取约束:

load("@local_config_platform//:constraints.bzl", "HOST_CONSTRAINTS")

这是当前平台的属性列表。因此,要选取需要循环的 cpu 值,但是

BUILD
文件中不允许循环,因此需要将其包装在函数(或宏)中。

因此添加一个文件,例如名为

get_host_cpu.bzl
,其中包含:

load("@local_config_platform//:constraints.bzl", "HOST_CONSTRAINTS")

def get_host_cpu():
    cpu_constraint = "@platforms//cpu:"
    for constraint in HOST_CONSTRAINTS:
        if constraint.startswith(cpu_constraint):
            return constraint[len(cpu_constraint):]

然后修改规则调用来使用该函数。然而,在其他地方使用它也需要调用这个函数,所以我们也可以创建一个别名。将您的构建文件更新为:

load(":get_host_cpu.bzl", "get_host_cpu")

java_library(
   name = "mylib" + get_host_cpu(),
   resources = ["//:my-native-lib.so"]
)

alias(
    name = "mylib",
    actual = "mylib" + get_host_cpu(),
)
© www.soinside.com 2019 - 2024. All rights reserved.