cmake: add Zephyr image output files as byproducts

Export Zephyr image byproducts through `BYPRODUCT_<VAR>` cache
variables.

This allow external tools, such as sysbuild, to read information on
products produced by a Zephyr build from the image CMake cache.

For sysbuild, this means that all byproducts will be added to a phony
build target, which again allow sysbuild itself to depends on target
output and properly describe dependencies between byproducts and their
producing targets.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 139a504..3d761a9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1436,6 +1436,7 @@
 target_byproducts(TARGET ${ZEPHYR_LINK_STAGE_EXECUTABLE}
                   BYPRODUCTS ${PROJECT_BINARY_DIR}/${ZEPHYR_LINK_STAGE_EXECUTABLE}.map
 )
+set(BYPRODUCT_KERNEL_ELF_NAME "${PROJECT_BINARY_DIR}/${KERNEL_ELF_NAME}" CACHE FILEPATH "Kernel elf file" FORCE)
 set_property(TARGET
   ${ZEPHYR_LINK_STAGE_EXECUTABLE}
   PROPERTY LINK_DEPENDS ${PROJECT_BINARY_DIR}/${ZEPHYR_CURRENT_LINKER_CMD}
@@ -1582,6 +1583,7 @@
       post_build_byproducts
       ${KERNEL_HEX_NAME}
       )
+    set(BYPRODUCT_KERNEL_HEX_NAME "${PROJECT_BINARY_DIR}/${KERNEL_HEX_NAME}" CACHE FILEPATH "Kernel hex file" FORCE)
   endif()
 endif()
 
@@ -1603,6 +1605,7 @@
       post_build_byproducts
       ${KERNEL_BIN_NAME}
       )
+    set(BYPRODUCT_KERNEL_BIN_NAME "${PROJECT_BINARY_DIR}/${KERNEL_BIN_NAME}" CACHE FILEPATH "Kernel binary file" FORCE)
   endif()
 endif()
 
@@ -1635,6 +1638,7 @@
     post_build_byproducts
     ${KERNEL_UF2_NAME}
   )
+  set(BYPRODUCT_KERNEL_UF2_NAME "${PROJECT_BINARY_DIR}/${KERNEL_UF2_NAME}" CACHE FILEPATH "Kernel uf2 file" FORCE)
 endif()
 
 if(CONFIG_BUILD_OUTPUT_META)
@@ -1684,6 +1688,7 @@
       post_build_byproducts
       ${KERNEL_S19_NAME}
       )
+    set(BYPRODUCT_KERNEL_S19_NAME "${PROJECT_BINARY_DIR}/${KERNEL_S19_NAME}" CACHE FILEPATH "Kernel s19 file" FORCE)
   endif()
 endif()
 
@@ -1766,6 +1771,7 @@
       post_build_byproducts
       ${KERNEL_EXE_NAME}
       )
+    set(BYPRODUCT_KERNEL_EXE_NAME "${PROJECT_BINARY_DIR}/${KERNEL_EXE_NAME}" CACHE FILEPATH "Kernel exe file" FORCE)
   else()
     if(CMAKE_GENERATOR STREQUAL "Unix Makefiles")
       set(MAKE "${CMAKE_MAKE_PROGRAM}" CACHE FILEPATH "cmake defined make")
diff --git a/cmake/mcuboot.cmake b/cmake/mcuboot.cmake
index f551466..3b29069 100644
--- a/cmake/mcuboot.cmake
+++ b/cmake/mcuboot.cmake
@@ -114,15 +114,24 @@
     list(APPEND unconfirmed_args --bin --sbin ${output}.signed.bin)
     list(APPEND byproducts ${output}.signed.bin)
     zephyr_runner_file(bin ${output}.signed.bin)
+    set(BYPRODUCT_KERNEL_SIGNED_BIN_NAME "${output}.signed.bin"
+        CACHE FILEPATH "Signed kernel bin file" FORCE
+    )
 
     if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE)
       list(APPEND confirmed_args --bin --sbin ${output}.signed.confirmed.bin)
       list(APPEND byproducts ${output}.signed.confirmed.bin)
+      set(BYPRODUCT_KERNEL_SIGNED_CONFIRMED_BIN_NAME "${output}.signed.confirmed.bin"
+          CACHE FILEPATH "Signed and confirmed kernel bin file" FORCE
+      )
     endif()
 
     if(NOT "${keyfile_enc}" STREQUAL "")
       list(APPEND encrypted_args --bin --sbin ${output}.signed.encrypted.bin)
       list(APPEND byproducts ${output}.signed.encrypted.bin)
