Search code examples
bazel

Custom rule does not build dependent target


I want to run unit tests on qemu. I have created a custom rule, that invokes qemu with arguments specified in the rule. One of those arguments is the elf file (rule attribute "target") which is used by qemu as kernel.
When I invoke my custom rule with the following command, the elf file ("kernel.elf") does not get compiled:

 bazel build //test:custom_rule

This happens even though bazel query 'deps(//test:custom_rule)' lists the target ":kernel.elf" as a dependency.

Furthermore I have another problem with the custom rule. When I manually build the ":kernel.elf" and call the custom rule afterwards qemu tells me, that it could not load the kernel file. Manually invoking the qemu command in the shell does work, so I guess the problem does not lie within the "kernel.elf" file.

Does anybody have an answer to my problems?

Thanks in advance!

run_tests.bzl

def _impl(ctx):
  qemu = ctx.attr.qemu
  machine = ctx.attr.machine
  cpu = ctx.attr.cpu
  target = ctx.file.target.path
  output = ctx.outputs.out
  # The command may only access files declared in inputs.
  ctx.actions.run_shell(
      arguments = [qemu, machine, cpu, target],
      outputs=[output],
      command="$1 -M $2 -cpu $3 -nographic -monitor null 
               -serial null -semihosting -kernel $4 > %s" % (output.path))


run_tests = rule(
    implementation=_impl,
    attrs = {"qemu" : attr.string(),
             "machine" : attr.string(),
             "cpu" : attr.string(),
             "target" : attr.label(allow_files=True, single_file=True,
                        mandatory=True)},
    outputs={"out": "run_tests.log"}
)

BUILD

load("//make:run_tests.bzl", "run_tests")

run_tests(
    name = "custom_rule",
    qemu = "qemu-system-arm",
    machine = "xilinx-zynq-a9",
    cpu = "cortex-a9",
    target = ":kernel.elf"
)

cc_binary(
    name = "kernel.elf",
    srcs = glob(["*.cc"]),
    deps = ["//src:portos", 
            "@unity//:unity"],
    copts = ["-Isrc", 
             "-Iexternal/unity/src",
             "-Iexternal/unity/extras/fixture/src"] 
)

Solution

  • The issue is probably that the inputs need to specified to the action, see https://docs.bazel.build/versions/master/skylark/lib/actions.html#run_shell.inputs

    You'll also probably need to make qemu a label and make that an input to the action as well (And machine too, if that's a file that qemu needs)

    E.g. something like:

    def _impl(ctx):
      qemu = ctx.attr.qemu
      machine = ctx.attr.machine
      cpu = ctx.attr.cpu
      target = ctx.file.target.path
      output = ctx.outputs.out
      # The command may only access files declared in inputs.
      ctx.actions.run_shell(
          inputs = [qemu, target],
          outputs=[output],
          arguments = [qemu, machine, cpu, target],
          command="$1 -M $2 -cpu $3 -nographic -monitor null 
                   -serial null -semihosting -kernel $4 > %s" % (output.path))
    
    
    run_tests = rule(
        implementation=_impl,
        attrs = {
            "qemu" : attr.label(allow_files=True, single_file=True,
                                mandatory=True),
            "machine" : attr.string(),
            "cpu" : attr.string(),
            "target" : attr.label(allow_files=True, single_file=True,
                                  mandatory=True)
        },
        outputs={"out": "run_tests.log"}
    )