Search code examples
pythonc++buildbazel

Zipping Bazel-generated files for deployment


I have a Bazel project that contains a python/ folder in the root. This folder contains two files:

# BUILD
py_binary(
    name = "foo",
    srcs = ["foo.py"],
    deps = ["//cc:bar"],
)

and

# foo.py
import cc.bar as bar

# This is a SWIG-wrapped C++ function that prints "hello world"
print(bar.hello_world())

The cc/ folder, which is also in the root, contains (among other things) the following rule:

# Expose the shared object library to Python.
py_library(
    name = "bar",
    srcs = [":bar_swig.py"], # Generated by SWIG.
    data = [":_bar.so"], # Generated by SWIG.
    visibility = ["//python:__pkg__"],
)

Running bazel build //python:foo generates bazel-bin/python/foo.runfiles/ and bazel-bin/python/foo. I would like to write a rule in Bazel that gathers this directory and binary and zips them in foo.zip.

This is what I came up with:

genrule(
    name = "zip_foo",
    srcs = ["//python:foo"],
    outs = ["foo.zip"],
    cmd = "zip $@ $(locations //python:foo)",
)

However, the generated zip does not include foo.runfiles/. How do I write a rule that zips all of a target's runtime dependencies? I would like this rule to be as generic as possible, by which I mean it should handle zipping any target's runtime, even if the target has complex dependencies.


Solution

  • The srcs attribute of genrule will not build runfiles tree for binaries. Bazel will only build a runfiles tree if it expects something to run that binary on the host system as part of the build or test. Instead, we can use the tools attribute of genrule, which is intended for binaries that will run as part of the genrule. The following genrule will zip up the python binary and its runfiles tree.

    genrule(
        name = "zip_foo",
        tools = ["//python:foo"],
        outs = ["foo.zip"],
        cmd = "zip -r $@ $(location //python:foo)*",
    )
    

    DISCLAIMER: This will build //python:foo in the "host configuration". What this means is that any native code will be built for the architecture of the machine that you are running bazel on. So if you build foo.zip on Linux and copy it onto a Mac, it will probably not work.