+      set(BYPRODUCT_KERNEL_SIGNED_ENCRYPTED_BIN_NAME "${output}.signed.encrypted.bin"
+          CACHE FILEPATH "Signed and encrypted kernel bin file" FORCE
+      )
     endif()
   endif()
 
@@ -131,15 +140,24 @@
     list(APPEND unconfirmed_args --hex --shex ${output}.signed.hex)
     list(APPEND byproducts ${output}.signed.hex)
     zephyr_runner_file(hex ${output}.signed.hex)
+    set(BYPRODUCT_KERNEL_SIGNED_HEX_NAME "${output}.signed.hex"
+        CACHE FILEPATH "Signed kernel hex file" FORCE
+    )
 
     if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE)
       list(APPEND confirmed_args --hex --shex ${output}.signed.confirmed.hex)
       list(APPEND byproducts ${output}.signed.confirmed.hex)
+      set(BYPRODUCT_KERNEL_SIGNED_CONFIRMED_HEX_NAME "${output}.signed.confirmed.hex"
+          CACHE FILEPATH "Signed and confirmed kernel hex file" FORCE
+      )
     endif()
 
     if(NOT "${keyfile_enc}" STREQUAL "")
       list(APPEND encrypted_args --hex --shex ${output}.signed.encrypted.hex)
       list(APPEND byproducts ${output}.signed.encrypted.hex)
+      set(BYPRODUCT_KERNEL_SIGNED_ENCRYPTED_HEX_NAME "${output}.signed.encrypted.hex"
+          CACHE FILEPATH "Signed and encrypted kernel hex file" FORCE
+      )
     endif()
   endif()
 
diff --git a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake
index c4e90f9..1012629 100644
--- a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake
+++ b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake
@@ -34,6 +34,11 @@
       set_property(TARGET ${LOAD_CACHE_IMAGE}_cache APPEND PROPERTY "CACHE:VARIABLES" "${CMAKE_MATCH_1}")
       set_property(TARGET ${LOAD_CACHE_IMAGE}_cache PROPERTY "${CMAKE_MATCH_1}:TYPE" "${CMAKE_MATCH_2}")
       set_property(TARGET ${LOAD_CACHE_IMAGE}_cache PROPERTY "${CMAKE_MATCH_1}" "${variable_value}")
+      if("${CMAKE_MATCH_1}" MATCHES "^BYPRODUCT_.*")
+        set_property(TARGET ${LOAD_CACHE_IMAGE}_cache APPEND
+                     PROPERTY "EXTRA_BYPRODUCTS" "${variable_value}"
+        )
+      endif()
     endif()
   endforeach()
 endfunction()
@@ -297,6 +302,17 @@
 # If the application is not due to ExternalZephyrProject_Add() being called,
 # then an error is raised.
 #
+# The image output files are added as target properties on the image target as:
+# ELF_OUT: property specifying the generated elf file.
+# BIN_OUT: property specifying the generated bin file.
+# HEX_OUT: property specifying the generated hex file.
+# S19_OUT: property specifying the generated s19 file.
+# UF2_OUT: property specifying the generated uf2 file.
+# EXE_OUT: property specifying the generated exe file.
+#
+# the property is only set if the image is configured to generate the output
+# format. Elf files are always created.
+#
 # APPLICATION: <name>: Name of the application.
 #
 function(ExternalZephyrProject_Cmake)
@@ -408,6 +424,15 @@
   endif()
   load_cache(IMAGE ${ZCMAKE_APPLICATION} BINARY_DIR ${BINARY_DIR})
   import_kconfig(CONFIG_ ${BINARY_DIR}/zephyr/.config TARGET ${ZCMAKE_APPLICATION})
+
+  # This custom target informs CMake how the BYPRODUCTS are generated if a target
+  # depends directly on the BYPRODUCT instead of depending on the image target.
+  get_target_property(${ZCMAKE_APPLICATION}_byproducts ${ZCMAKE_APPLICATION}_cache EXTRA_BYPRODUCTS)
+  add_custom_target(${ZCMAKE_APPLICATION}_extra_byproducts
+                    COMMAND ${CMAKE_COMMAND} -E true
+                    BYPRODUCTS ${${ZCMAKE_APPLICATION}_byproducts}
+                    DEPENDS ${ZCMAKE_APPLICATION}
+  )
 endfunction()
 
 # Usage: