How do I debug a 'java_binary' target executed by a Bazel rule via 'ctx.actions.run(...)'?
Asked Answered
C

3

5

I have a java_binary target in my workspace that I'm later passing as an executable to ctx.actions.run inside the rule. So far so good.

Now I want to debug this java_binary while Bazel is executing the rule. In order to attach a debugger I need the java_binary run in debug mode. So far, the only thing I came up with is setting jvm_flags on the java_binary. I was able to get that to work. But I was wondering if there is a way to achieve it from the command line instead of baking it into the java_binary.

java_binary(
    ...
    jvm_flags = [
        "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000"
    ],
)

Is it possible to achieve this from the command line without hard coding jvm_flags?

Cretin answered 28/2, 2020 at 16:39 Comment(0)
S
4

java_binary outputs a wrapper script that includes a --debug[=<port>] flag that will tell the JVM to wait for debugging. For example:

bazel run //:my-target -- --debug

Another strategy that gives more direct control and shows you how your Starlark rule is running the binary is to run the build with --subcommands. With this Bazel will print out all the commands it runs during the build. Then find the command line corresponding to the invocation of the java_binary you're interested in. Then you can copy/paste that command (including the cd part) and modify it to include the debug flags, and debug it as you would any other process.

For example:

bazel build //:some-target-using-the-binary --subcommands=pretty_print

This should output something like:

INFO: Analyzed target //:some-target-using-the-binary (...).
INFO: Found 1 target...
SUBCOMMAND: # //:some-target-using-the-binary [action '...']
(cd /private/var/tmp/_bazel_username/hash/execroot/core && \
  exec env - \
    LC_CTYPE=en_US.UTF-8 \
    LD_LIBRARY_PATH='' \
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
  bazel-out/exec-config/bin/path/to/binary/package/TheBinaryToDebug \
    @bazel-out/target-config/bin/some-target-using-the-binary-0.params)

--sandbox_debug may be needed to prevent Bazel from deleting the execution root sandbox.

Note also that --subcommands will only print the commands that are actually executed during the build, so a fully cached / fully incremental build will print nothing. You may need to do a clean, or delete some of the outputs of the action you're interested in so that bazel runs that command.

Selfassurance answered 28/2, 2020 at 19:34 Comment(1)
That debug flag was all I needed, thanks bazel run //:my-target -- --debugKarlise
K
2

The accepted answer works but if you're looking for a more complete command try running

bazel run --java_debug --test_arg=--wrapper_script_flag=--debug=8000 -- //your-target/...

You should see this in the Bazel logs

...
Listening for transport dt_socket at address: 8000
...

If you're running the command on a different host, you can reverse ssh tunnel using

ssh -L 8000:localhost:8000 <remote-host-cname>

Once you do this, just bind your debugger to port 8000 using this JVM flag

-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000

This should do what you're looking for.

Karwan answered 26/5, 2023 at 23:32 Comment(0)
S
0

It looks like you can pass the --jvm_flag option as part of the program options after the --.

BUILD:

java_binary(
    name = "extract",
    main_class = "com.pkg.Main",
    resources = glob(["src/main/resources/**/*"]),
)

CLI:

bazel run //:extract -- --jvm_flag="-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=7942" -path %cd%\config.json

It seems that the --jvm_flag option needs to come immediately after the --, before the program options (-path in the example). This is with Bazel 3.7.0.

Shrunken answered 9/12, 2020 at 14:36 Comment(1)
Turns out --jvm_flag is not needed. See the accepted answer.Cretin

© 2022 - 2024 — McMap. All rights reserved.