Practical Bazel: Use ctx.actions.args() to Form Arguments Lists
Practical Bazel bazel
Published: 2020-11-12
Practical Bazel: Use ctx.actions.args() to Form Arguments Lists

When writing custom rules, you often need to invoke executables with argument lists. For example, let’s say you are writing a custom rule that executes gcc to compile a set of input source files. You could write:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
output_file = ctx.actions.declare_file("exe")

ctx.actions.run(
    inputs = ctx.files.srcs,
    outputs = [output_file],
    # This is for demo purposes.  In a real Bazel rule you'd
    # want to use cc_common.
    executable = "/usr/bin/gcc",
    arguments = ["-o", output_file.path] + [x.path for x in ctx.files.srcs],
)

However, it is both more efficient and better style to create the arguments list using ctx.actions.args(). Furthermore, the args object will automatically handle any path vs short_path differences for you.

Therefore, the above rule fragment should instead be written as:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
output_file = ctx.actions.declare_file("exe")

args = ctx.actions.args()
args.add("-o", output_file)
args.add_all(ctx.files.srcs)

ctx.actions.run(
    inputs = ctx.files.srcs,
    outputs = [output_file],
    # This is for demo purposes.  In a real Bazel rule you'd
    # want to use cc_common.
    executable = "/usr/bin/gcc",
    arguments = [args],
)