Something like this should be close to what you're looking for:
defs.bzl:
def _multi_cpu_package_impl(ctx):
zipper_args = ["c", ctx.outputs.zip.path]
binaries = {}
for dep in ctx.attr.deps:
files = dep.files.to_list()
if "bazel-out/k8" in files[0].path:
binaries["k8"] = files
elif "bazel-out/armeabi-v7a" in files[0].path:
binaries["armeabi-v7a"] = files
zipper_inputs = []
for cpu, files in binaries.items():
for f in files:
zipper_args.append("%s/%s=%s" % (cpu, f.short_path, f.path))
zipper_inputs.append(f)
ctx.actions.run(
inputs = zipper_inputs,
outputs = [ctx.outputs.zip],
executable = ctx.executable._zipper,
arguments = zipper_args,
progress_message = "Creating zip...",
mnemonic = "zipper",
)
def _multi_cpu_transition_impl(settings, attr):
return {
"k8": {
"//command_line_option:cpu": "k8",
},
"armeabi-v7a": {
"//command_line_option:cpu": "armeabi-v7a",
}
}
_multi_cpu_transition = transition(
implementation = _multi_cpu_transition_impl,
inputs = [],
outputs = [
"//command_line_option:cpu",
],
)
multi_cpu_package = rule(
implementation = _multi_cpu_package_impl,
attrs = {
"deps": attr.label_list(cfg = _multi_cpu_transition),
"$zipper": attr.label(default = Label("@bazel_tools//tools/zip:zipper"), cfg = "host", executable=True),
"_whitelist_function_transition": attr.label(default = "//tools/whitelists/function_transition_whitelist"),
},
outputs = {"zip": "%{name}.zip"},
)
tools/whitelists/function_transition_whitelist/BUILD
package_group(
name = "function_transition_whitelist",
packages = ["//..."],
)
BUILD:
load(":defs.bzl", "multi_cpu_package")
cc_binary(
name = "foo",
srcs = ["foo.c"],
)
multi_cpu_package(
name = "foo_pkg",
deps = [
":foo",
],
)
foo.c:
int main() {
return 0;
}
Some notes:
1. In order to distinguish the targets in ctx.attr.deps by their configuration, this example examines the paths of files in that target, because those paths happen to contain the cpu the files were built for. In earlier iterations of this API, there is ctx.split_attr.
<attr> which would contain a map with the same keys as in the map that the transition implementation function returns (here, the keys are the cpu values we want), but that no longer seems to be populated (
+Greg Estren +Julie Xia)
2. Out of convenience I used zipper, which is bundled with bazel, instead of tar.
3. The example collapses a bunch of depsets with to_list(), which is usually bad for performance, but using
Args was tricky with zipper. This is a top-level rule so it's probably ok here.
4. The whitelist thing is necessary because some transitions can cause performance problems for large depots. In fact, in the case here, everything is analyzed and built twice (once for each cpu), which will result in up to about 2x memory usage (basically have to store the graph twice). There is ongoing work to make this better.
5. The example doesn't actually work out-of-the-box with bazel because bazel's crosstool contains a fake definition for the armeabi-v7a toolchain. You'll want to adjust the values in _multi_cpu_transition_impl to match your crosstool.