From d41f5e0c91b1b63db3ceb754336454ca24676d15 Mon Sep 17 00:00:00 2001 From: Noah Graf Date: Wed, 25 Mar 2026 17:43:20 +0000 Subject: [PATCH 1/3] Switched probe-rs to be resolved as a bazel host side executable and not a part of target resolution --- probe_rs/BUILD.bazel | 2 +- probe_rs/defs.bzl | 11 ++++--- probe_rs/private/BUILD.bazel | 6 ++++ probe_rs/private/run.bzl | 59 ++++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 probe_rs/private/run.bzl diff --git a/probe_rs/BUILD.bazel b/probe_rs/BUILD.bazel index acceb64..632c128 100644 --- a/probe_rs/BUILD.bazel +++ b/probe_rs/BUILD.bazel @@ -17,7 +17,7 @@ bzl_library( srcs = ["defs.bzl"], visibility = ["//visibility:public"], deps = [ - "@bazel_skylib//rules:native_binary", + "//probe_rs/private:run", ], ) diff --git a/probe_rs/defs.bzl b/probe_rs/defs.bzl index b87fa95..908df1b 100644 --- a/probe_rs/defs.bzl +++ b/probe_rs/defs.bzl @@ -1,6 +1,6 @@ "Public API re-exports" -load("@bazel_skylib//rules:native_binary.bzl", "native_binary") +load("//probe_rs/private:run.bzl", "probe_rs_run") def _probe_rs_run(name, elf, chip, args = [], **kwargs): """Run probe-rs on the given ELF file. @@ -13,11 +13,12 @@ def _probe_rs_run(name, elf, chip, args = [], **kwargs): **kwargs: Additional arguments to pass to native_binary. """ - native_binary( + probe_rs_run( name = name, - src = "@probe_rs//:probe-rs", - data = [elf], - args = ["run", "--chip", chip, "$(locations {})".format(elf)] + args, + elf = elf, + chip = chip, + probe_rs = "@probe_rs//:probe-rs", + probe_rs_args = args, **kwargs ) diff --git a/probe_rs/private/BUILD.bazel b/probe_rs/private/BUILD.bazel index 1bf5209..1745335 100644 --- a/probe_rs/private/BUILD.bazel +++ b/probe_rs/private/BUILD.bazel @@ -6,6 +6,12 @@ bzl_library( visibility = ["//probe_rs:__subpackages__"], ) +bzl_library( + name = "run", + srcs = ["run.bzl"], + visibility = ["//probe_rs:__subpackages__"], +) + bzl_library( name = "versions", srcs = ["versions.bzl"], diff --git a/probe_rs/private/run.bzl b/probe_rs/private/run.bzl new file mode 100644 index 0000000..2ccadf7 --- /dev/null +++ b/probe_rs/private/run.bzl @@ -0,0 +1,59 @@ +"""Executable rule for running probe-rs against an ELF built for another platform.""" + +def _quote_shell(arg): + return "'" + arg.replace("'", "'\"'\"'") + "'" + +def _quote_batch(arg): + escaped = arg.replace("^", "^^") + escaped = escaped.replace("\"", "\"\"") + return "\"" + escaped + "\"" + +def _probe_rs_run_impl(ctx): + elf = ctx.file.elf + tool = ctx.executable.probe_rs + is_windows = tool.basename.endswith(".exe") + script_name = ctx.label.name + (".bat" if is_windows else ".sh") + launcher = ctx.actions.declare_file(script_name) + + args = ["run", "--chip", ctx.attr.chip, elf.short_path] + ctx.attr.probe_rs_args + + if is_windows: + script = "\r\n".join([ + "@echo off", + "setlocal", + "{} {}".format(_quote_batch(tool.short_path), " ".join([_quote_batch(arg) for arg in args])), + "exit /b %ERRORLEVEL%", + "", + ]) + else: + script = "\n".join([ + "#!/usr/bin/env bash", + "set -euo pipefail", + "{} {}".format(_quote_shell(tool.short_path), " ".join([_quote_shell(arg) for arg in args])), + "", + ]) + + ctx.actions.write(launcher, script, is_executable = True) + + runfiles = ctx.runfiles(files = [elf, tool]) + runfiles = runfiles.merge(ctx.attr.elf[DefaultInfo].default_runfiles) + runfiles = runfiles.merge(ctx.attr.probe_rs[DefaultInfo].default_runfiles) + + return [DefaultInfo(executable = launcher, runfiles = runfiles)] + +probe_rs_run = rule( + implementation = _probe_rs_run_impl, + executable = True, + attrs = { + "elf": attr.label( + mandatory = True, + allow_single_file = True, + ), + "chip": attr.string(mandatory = True), + "probe_rs_args": attr.string_list(), + "probe_rs": attr.label( + executable = True, + cfg = "exec", + ), + }, +) From 47ae8352a83a6102b15e58f438458bf2e07512ed Mon Sep 17 00:00:00 2001 From: Noah Graf Date: Wed, 25 Mar 2026 20:10:19 +0000 Subject: [PATCH 2/3] Commented --- probe_rs/defs.bzl | 4 +++- probe_rs/private/run.bzl | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/probe_rs/defs.bzl b/probe_rs/defs.bzl index 908df1b..cf5d6f4 100644 --- a/probe_rs/defs.bzl +++ b/probe_rs/defs.bzl @@ -10,13 +10,15 @@ def _probe_rs_run(name, elf, chip, args = [], **kwargs): elf: The ELF file to run probe-rs on. chip: probe-rs chip to use. Ex. "nRF52840_xxAA" args: Additional arguments to pass to probe-rs. - **kwargs: Additional arguments to pass to native_binary. + **kwargs: Additional arguments to pass to the underlying executable rule. """ probe_rs_run( name = name, elf = elf, chip = chip, + # Resolve this label in the caller's repo mapping so bzlmod users can + # `use_repo(..., "probe_rs")` from their main workspace. probe_rs = "@probe_rs//:probe-rs", probe_rs_args = args, **kwargs diff --git a/probe_rs/private/run.bzl b/probe_rs/private/run.bzl index 2ccadf7..e5c4bf8 100644 --- a/probe_rs/private/run.bzl +++ b/probe_rs/private/run.bzl @@ -10,6 +10,7 @@ def _quote_batch(arg): def _probe_rs_run_impl(ctx): elf = ctx.file.elf + # probe-rs is a host tool even when the ELF was built for an embedded target. tool = ctx.executable.probe_rs is_windows = tool.basename.endswith(".exe") script_name = ctx.label.name + (".bat" if is_windows else ".sh") @@ -17,6 +18,8 @@ def _probe_rs_run_impl(ctx): args = ["run", "--chip", ctx.attr.chip, elf.short_path] + ctx.attr.probe_rs_args + # Emit a tiny launcher so `bazel run` executes probe-rs from runfiles while + # still allowing the ELF input to stay in the target configuration. if is_windows: script = "\r\n".join([ "@echo off", @@ -35,6 +38,8 @@ def _probe_rs_run_impl(ctx): ctx.actions.write(launcher, script, is_executable = True) + # Keep both the ELF and the host tool in runfiles so the launcher can refer + # to them by short_path on every supported host platform. runfiles = ctx.runfiles(files = [elf, tool]) runfiles = runfiles.merge(ctx.attr.elf[DefaultInfo].default_runfiles) runfiles = runfiles.merge(ctx.attr.probe_rs[DefaultInfo].default_runfiles) @@ -53,6 +58,8 @@ probe_rs_run = rule( "probe_rs_args": attr.string_list(), "probe_rs": attr.label( executable = True, + # Resolve probe-rs for the execution platform rather than the ELF's + # target platform so cross-target flashing works correctly. cfg = "exec", ), }, From 896d6c04899f4d9b3cbf4685d5255d004707cc06 Mon Sep 17 00:00:00 2001 From: Noah Graf Date: Wed, 25 Mar 2026 20:24:03 +0000 Subject: [PATCH 3/3] Commented --- probe_rs/defs.bzl | 2 -- 1 file changed, 2 deletions(-) diff --git a/probe_rs/defs.bzl b/probe_rs/defs.bzl index cf5d6f4..e4c4eff 100644 --- a/probe_rs/defs.bzl +++ b/probe_rs/defs.bzl @@ -17,8 +17,6 @@ def _probe_rs_run(name, elf, chip, args = [], **kwargs): name = name, elf = elf, chip = chip, - # Resolve this label in the caller's repo mapping so bzlmod users can - # `use_repo(..., "probe_rs")` from their main workspace. probe_rs = "@probe_rs//:probe-rs", probe_rs_args = args, **kwargs