targets/rp2040: Auto generate uf2 files

Adds build integration to build the elf2uf2 tool and then use it to
generate uf2 files alongside every ELF file.

Change-Id: Ia72f1e967a775472384a6eaf7318835087a0837d
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/109810
Pigweed-Auto-Submit: Armando Montanez <amontanez@google.com>
Reviewed-by: Anthony DiGirolamo <tonymd@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
diff --git a/targets/rp2040/pico_executable.gni b/targets/rp2040/pico_executable.gni
index f8afcf1..e9a6725 100644
--- a/targets/rp2040/pico_executable.gni
+++ b/targets/rp2040/pico_executable.gni
@@ -14,12 +14,41 @@
 
 import("//build_overrides/pigweed.gni")
 
+import("$dir_pw_build/exec.gni")
+
 # Executable wrapper that allows the 2nd stage bootloader to strip link deps.
 template("pico_executable") {
-  target("executable", target_name) {
-    forward_variables_from(invoker, "*")
-    if (defined(no_link_deps) && no_link_deps) {
+  if (defined(invoker.is_boot_stage2) && invoker.is_boot_stage2) {
+    executable(target_name) {
+      forward_variables_from(invoker, "*")
+
+      # Link deps pulls in Pigweed things that don't fit in the 2nd stage
+      # bootloader.
       public_deps -= [ "$dir_pw_build:link_deps" ]
     }
+  } else {
+    _uf2_name = "${target_name}.uf2"
+    _elf_name = "${target_name}.elf"
+    executable(_elf_name) {
+      forward_variables_from(invoker, "*")
+    }
+
+    pw_exec(_uf2_name) {
+      _elf2uf2_target = "$dir_pw_third_party/pico_sdk/src:elf2uf2($dir_pigweed/targets/host:host_clang_debug)"
+      _uf2_out_path = "${target_out_dir}/${_uf2_name}"
+      deps = [
+        ":${_elf_name}",
+        _elf2uf2_target,
+      ]
+      program = "<TARGET_FILE(${_elf2uf2_target})>"
+      args = [
+        "<TARGET_FILE(:${_elf_name})>",
+        rebase_path(_uf2_out_path, root_build_dir),
+      ]
+      outputs = [ _uf2_out_path ]
+    }
+    group(target_name) {
+      deps = [ ":${_uf2_name}" ]
+    }
   }
 }
diff --git a/targets/rp2040/target_docs.rst b/targets/rp2040/target_docs.rst
index cbcbf66..e6c5d24 100644
--- a/targets/rp2040/target_docs.rst
+++ b/targets/rp2040/target_docs.rst
@@ -20,7 +20,7 @@
 
   gn args out
     # Add this line.
-    PICO_SRC_DIR = pw_env_setup_PACKAGE_ROOT + "/pico_sdk"
+    PICO_SRC_DIR = getenv("PW_PACKAGE_ROOT") + "/pico_sdk"
 
 Usage
 =====
@@ -35,26 +35,14 @@
 
   ninja -C out
 
-Pigweed's build will produce ELF files for each unit test built for the Pi Pico.
-While ELF files can be flashed to a Pi Pico via SWD, it's slightly easier to
-use the Pi Pico's bootloader to flash the firmware as a UF2 file.
-
-Pigweed currently does not yet build/provide the elf2uf2 utility used to convert
-ELF files to UF2 files. This tool can be built from within the Pi Pico SDK with
-the following command:
-
-.. code:: sh
-
-  mkdir build && cd build && cmake -G Ninja ../ && ninja
-  # Copy the tool so it's visible in your PATH.
-  cp elf2uf2/elf2uf2 $HOME/bin/elf2uf2
+Pigweed's build will produce ELF and UF2 files for each unit test built for the
+Pi Pico.
 
 Flashing
 ========
-Flashing the Pi Pico is as easy as 1-2-3:
+Flashing the Pi Pico is two easy steps:
 
-#. Create a UF2 file from an ELF file using ``elf2uf2``.
 #. While holding the button on the Pi Pico, connect the Pico to your computer
    via the micro USB port.
-#. Copy the UF2 to the RPI-RP2 volume that enumerated when you connected the
-   Pico.
+#. Copy the desired UF2 firmware image to the RPI-RP2 volume that enumerated
+   when you connected the Pico.
diff --git a/third_party/pico_sdk/src/BUILD.gn b/third_party/pico_sdk/src/BUILD.gn
index 62b3952..6eb97aa 100644
--- a/third_party/pico_sdk/src/BUILD.gn
+++ b/third_party/pico_sdk/src/BUILD.gn
@@ -12,6 +12,11 @@
 # License for the specific language governing permissions and limitations under
 # the License.
 
+import("//build_overrides/pi_pico.gni")
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_build/target_types.gni")
+
 # TODO(amontanez): If a successor to the RP2040 comes out, this might need to
 # be a little smarter about what code is pulled in.
 group("pico_sdk") {
@@ -21,3 +26,14 @@
     "rp2_common",
   ]
 }
+
+config("elf2uf2_configs") {
+  include_dirs = [ "$PICO_SRC_DIR/src/common/boot_uf2/include" ]
+  cflags_cc = [ "-std=gnu++14" ]
+}
+
+pw_executable("elf2uf2") {
+  configs = [ ":elf2uf2_configs" ]
+  sources = [ "$PICO_SRC_DIR/tools/elf2uf2/main.cpp" ]
+  remove_configs = [ "$dir_pw_build:strict_warnings" ]
+}
diff --git a/third_party/pico_sdk/src/rp2_common/boot_stage2/BUILD.gn b/third_party/pico_sdk/src/rp2_common/boot_stage2/BUILD.gn
index d23802a..7eeee43 100644
--- a/third_party/pico_sdk/src/rp2_common/boot_stage2/BUILD.gn
+++ b/third_party/pico_sdk/src/rp2_common/boot_stage2/BUILD.gn
@@ -56,7 +56,7 @@
     "$dir_pw_build:reduced_size",
     "$dir_pw_build:strict_warnings",
   ]
-  no_link_deps = true
+  is_boot_stage2 = true
 
   public = [ "${_CWD}/include/boot_stage2/config.h" ]